From 6185199abdb9f3f18bc9a1f65e484c75a237bcd7 Mon Sep 17 00:00:00 2001 From: Ben Smith Date: Wed, 6 Sep 2017 12:21:45 -0700 Subject: [PATCH 001/199] Add initial proposal overview --- README.md | 12 ++ proposals/bulk-memory-operations/Overview.md | 170 +++++++++++++++++++ 2 files changed, 182 insertions(+) create mode 100644 proposals/bulk-memory-operations/Overview.md diff --git a/README.md b/README.md index 26d58a3a5c..466b0e6a81 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,17 @@ [![Build Status](https://travis-ci.org/WebAssembly/spec.svg?branch=master)](https://travis-ci.org/WebAssembly/spec) +# Bulk Memory Operations Proposal for WebAssembly + +This repository is a clone of github.com/WebAssembly/spec/. It is meant for +discussion, prototype specification and implementation of a proposal to add +bulk memory operations (e.g. instructions with behavior similar to `memmove` +and `memset`) to WebAssembly. + +See the [overview](proposals/bulk-memory-operations/Overview.md) for a summary of the +proposal. + +Original README from upstream repository follows... + # spec This repository holds the sources for the WebAssembly draft specification diff --git a/proposals/bulk-memory-operations/Overview.md b/proposals/bulk-memory-operations/Overview.md new file mode 100644 index 0000000000..2fb12a4502 --- /dev/null +++ b/proposals/bulk-memory-operations/Overview.md @@ -0,0 +1,170 @@ +# Bulk Memory Operations + +## Motivation + +Some people have mentioned that `memcpy` and `memmove` functions are hot +when profiling some WebAssembly benchmarks. Some examples: + +- https://github.com/WebAssembly/design/issues/236#issuecomment-283279499 + +> I've been looking at perf profiles for wasm unity benchmark a bit recently and see that some + of the hottest functions are doing memcpy or memset like things. If this is any indication of + normal wasm code patterns, I think we could see significant improvement with an intrinsic so + it may be worth prioritizing. + +- https://github.com/WebAssembly/design/issues/977#issue-204960079 + +> In a number of game engines I've been optimizing and benchmarking, interestingly the performance + of memcpy() does show up relatively high in profiles. (~2%-5% of total execution time) + +## Prototype + +I implemented a prototype implementation of a `move_memory` instruction in v8 which just calls out +to v8's [`MemMove` function](https://cs.chromium.org/chromium/src/v8/src/utils.h?l=446). I compared +this to an implementation [generated by emscripten](https://gist.github.com/binji/c57dc945bba60985439ef8e5b574eee0) and currently used in the Unity demo. This implementation aligns then performs copies using `i32.load` and `i32.store`. I've also included performance achieved by unrolling this loop manually and increasing the size to `i64`. + +Each test copies `size` bytes from one address to another, non-overlapping. This is repeated `N` times. Each row copies a total of 1 Gib of data, and only touches 1 Mib of memory in the source and destination ranges. + +This is the core loop: + +``` + let mask = Mib - 1; + let start = performance.now(); + for (let i = 0; i < N; ++i) { + f(dst_base + dst, src_base + src, size); + dst = (dst + size) & mask; + src = (src + size) & mask; + } + let end = performance.now(); +``` + +Here are the results on my machine (x86_64, 2.9GHz, L1 32k, L2 256k, L3 256k): + +| | intrinsic | i64 load/store x 4 | i64 load/store x 2 | i32 load/store x 2 | i32 load/store | +| --- | --- | --- | --- | --- | --- | +| size=32b, N=33554432 | 1.382 Gib/s | 1.565 Gib/s | 1.493 Gib/s | 1.275 Gib/s | 1.166 Gib/s | +| size=64b, N=16777216 | 3.285 Gib/s | 2.669 Gib/s | 2.383 Gib/s | 1.861 Gib/s | 1.639 Gib/s | +| size=128b, N=8388608 | 6.162 Gib/s | 3.993 Gib/s | 3.480 Gib/s | 2.433 Gib/s | 2.060 Gib/s | +| size=256b, N=4194304 | 9.939 Gib/s | 5.323 Gib/s | 4.462 Gib/s | 2.724 Gib/s | 2.213 Gib/s | +| size=512b, N=2097152 | 15.777 Gib/s | 6.377 Gib/s | 4.913 Gib/s | 3.231 Gib/s | 2.457 Gib/s | +| size=1.0Kib, N=1048576 | 17.902 Gib/s | 7.010 Gib/s | 6.112 Gib/s | 3.568 Gib/s | 2.614 Gib/s | +| size=2.0Kib, N=524288 | 19.870 Gib/s | 8.248 Gib/s | 6.915 Gib/s | 3.764 Gib/s | 2.699 Gib/s | +| size=4.0Kib, N=262144 | 20.940 Gib/s | 9.145 Gib/s | 7.400 Gib/s | 3.871 Gib/s | 2.729 Gib/s | +| size=8.0Kib, N=131072 | 21.162 Gib/s | 9.258 Gib/s | 7.672 Gib/s | 3.925 Gib/s | 2.763 Gib/s | +| size=16.0Kib, N=65536 | 20.991 Gib/s | 9.758 Gib/s | 7.756 Gib/s | 3.945 Gib/s | 2.773 Gib/s | +| size=32.0Kib, N=32768 | 22.504 Gib/s | 9.956 Gib/s | 7.861 Gib/s | 3.966 Gib/s | 2.780 Gib/s | +| size=64.0Kib, N=16384 | 22.534 Gib/s | 10.088 Gib/s | 7.931 Gib/s | 3.974 Gib/s | 2.782 Gib/s | +| size=128.0Kib, N=8192 | 29.728 Gib/s | 10.032 Gib/s | 7.934 Gib/s | 3.975 Gib/s | 2.782 Gib/s | +| size=256.0Kib, N=4096 | 29.742 Gib/s | 10.116 Gib/s | 7.625 Gib/s | 3.886 Gib/s | 2.781 Gib/s | +| size=512.0Kib, N=2048 | 29.994 Gib/s | 10.090 Gib/s | 7.627 Gib/s | 3.985 Gib/s | 2.785 Gib/s | +| size=1.0Mib, N=1024 | 11.760 Gib/s | 10.091 Gib/s | 7.959 Gib/s | 3.989 Gib/s | 2.787 Gib/s | + +## Design + +This proposal introduces 2 new instructions: + +`move_memory`: + +Copy data from a source memory region to destination region; +these regions may overlap: the copy is performed as if the source region was +first copied to a temporary buffer, then the temporary buffer is copied to +the destination region. + +The instruction has the signature `[i32 i32 i32] -> []`. The parameters are, in order: + +- top-2: destination address +- top-1: source address +- top-0: size of memory region in bytes + +`set_memory`: Set all bytes in a memory region to a given byte. + +The instruction has the signature `[i32 i32 i32] -> []`. The parameters are, in order: + +- top-2: destination address +- top-1: byte value to set +- top-0: size of memory region in bytes + +## Structure + +Unlike most other memory operations, the bulk operations do not have a `memarg` +immediate. + +``` +instr ::== ... + | move_memory + | set_memory +``` + +## Validation + +`move_memory` + +* The memory `C.mems[0]` must be defined in the context. +* Then the instruction is valid with type `[i32 i32 i32] -> []`. + +`set_memory` + +* The memory `C.mems[0]` must be defined in the context. +* Then the instruction is valid with type `[i32 i32 i32] -> []`. + +## Execution + +`move_memory` + +1. Let `F` be the current frame. +1. Assert: due to validation, `F.module.memaddrs[0]` exists. +1. Let `a` be the memory address `F.module.memaddrs[0]`. +1. Assert: due to validation, `S.mems[a]` exists. +1. Let `mem` be the memory instance `S.mems[a]`. +1. Assert: due to validation, a value of value type `i32` is on the top of the stack. +1. Pop the value `i32.const n` from the stack. +1. Assert: due to validation, a value of value type `i32` is on the top of the stack. +1. Pop the value `i32.const s` from the stack. +1. If `s + n` is larger than the length of `mem.data`, then: + 1. Trap. +1. Assert: due to validation, a value of value type `i32` is on the top of the stack. +1. Pop the value `i32.const d` from the stack. +1. If `d + n` is larger than the length of `mem.data`, then: + 1. Trap. +1. Let `b*` be the byte sequence `mem.data[s:n]`. +1. Replace the bytes `mem.data[d:n]` with `b*`. + +`set_memory` + +1. Let `F` be the current frame. +1. Assert: due to validation, `F.module.memaddrs[0]` exists. +1. Let `a` be the memory address `F.module.memaddrs[0]`. +1. Assert: due to validation, `S.mems[a]` exists. +1. Let `mem` be the memory instance `S.mems[a]`. +1. Assert: due to validation, a value of value type `i32` is on the top of the stack. +1. Pop the value `i32.const n` from the stack. +1. Assert: due to validation, a value of value type `i32` is on the top of the stack. +1. Pop the value `i32.const c` from the stack. +1. Assert: due to validation, a value of value type `i32` is on the top of the stack. +1. Pop the value `i32.const d` from the stack. +1. If `d + n` is larger than the length of `mem.data`, then: + 1. Trap. +1. Let `c_w` be the result of computing `wrap_{32,8}(c)`. +1. Let `b*` be the byte sequence `{bytes_i8(c_w)}^n`. +1. Replace the bytes `mem.data[d:n]` with `b*`. + +## Binary Format + +``` +instr ::= ... + | 0xC5 0x00 => move_memory + | 0xC6 0x00 => set_memory +``` + +Note that this skips `0xC0..0xC4` because those are currently proposed to be used for the +new sign-extending operators (see https://github.com/WebAssembly/threads/blob/master/proposals/threads/Overview.md#new-sign-extending-operators). + +An immediate byte is included for future extensions. It currently must be zero. + +## Text Format + +``` +plaininstr_I ::= ... + | `move_memory` => move_memory + | `set_memory` => set_memory +``` From 107c4cc2e7a8beb486f6f9aedc2ecd7553248148 Mon Sep 17 00:00:00 2001 From: Ben Smith Date: Thu, 26 Oct 2017 15:26:58 -0700 Subject: [PATCH 002/199] Include link to gist for benchmark See issue #3. --- proposals/bulk-memory-operations/Overview.md | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/proposals/bulk-memory-operations/Overview.md b/proposals/bulk-memory-operations/Overview.md index 2fb12a4502..4e18c0a8d7 100644 --- a/proposals/bulk-memory-operations/Overview.md +++ b/proposals/bulk-memory-operations/Overview.md @@ -38,6 +38,20 @@ This is the core loop: let end = performance.now(); ``` +The code for the benchmark can be found [here](https://gist.github.com/binji/b8e8bc0c0121235d9f1668bc447c7f8c). +Note that this will not run properly without a WebAssembly implementation of `move_memory`. For my tests, I +hacked a version of v8 to replace any exported function called `memcpy` or `memmove` with a new function with +the following contents: + +```wasm +(func (param $dst i32) (param $src i32) (param $size i32) (result i32) + get_local $dst + get_local $src + get_local $size + move_memory + get_local $dst) +``` + Here are the results on my machine (x86_64, 2.9GHz, L1 32k, L2 256k, L3 256k): | | intrinsic | i64 load/store x 4 | i64 load/store x 2 | i32 load/store x 2 | i32 load/store | @@ -59,6 +73,7 @@ Here are the results on my machine (x86_64, 2.9GHz, L1 32k, L2 256k, L3 256k): | size=512.0Kib, N=2048 | 29.994 Gib/s | 10.090 Gib/s | 7.627 Gib/s | 3.985 Gib/s | 2.785 Gib/s | | size=1.0Mib, N=1024 | 11.760 Gib/s | 10.091 Gib/s | 7.959 Gib/s | 3.989 Gib/s | 2.787 Gib/s | + ## Design This proposal introduces 2 new instructions: From 096ac5bc967835ca427f74f5bd51ea05f1741dc5 Mon Sep 17 00:00:00 2001 From: Ben Smith Date: Wed, 17 Jan 2018 16:20:49 -0800 Subject: [PATCH 003/199] Include ConditionalSegmentInitialization proposal (#4) --- README.md | 6 + .../ConditionalSegmentInitialization.md | 174 ++++++++++++++++++ 2 files changed, 180 insertions(+) create mode 100644 proposals/bulk-memory-operations/ConditionalSegmentInitialization.md diff --git a/README.md b/README.md index 466b0e6a81..87fc140573 100644 --- a/README.md +++ b/README.md @@ -10,6 +10,12 @@ and `memset`) to WebAssembly. See the [overview](proposals/bulk-memory-operations/Overview.md) for a summary of the proposal. +This proposal also includes functionality to conditionally initialize data and +elem segments that was previously coupled with the +[thread proposal](https://github.com/WebAssembly/threads). This is currently in a +[separate overview document](proposals/bulk-memory-operations/ConditionalSegmentInitialization.md) +but will combined into the main overview soon. + Original README from upstream repository follows... # spec diff --git a/proposals/bulk-memory-operations/ConditionalSegmentInitialization.md b/proposals/bulk-memory-operations/ConditionalSegmentInitialization.md new file mode 100644 index 0000000000..2c17e4c219 --- /dev/null +++ b/proposals/bulk-memory-operations/ConditionalSegmentInitialization.md @@ -0,0 +1,174 @@ +# Proposal to conditionally initialize segments + +This page describes a proposal for providing a mechanism to skip data or +element segment initialization when instantiating a module. + +Although the following rationale applies only to data segments, this proposal +suggests that the proposed solutions apply to element segments as well for +consistency. + +## Rationale + +Under the current threading proposal, to share a module between multiple +agents, the module must be instantiated multiple times: once per agent. +Instantiation initializes linear memory with the contents in the module's data +segments. If the memory is shared between multiple agents, it will be +initialized multiple times, potentially overwriting stores that occurred after +the previous initializations. + +For example: + +```webassembly +;; The module. +(module + (memory (export "memory") 1) + + ;; Some value used as a counter. + (data (i32.const 0) "\0") + + ;; Add one to the counter. + (func (export "addOne") + (i32.store8 + (i32.const 0) + (i32.add + (i32.load8_u (i32.const 0)) + (i32.const 1))) + ) +) +``` + +```javascript +// main.js +let moduleBytes = ...; + +WebAssembly.instantiate(moduleBytes).then( + ({module, instance}) => { + // Increment our counter. + instance.exports.addOne(); + + // Spawn a new Worker. + let worker = new Worker('worker.js'); + + // Send the module to the new Worker. + worker.postMessage(module); + }); + +// worker.js + +function onmessage(event) { + let module = event.data; + + // Use the module to create another instance. + WebAssembly.instantiate(module).then( + (instance) => { + // Oops, our counter has been clobbered. + }); +} + +``` + +This can be worked around by storing the data segments in a separate module +which is only instantiated once, then exporting this memory to be used by +another module that contains only code. This works, but it cumbersome since it +requires two modules where one should be enough. + +## Proposal: New instructions to initialize data and element segments + +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. + +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 +_passive_. A passive 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 passive segment has no initializer expression, since it will be specified +as an operand to `mem.init` or `table.init`. + +Passive segments 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 + +Attempting to drop an active segment is a validation error. + +The data section is encoded as follows: + +``` +datasec ::= seg*:section_11(vec(data)) => seg +data ::= 0x00 e:expr b*:vec(byte) => {data 0, offset e, init b*, active true} +data ::= 0x01 b*:vec(byte) => {data 0, offset empty, init b*, active false} +``` + +The element section is encoded similarly. + +### `mem.init` instruction + +The `mem.init` instruction copies data from a given passive 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 `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 `mem.init` operands. + +A trap occurs if: +* the segment is passive +* the segment is used after it has been dropped via `mem.drop` +* any of the accessed bytes lies outside the source data segment or the target memory + +Note that it is allowed to use `mem.init` on the same data segment more than +once. + +### `mem.drop` instruction + +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 + +Consider if there are two data sections, the first is always active and the +second is conditionally active if global 0 has a non-zero value. This could be +implemented as follows: + +```webassembly +(import "a" "global" (global i32)) ;; global 0 +(memory 1) +(data (i32.const 0) "hello") ;; data segment 0, is active so always copied +(data passive "goodbye") ;; data segment 1, is passive + +(func $start + (if (get_global 0) + + ;; copy data segment 1 into memory + (mem.init 1 + (i32.const 0) ;; source offset + (i32.const 16) ;; target offset + (i32.const 7)) ;; length + + ;; The memory used by this segment is no longer needed, so this segment can + ;; be dropped. + (mem.drop 1)) +) +``` From 83b76206a74fccf467ccb659f4c9344206a66ed7 Mon Sep 17 00:00:00 2001 From: Ben Smith Date: Wed, 17 Jan 2018 16:25:42 -0800 Subject: [PATCH 004/199] Rename `{set,move}_memory` to `mem.{set,copy}` This aligns with current interest in using `mem.` prefix for memory operations, see https://github.com/WebAssembly/spec/issues/627 and https://github.com/WebAssembly/threads/issues/62#issuecomment-348137094. --- proposals/bulk-memory-operations/Overview.md | 30 ++++++++++---------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/proposals/bulk-memory-operations/Overview.md b/proposals/bulk-memory-operations/Overview.md index 4e18c0a8d7..4bc6f90fed 100644 --- a/proposals/bulk-memory-operations/Overview.md +++ b/proposals/bulk-memory-operations/Overview.md @@ -19,7 +19,7 @@ when profiling some WebAssembly benchmarks. Some examples: ## Prototype -I implemented a prototype implementation of a `move_memory` instruction in v8 which just calls out +I implemented a prototype implementation of a `mem.copy` instruction in v8 which just calls out to v8's [`MemMove` function](https://cs.chromium.org/chromium/src/v8/src/utils.h?l=446). I compared this to an implementation [generated by emscripten](https://gist.github.com/binji/c57dc945bba60985439ef8e5b574eee0) and currently used in the Unity demo. This implementation aligns then performs copies using `i32.load` and `i32.store`. I've also included performance achieved by unrolling this loop manually and increasing the size to `i64`. @@ -39,7 +39,7 @@ This is the core loop: ``` The code for the benchmark can be found [here](https://gist.github.com/binji/b8e8bc0c0121235d9f1668bc447c7f8c). -Note that this will not run properly without a WebAssembly implementation of `move_memory`. For my tests, I +Note that this will not run properly without a WebAssembly implementation of `mem.copy`. For my tests, I hacked a version of v8 to replace any exported function called `memcpy` or `memmove` with a new function with the following contents: @@ -48,7 +48,7 @@ the following contents: get_local $dst get_local $src get_local $size - move_memory + mem.copy get_local $dst) ``` @@ -78,7 +78,7 @@ Here are the results on my machine (x86_64, 2.9GHz, L1 32k, L2 256k, L3 256k): This proposal introduces 2 new instructions: -`move_memory`: +`mem.copy`: Copy data from a source memory region to destination region; these regions may overlap: the copy is performed as if the source region was @@ -91,7 +91,7 @@ The instruction has the signature `[i32 i32 i32] -> []`. The parameters are, in - top-1: source address - top-0: size of memory region in bytes -`set_memory`: Set all bytes in a memory region to a given byte. +`mem.set`: Set all bytes in a memory region to a given byte. The instruction has the signature `[i32 i32 i32] -> []`. The parameters are, in order: @@ -106,25 +106,25 @@ immediate. ``` instr ::== ... - | move_memory - | set_memory + | mem.copy + | mem.set ``` ## Validation -`move_memory` +`mem.copy` * The memory `C.mems[0]` must be defined in the context. * Then the instruction is valid with type `[i32 i32 i32] -> []`. -`set_memory` +`mem.set` * The memory `C.mems[0]` must be defined in the context. * Then the instruction is valid with type `[i32 i32 i32] -> []`. ## Execution -`move_memory` +`mem.copy` 1. Let `F` be the current frame. 1. Assert: due to validation, `F.module.memaddrs[0]` exists. @@ -144,7 +144,7 @@ instr ::== ... 1. Let `b*` be the byte sequence `mem.data[s:n]`. 1. Replace the bytes `mem.data[d:n]` with `b*`. -`set_memory` +`mem.set` 1. Let `F` be the current frame. 1. Assert: due to validation, `F.module.memaddrs[0]` exists. @@ -167,8 +167,8 @@ instr ::== ... ``` instr ::= ... - | 0xC5 0x00 => move_memory - | 0xC6 0x00 => set_memory + | 0xC5 0x00 => mem.copy + | 0xC6 0x00 => mem.set ``` Note that this skips `0xC0..0xC4` because those are currently proposed to be used for the @@ -180,6 +180,6 @@ An immediate byte is included for future extensions. It currently must be zero. ``` plaininstr_I ::= ... - | `move_memory` => move_memory - | `set_memory` => set_memory + | `mem.copy` => mem.copy + | `mem.set` => mem.set ``` From dd356d5717bae3f304a0647fb0c7dc1461d3ccc9 Mon Sep 17 00:00:00 2001 From: Ben Smith Date: Thu, 18 Jan 2018 10:19:32 -0800 Subject: [PATCH 005/199] Combine bulk-memory-ops + cond-seg-init proposals (#5) Also remove some of the stuff from the bulk memory proposal that really should be written in the spec ReST files. --- README.md | 6 - .../ConditionalSegmentInitialization.md | 174 ---------- proposals/bulk-memory-operations/Overview.md | 309 ++++++++++++------ 3 files changed, 204 insertions(+), 285 deletions(-) delete mode 100644 proposals/bulk-memory-operations/ConditionalSegmentInitialization.md diff --git a/README.md b/README.md index 87fc140573..466b0e6a81 100644 --- a/README.md +++ b/README.md @@ -10,12 +10,6 @@ and `memset`) to WebAssembly. See the [overview](proposals/bulk-memory-operations/Overview.md) for a summary of the proposal. -This proposal also includes functionality to conditionally initialize data and -elem segments that was previously coupled with the -[thread proposal](https://github.com/WebAssembly/threads). This is currently in a -[separate overview document](proposals/bulk-memory-operations/ConditionalSegmentInitialization.md) -but will combined into the main overview soon. - Original README from upstream repository follows... # spec diff --git a/proposals/bulk-memory-operations/ConditionalSegmentInitialization.md b/proposals/bulk-memory-operations/ConditionalSegmentInitialization.md deleted file mode 100644 index 2c17e4c219..0000000000 --- a/proposals/bulk-memory-operations/ConditionalSegmentInitialization.md +++ /dev/null @@ -1,174 +0,0 @@ -# Proposal to conditionally initialize segments - -This page describes a proposal for providing a mechanism to skip data or -element segment initialization when instantiating a module. - -Although the following rationale applies only to data segments, this proposal -suggests that the proposed solutions apply to element segments as well for -consistency. - -## Rationale - -Under the current threading proposal, to share a module between multiple -agents, the module must be instantiated multiple times: once per agent. -Instantiation initializes linear memory with the contents in the module's data -segments. If the memory is shared between multiple agents, it will be -initialized multiple times, potentially overwriting stores that occurred after -the previous initializations. - -For example: - -```webassembly -;; The module. -(module - (memory (export "memory") 1) - - ;; Some value used as a counter. - (data (i32.const 0) "\0") - - ;; Add one to the counter. - (func (export "addOne") - (i32.store8 - (i32.const 0) - (i32.add - (i32.load8_u (i32.const 0)) - (i32.const 1))) - ) -) -``` - -```javascript -// main.js -let moduleBytes = ...; - -WebAssembly.instantiate(moduleBytes).then( - ({module, instance}) => { - // Increment our counter. - instance.exports.addOne(); - - // Spawn a new Worker. - let worker = new Worker('worker.js'); - - // Send the module to the new Worker. - worker.postMessage(module); - }); - -// worker.js - -function onmessage(event) { - let module = event.data; - - // Use the module to create another instance. - WebAssembly.instantiate(module).then( - (instance) => { - // Oops, our counter has been clobbered. - }); -} - -``` - -This can be worked around by storing the data segments in a separate module -which is only instantiated once, then exporting this memory to be used by -another module that contains only code. This works, but it cumbersome since it -requires two modules where one should be enough. - -## Proposal: New instructions to initialize data and element segments - -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. - -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 -_passive_. A passive 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 passive segment has no initializer expression, since it will be specified -as an operand to `mem.init` or `table.init`. - -Passive segments 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 - -Attempting to drop an active segment is a validation error. - -The data section is encoded as follows: - -``` -datasec ::= seg*:section_11(vec(data)) => seg -data ::= 0x00 e:expr b*:vec(byte) => {data 0, offset e, init b*, active true} -data ::= 0x01 b*:vec(byte) => {data 0, offset empty, init b*, active false} -``` - -The element section is encoded similarly. - -### `mem.init` instruction - -The `mem.init` instruction copies data from a given passive 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 `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 `mem.init` operands. - -A trap occurs if: -* the segment is passive -* the segment is used after it has been dropped via `mem.drop` -* any of the accessed bytes lies outside the source data segment or the target memory - -Note that it is allowed to use `mem.init` on the same data segment more than -once. - -### `mem.drop` instruction - -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 - -Consider if there are two data sections, the first is always active and the -second is conditionally active if global 0 has a non-zero value. This could be -implemented as follows: - -```webassembly -(import "a" "global" (global i32)) ;; global 0 -(memory 1) -(data (i32.const 0) "hello") ;; data segment 0, is active so always copied -(data passive "goodbye") ;; data segment 1, is passive - -(func $start - (if (get_global 0) - - ;; copy data segment 1 into memory - (mem.init 1 - (i32.const 0) ;; source offset - (i32.const 16) ;; target offset - (i32.const 7)) ;; length - - ;; The memory used by this segment is no longer needed, so this segment can - ;; be dropped. - (mem.drop 1)) -) -``` diff --git a/proposals/bulk-memory-operations/Overview.md b/proposals/bulk-memory-operations/Overview.md index 4bc6f90fed..7c8ba41382 100644 --- a/proposals/bulk-memory-operations/Overview.md +++ b/proposals/bulk-memory-operations/Overview.md @@ -1,13 +1,13 @@ -# Bulk Memory Operations +# Bulk Memory Operations and Conditional Segment Initialization -## Motivation +## Motivation for Bulk Memory Operations Some people have mentioned that `memcpy` and `memmove` functions are hot when profiling some WebAssembly benchmarks. Some examples: - https://github.com/WebAssembly/design/issues/236#issuecomment-283279499 -> I've been looking at perf profiles for wasm unity benchmark a bit recently and see that some +> I've been looking at perf profiles for wasm unity benchmark a bit recently and see that some of the hottest functions are doing memcpy or memset like things. If this is any indication of normal wasm code patterns, I think we could see significant improvement with an intrinsic so it may be worth prioritizing. @@ -17,7 +17,7 @@ when profiling some WebAssembly benchmarks. Some examples: > In a number of game engines I've been optimizing and benchmarking, interestingly the performance of memcpy() does show up relatively high in profiles. (~2%-5% of total execution time) -## Prototype +### Bulk Memory Operations Prototype I implemented a prototype implementation of a `mem.copy` instruction in v8 which just calls out to v8's [`MemMove` function](https://cs.chromium.org/chromium/src/v8/src/utils.h?l=446). I compared @@ -27,7 +27,7 @@ Each test copies `size` bytes from one address to another, non-overlapping. This This is the core loop: -``` +```javascript let mask = Mib - 1; let start = performance.now(); for (let i = 0; i < N; ++i) { @@ -56,42 +56,192 @@ Here are the results on my machine (x86_64, 2.9GHz, L1 32k, L2 256k, L3 256k): | | intrinsic | i64 load/store x 4 | i64 load/store x 2 | i32 load/store x 2 | i32 load/store | | --- | --- | --- | --- | --- | --- | -| size=32b, N=33554432 | 1.382 Gib/s | 1.565 Gib/s | 1.493 Gib/s | 1.275 Gib/s | 1.166 Gib/s | -| size=64b, N=16777216 | 3.285 Gib/s | 2.669 Gib/s | 2.383 Gib/s | 1.861 Gib/s | 1.639 Gib/s | -| size=128b, N=8388608 | 6.162 Gib/s | 3.993 Gib/s | 3.480 Gib/s | 2.433 Gib/s | 2.060 Gib/s | -| size=256b, N=4194304 | 9.939 Gib/s | 5.323 Gib/s | 4.462 Gib/s | 2.724 Gib/s | 2.213 Gib/s | -| size=512b, N=2097152 | 15.777 Gib/s | 6.377 Gib/s | 4.913 Gib/s | 3.231 Gib/s | 2.457 Gib/s | -| size=1.0Kib, N=1048576 | 17.902 Gib/s | 7.010 Gib/s | 6.112 Gib/s | 3.568 Gib/s | 2.614 Gib/s | -| size=2.0Kib, N=524288 | 19.870 Gib/s | 8.248 Gib/s | 6.915 Gib/s | 3.764 Gib/s | 2.699 Gib/s | -| size=4.0Kib, N=262144 | 20.940 Gib/s | 9.145 Gib/s | 7.400 Gib/s | 3.871 Gib/s | 2.729 Gib/s | -| size=8.0Kib, N=131072 | 21.162 Gib/s | 9.258 Gib/s | 7.672 Gib/s | 3.925 Gib/s | 2.763 Gib/s | -| size=16.0Kib, N=65536 | 20.991 Gib/s | 9.758 Gib/s | 7.756 Gib/s | 3.945 Gib/s | 2.773 Gib/s | -| size=32.0Kib, N=32768 | 22.504 Gib/s | 9.956 Gib/s | 7.861 Gib/s | 3.966 Gib/s | 2.780 Gib/s | -| size=64.0Kib, N=16384 | 22.534 Gib/s | 10.088 Gib/s | 7.931 Gib/s | 3.974 Gib/s | 2.782 Gib/s | -| size=128.0Kib, N=8192 | 29.728 Gib/s | 10.032 Gib/s | 7.934 Gib/s | 3.975 Gib/s | 2.782 Gib/s | -| size=256.0Kib, N=4096 | 29.742 Gib/s | 10.116 Gib/s | 7.625 Gib/s | 3.886 Gib/s | 2.781 Gib/s | -| size=512.0Kib, N=2048 | 29.994 Gib/s | 10.090 Gib/s | 7.627 Gib/s | 3.985 Gib/s | 2.785 Gib/s | -| size=1.0Mib, N=1024 | 11.760 Gib/s | 10.091 Gib/s | 7.959 Gib/s | 3.989 Gib/s | 2.787 Gib/s | +| size=32b, N=33554432 | 1.382 Gib/s | 1.565 Gib/s | 1.493 Gib/s | 1.275 Gib/s | 1.166 Gib/s | +| size=64b, N=16777216 | 3.285 Gib/s | 2.669 Gib/s | 2.383 Gib/s | 1.861 Gib/s | 1.639 Gib/s | +| size=128b, N=8388608 | 6.162 Gib/s | 3.993 Gib/s | 3.480 Gib/s | 2.433 Gib/s | 2.060 Gib/s | +| size=256b, N=4194304 | 9.939 Gib/s | 5.323 Gib/s | 4.462 Gib/s | 2.724 Gib/s | 2.213 Gib/s | +| size=512b, N=2097152 | 15.777 Gib/s | 6.377 Gib/s | 4.913 Gib/s | 3.231 Gib/s | 2.457 Gib/s | +| size=1.0Kib, N=1048576 | 17.902 Gib/s | 7.010 Gib/s | 6.112 Gib/s | 3.568 Gib/s | 2.614 Gib/s | +| size=2.0Kib, N=524288 | 19.870 Gib/s | 8.248 Gib/s | 6.915 Gib/s | 3.764 Gib/s | 2.699 Gib/s | +| size=4.0Kib, N=262144 | 20.940 Gib/s | 9.145 Gib/s | 7.400 Gib/s | 3.871 Gib/s | 2.729 Gib/s | +| size=8.0Kib, N=131072 | 21.162 Gib/s | 9.258 Gib/s | 7.672 Gib/s | 3.925 Gib/s | 2.763 Gib/s | +| size=16.0Kib, N=65536 | 20.991 Gib/s | 9.758 Gib/s | 7.756 Gib/s | 3.945 Gib/s | 2.773 Gib/s | +| size=32.0Kib, N=32768 | 22.504 Gib/s | 9.956 Gib/s | 7.861 Gib/s | 3.966 Gib/s | 2.780 Gib/s | +| size=64.0Kib, N=16384 | 22.534 Gib/s | 10.088 Gib/s | 7.931 Gib/s | 3.974 Gib/s | 2.782 Gib/s | +| size=128.0Kib, N=8192 | 29.728 Gib/s | 10.032 Gib/s | 7.934 Gib/s | 3.975 Gib/s | 2.782 Gib/s | +| size=256.0Kib, N=4096 | 29.742 Gib/s | 10.116 Gib/s | 7.625 Gib/s | 3.886 Gib/s | 2.781 Gib/s | +| size=512.0Kib, N=2048 | 29.994 Gib/s | 10.090 Gib/s | 7.627 Gib/s | 3.985 Gib/s | 2.785 Gib/s | +| size=1.0Mib, N=1024 | 11.760 Gib/s | 10.091 Gib/s | 7.959 Gib/s | 3.989 Gib/s | 2.787 Gib/s | + + +## Motivation for Conditional Segment Initialization + +Under the current [threading proposal](https://github.com/WebAssembly/threads), +to share a module between multiple agents, the module must be instantiated +multiple times: once per agent. Instantiation initializes linear memory with +the contents in the module's data segments. If the memory is shared between +multiple agents, it will be initialized multiple times, potentially overwriting +stores that occurred after the previous initializations. + +For example: + +```webassembly +;; The module. +(module + (memory (export "memory") 1) + + ;; Some value used as a counter. + (data (i32.const 0) "\0") + + ;; Add one to the counter. + (func (export "addOne") + (i32.store8 + (i32.const 0) + (i32.add + (i32.load8_u (i32.const 0)) + (i32.const 1))) + ) +) +``` + +```javascript +// main.js +let moduleBytes = ...; + +WebAssembly.instantiate(moduleBytes).then( + ({module, instance}) => { + // Increment our counter. + instance.exports.addOne(); + + // Spawn a new Worker. + let worker = new Worker('worker.js'); + + // Send the module to the new Worker. + worker.postMessage(module); + }); + +// worker.js + +function onmessage(event) { + let module = event.data; + + // Use the module to create another instance. + WebAssembly.instantiate(module).then( + (instance) => { + // Oops, our counter has been clobbered. + }); +} + +``` + +This can be worked around by storing the data segments in a separate module +which is only instantiated once, then exporting this memory to be used by +another module that contains only code. This works, but it cumbersome since it +requires two modules where one should be enough. +## Motivation for combining Bulk Memory Operations + Conditional Segment Initialization Proposals + +When [discussing the design of Conditional Segment Initialization](https://github.com/WebAssembly/threads/issues/62), +we found that programmatic memory initialization from a read-only data segment +(via the `mem.init` instruction, described below) has similar behavior to the +proposed instruction to copy memory regions from linear memory (`mem.copy`, +also described below.) + ## Design -This proposal introduces 2 new instructions: +Copying between regions in linear memory or a table is accomplished with the +new `*.copy` instructions: + +* `mem.copy`: copy from one region of linear memory to another +* `table.copy`: copy from one region of a table to another + +Filling a memory region can be accomplished with `mem.set`: + +* `mem.set`: fill a region of linear memory with a given byte value + +TODO: should we provide `mem.clear` and `table.clear` instead? + +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. + +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 +_passive_. A passive 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 passive segment has no initializer expression, since it will be specified +as an operand to `mem.init` or `table.init`. -`mem.copy`: +Passive segments can also be discarded by using the following new instructions: -Copy data from a source memory region to destination region; -these regions may overlap: the copy is performed as if the source region was -first copied to a temporary buffer, then the temporary buffer is copied to -the destination region. +* `mem.drop`: prevent further use of a data segment +* `table.drop`: prevent further use of an element segment + +Attempting to drop an active segment is a validation error. + +The data section is encoded as follows: + +``` +datasec ::= seg*:section_11(vec(data)) => seg +data ::= 0x00 e:expr b*:vec(byte) => {data 0, offset e, init b*, active true} +data ::= 0x01 b*:vec(byte) => {data 0, offset empty, init b*, active false} +``` + +The element section is encoded similarly. + +### `mem.init` instruction + +The `mem.init` instruction copies data from a given passive 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 `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 `mem.init` operands. + +A trap occurs if: +* the segment is passive +* the segment is used after it has been dropped via `mem.drop` +* any of the accessed bytes lies outside the source data segment or the target memory + +Note that it is allowed to use `mem.init` on the same data segment more than +once. + +### `mem.drop` instruction + +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. + +### `mem.copy` instruction + +Copy data from a source memory region to destination region; these regions may +overlap: the copy is performed as if the source region was first copied to a +temporary buffer, then the temporary buffer is copied to the destination +region. The instruction has the signature `[i32 i32 i32] -> []`. The parameters are, in order: - top-2: destination address - top-1: source address - top-0: size of memory region in bytes - -`mem.set`: Set all bytes in a memory region to a given byte. + +### `mem.set` instruction + +Set all bytes in a memory region to a given byte. The instruction has the signature `[i32 i32 i32] -> []`. The parameters are, in order: @@ -99,87 +249,36 @@ The instruction has the signature `[i32 i32 i32] -> []`. The parameters are, in - top-1: byte value to set - top-0: size of memory region in bytes -## Structure +### `table.init`, `table.drop`, and `table.copy` instructions -Unlike most other memory operations, the bulk operations do not have a `memarg` -immediate. +The `table.*` instructions behave similary to the `mem.*` 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` and +`table.copy` have element units instead of bytes as well. -``` -instr ::== ... - | mem.copy - | mem.set -``` +## Conditional Segment Initialization Example -## Validation - -`mem.copy` - -* The memory `C.mems[0]` must be defined in the context. -* Then the instruction is valid with type `[i32 i32 i32] -> []`. - -`mem.set` - -* The memory `C.mems[0]` must be defined in the context. -* Then the instruction is valid with type `[i32 i32 i32] -> []`. - -## Execution - -`mem.copy` - -1. Let `F` be the current frame. -1. Assert: due to validation, `F.module.memaddrs[0]` exists. -1. Let `a` be the memory address `F.module.memaddrs[0]`. -1. Assert: due to validation, `S.mems[a]` exists. -1. Let `mem` be the memory instance `S.mems[a]`. -1. Assert: due to validation, a value of value type `i32` is on the top of the stack. -1. Pop the value `i32.const n` from the stack. -1. Assert: due to validation, a value of value type `i32` is on the top of the stack. -1. Pop the value `i32.const s` from the stack. -1. If `s + n` is larger than the length of `mem.data`, then: - 1. Trap. -1. Assert: due to validation, a value of value type `i32` is on the top of the stack. -1. Pop the value `i32.const d` from the stack. -1. If `d + n` is larger than the length of `mem.data`, then: - 1. Trap. -1. Let `b*` be the byte sequence `mem.data[s:n]`. -1. Replace the bytes `mem.data[d:n]` with `b*`. - -`mem.set` - -1. Let `F` be the current frame. -1. Assert: due to validation, `F.module.memaddrs[0]` exists. -1. Let `a` be the memory address `F.module.memaddrs[0]`. -1. Assert: due to validation, `S.mems[a]` exists. -1. Let `mem` be the memory instance `S.mems[a]`. -1. Assert: due to validation, a value of value type `i32` is on the top of the stack. -1. Pop the value `i32.const n` from the stack. -1. Assert: due to validation, a value of value type `i32` is on the top of the stack. -1. Pop the value `i32.const c` from the stack. -1. Assert: due to validation, a value of value type `i32` is on the top of the stack. -1. Pop the value `i32.const d` from the stack. -1. If `d + n` is larger than the length of `mem.data`, then: - 1. Trap. -1. Let `c_w` be the result of computing `wrap_{32,8}(c)`. -1. Let `b*` be the byte sequence `{bytes_i8(c_w)}^n`. -1. Replace the bytes `mem.data[d:n]` with `b*`. - -## Binary Format +Consider if there are two data sections, the first is always active and the +second is conditionally active if global 0 has a non-zero value. This could be +implemented as follows: -``` -instr ::= ... - | 0xC5 0x00 => mem.copy - | 0xC6 0x00 => mem.set -``` +```webassembly +(import "a" "global" (global i32)) ;; global 0 +(memory 1) +(data (i32.const 0) "hello") ;; data segment 0, is active so always copied +(data passive "goodbye") ;; data segment 1, is passive -Note that this skips `0xC0..0xC4` because those are currently proposed to be used for the -new sign-extending operators (see https://github.com/WebAssembly/threads/blob/master/proposals/threads/Overview.md#new-sign-extending-operators). +(func $start + (if (get_global 0) -An immediate byte is included for future extensions. It currently must be zero. + ;; copy data segment 1 into memory + (mem.init 1 + (i32.const 0) ;; source offset + (i32.const 16) ;; target offset + (i32.const 7)) ;; length -## Text Format - -``` -plaininstr_I ::= ... - | `mem.copy` => mem.copy - | `mem.set` => mem.set + ;; The memory used by this segment is no longer needed, so this segment can + ;; be dropped. + (mem.drop 1)) +) ``` From 5d60dabc59c2b63c78d42040bef22765ded53df8 Mon Sep 17 00:00:00 2001 From: Ben Smith Date: Thu, 1 Feb 2018 15:19:00 -0800 Subject: [PATCH 006/199] Rename `mem.set` to `mem.fill` (#6) I think it's a better name than `set`, especially considering we may have a `table.set` in the future, which will likely set just one value. It also follows naming of [Array.prototype.fill](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/fill) which has similar behavior. --- proposals/bulk-memory-operations/Overview.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/proposals/bulk-memory-operations/Overview.md b/proposals/bulk-memory-operations/Overview.md index 7c8ba41382..9a93c9d905 100644 --- a/proposals/bulk-memory-operations/Overview.md +++ b/proposals/bulk-memory-operations/Overview.md @@ -156,9 +156,9 @@ new `*.copy` instructions: * `mem.copy`: copy from one region of linear memory to another * `table.copy`: copy from one region of a table to another -Filling a memory region can be accomplished with `mem.set`: +Filling a memory region can be accomplished with `mem.fill`: -* `mem.set`: fill a region of linear memory with a given byte value +* `mem.fill`: fill a region of linear memory with a given byte value TODO: should we provide `mem.clear` and `table.clear` instead? @@ -239,7 +239,7 @@ The instruction has the signature `[i32 i32 i32] -> []`. The parameters are, in - top-1: source address - top-0: size of memory region in bytes -### `mem.set` instruction +### `mem.fill` instruction Set all bytes in a memory region to a given byte. From c71b28102a0615d7b202103c41b53f97a72ad977 Mon Sep 17 00:00:00 2001 From: Andreas Rossberg Date: Tue, 27 Feb 2018 16:05:33 +0100 Subject: [PATCH 007/199] Initial --- README.md | 28 +++++++++++++++++++++------- 1 file changed, 21 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index 26d58a3a5c..c202ce633e 100644 --- a/README.md +++ b/README.md @@ -1,14 +1,28 @@ -[![Build Status](https://travis-ci.org/WebAssembly/spec.svg?branch=master)](https://travis-ci.org/WebAssembly/spec) +[![Build Status](https://travis-ci.org/WebAssembly/multi-value.svg?branch=master)](https://travis-ci.org/WebAssembly/reference-types) + +# Reference Types Proposal for WebAssembly + +This repository is a clone of [github.com/WebAssembly/spec/](https://github.com/WebAssembly/spec/). +It is meant for discussion, prototype specification and implementation of a proposal to add support for basic reference types to WebAssembly. + +See the [overview](proposals/reference-types/Overview.md) for a summary of the proposal. + +Original `README` from upstream repository follows... # spec -This repository holds the sources for the WebAssembly draft specification -(to seed a future -[WebAssembly Working Group](https://lists.w3.org/Archives/Public/public-new-work/2017Jun/0005.html)), -a reference implementation, and the official testsuite. +This repository holds a prototypical reference implementation for WebAssembly, +which is currently serving as the official specification. Eventually, we expect +to produce a specification either written in human-readable prose or in a formal +specification language. + +It also holds the WebAssembly testsuite, which tests numerous aspects of +conformance to the spec. + +View the work-in-progress spec at [webassembly.github.io/spec](https://webassembly.github.io/spec/). -A formatted version of the spec is available here: -[webassembly.github.io/spec](https://webassembly.github.io/spec/), +At this time, the contents of this repository are under development and known +to be "incomplet and inkorrect". Participation is welcome. Discussions about new features, significant semantic changes, or any specification change likely to generate substantial discussion From 277308d84556b4e5e463210488c4276a257913e0 Mon Sep 17 00:00:00 2001 From: Andreas Rossberg Date: Mon, 5 Mar 2018 16:19:41 +0100 Subject: [PATCH 008/199] Add first sketch of overview --- proposals/reference-types/Overview.md | 245 ++++++++++++++++++++++++++ 1 file changed, 245 insertions(+) create mode 100644 proposals/reference-types/Overview.md diff --git a/proposals/reference-types/Overview.md b/proposals/reference-types/Overview.md new file mode 100644 index 0000000000..0b97907064 --- /dev/null +++ b/proposals/reference-types/Overview.md @@ -0,0 +1,245 @@ +# Reference Types for WebAssembly + +TODO: more text, motivation, explanation + +## Introduction + +Motivation: + +* Easier and more efficient interop with host environment + - allow host references to be represented directly by type `anyref` + - without having to go through tables, allocating slots, and maintaining index bijections at the boundaries + +* Basic manipulation of tables inside Wasm + - allow representing data structures containing references +by repurposing tables as a general memory for opaque data types + - allow manipulating function tables from within Wasm. + +* Set the stage for later additions: + + - Typed function references (see below) + - Exception references (see exception handling proposal) + - A smoother transition path to GC (see GC proposal) + +Get the most important parts soon! + +Summary: + +* Add a new type `anyref` that can be used as both a value type and a table element type. + +* Also allow `anyfunc` as a value type. + +* Introduce instructions to get and set table slots. + +* Allow multiple tables. + +Notes: + +* This extension does not imply GC by itself, only if host refs are GCed pointers! + +* Reference types are *opaque*, i.e., their value is abstract and they cannot be stored into linear memory. Tables are used as the equivalent. + + +## Language Extensions + +Typing extensions: + +* Introduce `anyref`, `anyfunc`, and `nullref` as a new class of *reference types*. + - `reftype ::= anyref | anyfunc | nullref` + - `nullref` is merely an internal type and is neither expressible in the binary format, nor the text format, nor the JS API. + - Question: should it be? + +* Value types (of locals, globals, function parameters and results) can now be either numeric types or reference types. + - `numtype ::= i32 | i64 | f32 | f64` + - `valtype ::= | ` + - locals with reference type are initialised with `null` + +* Element types (of tables) are equated with reference types. + - `elemtype ::= ` + +* Introduce a simple subtype relation between reference types. + - reflexive transitive closure of the following rules + - `n < anyref` for all reftypes `t` + - `anyfunc < anyref` + - Note: No rule `nullref < t` for all reftypes `t` -- while that is derivable from the above given the current set of types it might not hold for future reference types which don't allow null. + + +New/extended instructions: + +* The new instruction `ref.null` evaluates to the null reference constant. + - `ref.null : [] -> [nullref]` + - allowed in constant expressions + +* The new instruction `ref.is_null` checks for null. + - `ref.is_null : [anyref] -> [i32]` + +* The new instructions `table.get` and `table.set` access tables. + - `table.get $x : [i32] -> [t]` iff `t` is the element type of table `$x` + - `table.set $x : [i32 t] -> []` iff `t` is the element type of table `$x` + - `table.fill $x : [i32 i32 t] -> []` iff `t` is the element type of table `$x` + +* The `call_indirect` instruction takes a table index as immediate that identifies the table it calls through. + - `call_indirect (type $t) $x : [t1* i32] -> [t2*]` iff `$t` denotes the function type `[t1*] -> [t2*]` and the element type of table `$x` is a subtype of `anyfunc`. + - In the binary format, space for the index is already reserved. + - For backwards compatibility, the index may be omitted in the text format, in which case it defaults to 0. + + +Table extensions: + +* A module may define, import, and export multiple tables. + - As usual, the imports come first in the index space. + - This is already representable in the binary format. + +* Element segments take a table index as immediate that identifies the table they apply to. + - In the binary format, space for the index is already reserved. + - For backwards compatibility, the index may be omitted in the text format, in which case it defaults to 0. + + +API extensions: + +* Any JS object (non-primitive value) or `null` can be passed as `anyref` to a Wasm function, stored in a global, or in a table. + +* Any JS function object or `null` can be passed as `anyfunc` to a Wasm function, stored in a global, or in a table. + +* Only `null` can be passed as a `nullref` to a Wasm function, stored in a global, or in a table. + + +## Possible Future Extensions + + +### Equality on references + +Motivation: + +* Allow references to be compared by identity. +* However, not all reference types should be comparable, since that may make implementation details observable in a non-deterministic fashion (consider e.g. host JavaScript strings). + + +Additions: + +* Add `eqref` as the type of comparable references + - `reftype ::= ... | eqref` +* It is a subtype of `anyref` + - `eqref < anyref` + - `nullref < eqref` +* Add `ref.eq` instruction. + - `ref.eq : [eqref eqref] -> [i32]` + + +Questions: + +* Interaction with type imports/exports: do they need to distinguish equality types from non-equality now? + +* Similarly, the JS API for `WebAssembly.Type` below would need to enable the distinction. + + +### Typed function references + +Motivation: + +* Allow function pointers to be expressed directly without going through table and dynamic type check. +* Enable functions to be passed to other modules easily. + +Additions: + +* Add `(ref $t)` as a reference type + - `reftype ::= ... | ref ` +* Add `(ref.func $f)` and `(call_ref)` instructions + - `ref.func $f : [] -> (ref $t) iff $f : $t` + - `call_ref : [ts1 (ref $t)] -> [ts2]` iff `$t = [ts1] -> [ts2]` +* Introduce subtyping `ref < anyfunc` +* Subtying between concrete and universal reference types + - `ref $t < anyref` + - `ref < anyfunc` + - Note: reference types are not necessarily subtypes of `eqref`, including functions + +* Typed function references cannot be null! + +* The `table.grow` instruction (see bulk operation proposal) needs to take an initialisation argument. + +* Likewise `WebAssembly.Table#grow` takes an additional initialisation argument. + - optional for backwards compatibility, defaults to `null` + + +Question: + +* General function have no reasonable default, do we need scoped variables like `let`? +* Should there be a down cast instruction? +* Should there be depth subtyping for function types? + + +### Type Import/Export + +Motivation: + +* Allow the host (or Wasm modules) to distinguish different reference types. + +Additions: + +* Add `(type)` external type, enables types to be imported and exported + - `externtype ::= ... | type` + - `(ref $t)` can now denote an abstract type or a function reference + - imported types have index starting from 0. + - reserve byte in binary format to allow refinements later + +* Add abstract type definitions in type section + - `deftype ::= | new` + - creates unique abstract type + +* Add `WebAssembly.Type` class to JS API + - constructor `new WebAssembly.Type(name)` creates unique abstract type + +* Subtyping `ref ` < `anyref` + + +Questions: + +* Do we need to impose constraints on the order of imports, to stratify section dependencies? Should type import and export be separate sections instead? + +* Do we need a nullable `(ref opt $t)` type to allow use with locals etc.? Could a `(nullable T)` type constructor work instead? + - Unclear how `nullable` constructor would integrate exactly. Would it only allow (non-nullable) reference types as argument? Does this require a kind system? Should `anyref` be different from `(nullable anyref)`, or the latter disallowed? What about `anyfunc`? + - Semantically, thinking of `(nullable T)` as `T | nullref` could answer these questions, but we cannot support arbitrary unions in Wasm. + +* Should we add `(new)` definitional type to enable Wasm modules to define new types, too? + +* Do `new` definition types and the `WebAssembly.Type` constructor need to take a "comparable" flag controlling whether references to a type can be compared? + +* Should JS API allow specifying subtyping between new types? + + +### Down Casts + +Motivation: + +* Allow to implement generics by using `anyref` as a top type. + +Addition: + +* Add a `cast` instruction that checks whether its operand can be cast to a lower type and converts its type accordingly if so; otherwise, goes to an else branch. + - `cast * else * end: [] -> ` iff ` < ` and `* : [] -> ` and `* : [] -> ` + - could later be generalised to non-reference types? + +Note: + +* Can decompose `call_indirect` (assuming multi-value proposal): + - `(call_indirect $t $x)` reduces to `(table.get $x) (cast $t anyref (ref $t) (then (call_ref (ref $t))) (else (unreachable)))` + + +### GC Types + +See GC proposal. + + +### Further possible generalisations + +* Introduce reference types pointing to tables, memories, or globals. + - `deftype ::= ... | global | table | memory ` + - `ref.global $g : [] -> (ref $t)` iff `$g : $t` + - `ref.table $x : [] -> (ref $t)` iff `$x : $t` + - `ref.mem $m : [] -> (ref $t)` iff `$m : $t` + - yields first-class tables, memories, globals + - would requires duplicating all respective instructions + +* Allow all value types as element types. + - `deftype := ... | globaltype | tabletype | memtype` + - would unify element types with value types From c985a1be889d2f6af095dfe06c72916c9e3934f2 Mon Sep 17 00:00:00 2001 From: Andreas Rossberg Date: Tue, 6 Mar 2018 12:59:58 +0100 Subject: [PATCH 009/199] Add note --- proposals/reference-types/Overview.md | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/proposals/reference-types/Overview.md b/proposals/reference-types/Overview.md index 0b97907064..35859ed249 100644 --- a/proposals/reference-types/Overview.md +++ b/proposals/reference-types/Overview.md @@ -97,12 +97,11 @@ Table extensions: API extensions: -* Any JS object (non-primitive value) or `null` can be passed as `anyref` to a Wasm function, stored in a global, or in a table. +* Any JS object (non-primitive value) or string or symbol or `null` can be passed as `anyref` to a Wasm function, stored in a global, or in a table. + - It may be possible to allow all other non-primitive values as well, depending on details of existing engines. * Any JS function object or `null` can be passed as `anyfunc` to a Wasm function, stored in a global, or in a table. -* Only `null` can be passed as a `nullref` to a Wasm function, stored in a global, or in a table. - ## Possible Future Extensions @@ -125,6 +124,10 @@ Additions: * Add `ref.eq` instruction. - `ref.eq : [eqref eqref] -> [i32]` +API changes: + +* Any JS object (non-primitive value) or `null` can be passed as `eqref` to a Wasm function, stored in a global, or in a table. + Questions: From 835dc7d20df2aa7720ce1ea823d631d9e8f91f0f Mon Sep 17 00:00:00 2001 From: Sergey Rubanov Date: Thu, 8 Mar 2018 10:05:54 +0300 Subject: [PATCH 010/199] Fix typo in subtype relation (#5) --- proposals/reference-types/Overview.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/proposals/reference-types/Overview.md b/proposals/reference-types/Overview.md index 35859ed249..00453a073d 100644 --- a/proposals/reference-types/Overview.md +++ b/proposals/reference-types/Overview.md @@ -59,7 +59,7 @@ Typing extensions: * Introduce a simple subtype relation between reference types. - reflexive transitive closure of the following rules - - `n < anyref` for all reftypes `t` + - `t < anyref` for all reftypes `t` - `anyfunc < anyref` - Note: No rule `nullref < t` for all reftypes `t` -- while that is derivable from the above given the current set of types it might not hold for future reference types which don't allow null. From 9f0c7aa37740e4c320f4b4e4adb3065fcfab16da Mon Sep 17 00:00:00 2001 From: Andreas Rossberg Date: Tue, 13 Mar 2018 19:16:07 +0100 Subject: [PATCH 011/199] Add links --- proposals/reference-types/Overview.md | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/proposals/reference-types/Overview.md b/proposals/reference-types/Overview.md index 00453a073d..6355da00b3 100644 --- a/proposals/reference-types/Overview.md +++ b/proposals/reference-types/Overview.md @@ -6,8 +6,8 @@ TODO: more text, motivation, explanation Motivation: -* Easier and more efficient interop with host environment - - allow host references to be represented directly by type `anyref` +* Easier and more efficient interop with host environment (see the [host bindings proposal](https://github.com/WebAssembly/host-bindings/blob/master/proposals/host-bindings/Overview.md)) + - allow host references to be represented directly by type `anyref` (see WebAssembly/host-bindings#9) - without having to go through tables, allocating slots, and maintaining index bijections at the boundaries * Basic manipulation of tables inside Wasm @@ -17,9 +17,9 @@ by repurposing tables as a general memory for opaque data types * Set the stage for later additions: - - Typed function references (see below) - - Exception references (see exception handling proposal) - - A smoother transition path to GC (see GC proposal) + - Typed function references (see [below](#typed-function-references)) + - Exception references (see the [exception handling proposal](https://github.com/WebAssembly/exception-handling/blob/master/proposals/Exceptions.md) and WebAssembly/host-bindings#10) + - A smoother transition path to GC (see the [GC proposal](https://github.com/WebAssembly/gc/blob/master/proposals/GC.md)) Get the most important parts soon! @@ -158,7 +158,7 @@ Additions: * Typed function references cannot be null! -* The `table.grow` instruction (see bulk operation proposal) needs to take an initialisation argument. +* The `table.grow` instruction (see the [bulk operation proposal](https://github.com/WebAssembly/bulk-memory-operations/blob/master/proposals/bulk-memory-operations/Overview.md)) needs to take an initialisation argument. * Likewise `WebAssembly.Table#grow` takes an additional initialisation argument. - optional for backwards compatibility, defaults to `null` @@ -230,7 +230,7 @@ Note: ### GC Types -See GC proposal. +See [GC proposal](https://github.com/WebAssembly/gc/blob/master/proposals/GC.md). ### Further possible generalisations From 7a8d371136db960a7a16a30aad87d7f85ff4a8a3 Mon Sep 17 00:00:00 2001 From: Andreas Rossberg Date: Tue, 13 Mar 2018 19:19:33 +0100 Subject: [PATCH 012/199] Fix issue links --- proposals/reference-types/Overview.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/proposals/reference-types/Overview.md b/proposals/reference-types/Overview.md index 6355da00b3..2752da536f 100644 --- a/proposals/reference-types/Overview.md +++ b/proposals/reference-types/Overview.md @@ -7,7 +7,7 @@ TODO: more text, motivation, explanation Motivation: * Easier and more efficient interop with host environment (see the [host bindings proposal](https://github.com/WebAssembly/host-bindings/blob/master/proposals/host-bindings/Overview.md)) - - allow host references to be represented directly by type `anyref` (see WebAssembly/host-bindings#9) + - allow host references to be represented directly by type `anyref` (see [here](https://github.com/WebAssembly/host-bindings/issues/9)) - without having to go through tables, allocating slots, and maintaining index bijections at the boundaries * Basic manipulation of tables inside Wasm @@ -18,7 +18,7 @@ by repurposing tables as a general memory for opaque data types * Set the stage for later additions: - Typed function references (see [below](#typed-function-references)) - - Exception references (see the [exception handling proposal](https://github.com/WebAssembly/exception-handling/blob/master/proposals/Exceptions.md) and WebAssembly/host-bindings#10) + - Exception references (see the [exception handling proposal](https://github.com/WebAssembly/exception-handling/blob/master/proposals/Exceptions.md) and [here](https://github.com/WebAssembly/host-bindings/issues/10)) - A smoother transition path to GC (see the [GC proposal](https://github.com/WebAssembly/gc/blob/master/proposals/GC.md)) Get the most important parts soon! From 1d7785da726f3a31f84d916a81733654819cc53e Mon Sep 17 00:00:00 2001 From: Andreas Rossberg Date: Sat, 24 Mar 2018 10:53:30 +0100 Subject: [PATCH 013/199] [interpreter] Implement basic reference types and multiple tables (#2) --- interpreter/README.md | 49 ++++--- interpreter/binary/decode.ml | 33 +++-- interpreter/binary/encode.ml | 25 +++- interpreter/exec/eval.ml | 122 +++++++++++------- interpreter/exec/eval_numeric.ml | 146 ++++++++++++--------- interpreter/exec/eval_numeric.mli | 12 +- interpreter/host/env.ml | 6 +- interpreter/host/spectest.ml | 28 ++-- interpreter/runtime/global.ml | 13 +- interpreter/runtime/instance.ml | 17 ++- interpreter/runtime/memory.ml | 22 ++-- interpreter/runtime/memory.mli | 12 +- interpreter/runtime/table.ml | 20 +-- interpreter/runtime/table.mli | 11 +- interpreter/script/js.ml | 204 ++++++++++++++++++++++-------- interpreter/script/run.ml | 32 ++++- interpreter/script/script.ml | 22 +++- interpreter/syntax/ast.ml | 11 +- interpreter/syntax/operators.ml | 8 +- interpreter/syntax/types.ml | 88 +++++++++++-- interpreter/syntax/values.ml | 79 +++++------- interpreter/text/arrange.ml | 51 +++++--- interpreter/text/lexer.mll | 19 ++- interpreter/text/parser.mly | 71 +++++++---- interpreter/util/lib.ml | 5 + interpreter/util/lib.mli | 1 + interpreter/valid/valid.ml | 123 ++++++++++++------ test/core/binary.wast | 19 --- test/core/br_table.wast | 67 ++++++++++ test/core/exports.wast | 12 +- test/core/get_table.wast | 45 +++++++ test/core/globals.wast | 16 +++ test/core/imports.wast | 32 +++-- test/core/linking.wast | 17 +++ test/core/ref_eq.wast | 50 ++++++++ test/core/ref_isnull.wast | 64 ++++++++++ test/core/ref_null.wast | 9 ++ test/core/select.wast | 32 +++++ test/core/set_table.wast | 65 ++++++++++ 39 files changed, 1216 insertions(+), 442 deletions(-) create mode 100644 test/core/get_table.wast create mode 100644 test/core/ref_eq.wast create mode 100644 test/core/ref_isnull.wast create mode 100644 test/core/ref_null.wast create mode 100644 test/core/set_table.wast diff --git a/interpreter/README.md b/interpreter/README.md index af0ba20423..c2b656ba22 100644 --- a/interpreter/README.md +++ b/interpreter/README.md @@ -172,8 +172,8 @@ float: .?(e|E )? | 0x.?(p|P )? name: $( | | _ | . | + | - | * | / | \ | ^ | ~ | = | < | > | ! | ? | @ | # | $ | % | & | | | : | ' | `)+ string: "( | \n | \t | \\ | \' | \" | \ | \u{+})*" -value: | -var: | +num: | +var: | unop: ctz | clz | popcnt | ... binop: add | sub | mul | ... @@ -183,12 +183,13 @@ offset: offset= align: align=(1|2|4|8|...) cvtop: trunc_s | trunc_u | extend_s | extend_u | ... -val_type: i32 | i64 | f32 | f64 -elem_type: anyfunc +num_type: i32 | i64 | f32 | f64 +ref_type: anyref | anyfunc | anyeqref +val_type: num_type | ref_type block_type : ( result * )* func_type: ( type )? * * global_type: | ( mut ) -table_type: ? +table_type: ? memory_type: ? expr: @@ -223,16 +224,21 @@ op: tee_local get_global set_global - .load((8|16|32)_)? ? ? - .store(8|16|32)? ? ? + get_table + set_table + .load((8|16|32)_)? ? ? + .store(8|16|32)? ? ? current_memory grow_memory - .const - . - . - . - . - ./ + ref.null + ref.isnull + ref.eq + .const + . + . + . + . + ./ func: ( func ? * * ) ( func ? ( export ) <...> ) ;; = (export (func )) (func ? <...>) @@ -247,7 +253,7 @@ global: ( global ? * ) table: ( table ? ) ( table ? ( export ) <...> ) ;; = (export (table )) (table ? <...>) ( table ? ( import ) ) ;; = (import ? (table )) - ( table ? ( export )* ( elem * ) ) ;; = (table ? ( export )* ) (elem (i32.const 0) *) + ( table ? ( export )* ( elem * ) ) ;; = (table ? ( export )* ) (elem (i32.const 0) *) elem: ( elem ? (offset * ) * ) ( elem ? * ) ;; = (elem ? (offset ) *) memory: ( memory ? ) @@ -272,9 +278,9 @@ exkind: ( func ) ( table ) ( memory ) -module: ( module ? * * * * ? ? * * * ? ) - * * * *
? ? * * * ? ;; = - ( module * * * *
? ? * * * ? ) +module: ( module ? * * * *
* ? * * * ? ) + * * * *
* ? * * * ? ;; = + ( module * * * *
* ? * * * ? ) ``` Here, productions marked with respective comments are abbreviation forms for equivalent expansions (see the explanation of the AST below). @@ -320,11 +326,16 @@ module: ( module ? quote * ) ;; module quoted in text (may be malformed) action: - ( invoke ? * ) ;; invoke function export + ( invoke ? * ) ;; invoke function export ( get ? ) ;; get global export +const: + ( .const ) ;; number value + ( ref.null ) ;; null reference + ( ref.host ) ;; host reference + assertion: - ( assert_return * ) ;; assert action has expected results + ( assert_return * ) ;; assert action has expected results ( assert_return_canonical_nan ) ;; assert action results in NaN in a canonical form ( assert_return_arithmetic_nan ) ;; assert action results in NaN with 1 in MSB of fraction field ( assert_trap ) ;; assert action traps with given failure string diff --git a/interpreter/binary/decode.ml b/interpreter/binary/decode.ml index 68a8d9c4c9..6648f6735b 100644 --- a/interpreter/binary/decode.ml +++ b/interpreter/binary/decode.ml @@ -131,18 +131,25 @@ let sized f s = open Types -let value_type s = +let num_type s = match vs7 s with | -0x01 -> I32Type | -0x02 -> I64Type | -0x03 -> F32Type | -0x04 -> F64Type - | _ -> error s (pos s - 1) "invalid value type" + | _ -> error s (pos s - 1) "invalid number type" -let elem_type s = +let ref_type s = match vs7 s with | -0x10 -> AnyFuncType - | _ -> error s (pos s - 1) "invalid element type" + | -0x11 -> AnyRefType + | -0x12 -> AnyEqRefType + | _ -> error s (pos s - 1) "invalid reference type" + +let value_type s = + match peek s with + | Some n when n > 0x70 -> NumType (num_type s) + | _ -> RefType (ref_type s) let stack_type s = match peek s with @@ -164,7 +171,7 @@ let limits vu s = {min; max} let table_type s = - let t = elem_type s in + let t = ref_type s in let lim = limits vu32 s in TableType (lim, t) @@ -243,9 +250,9 @@ let rec instr s = | 0x10 -> call (at var s) | 0x11 -> + let y = at var s in let x = at var s in - expect 0x00 s "zero flag expected"; - call_indirect x + call_indirect x y | 0x12 | 0x13 | 0x14 | 0x15 | 0x16 | 0x17 | 0x18 | 0x19 as b -> illegal s pos b @@ -259,8 +266,10 @@ let rec instr s = | 0x22 -> tee_local (at var s) | 0x23 -> get_global (at var s) | 0x24 -> set_global (at var s) + | 0x25 -> get_table (at var s) + | 0x26 -> set_table (at var s) - | 0x25 | 0x26 | 0x27 as b -> illegal s pos b + | 0x27 as b -> illegal s pos b | 0x28 -> let a, o = memop s in i32_load a o | 0x29 -> let a, o = memop s in i64_load a o @@ -432,6 +441,14 @@ let rec instr s = | 0xbe -> f32_reinterpret_i32 | 0xbf -> f64_reinterpret_i64 + | 0xc0 | 0xc1 | 0xc2 | 0xc3 | 0xc4 | 0xc5 | 0xc6 | 0xc7 + | 0xc8 | 0xc9 | 0xca | 0xcb | 0xcc | 0xcd | 0xce | 0xcf as b -> illegal s pos b + + (* TODO: Allocate more adequate opcodes *) + | 0xd0 -> ref_null + | 0xd1 -> ref_isnull + | 0xd2 -> ref_eq + | b -> illegal s pos b and instr_block s = List.rev (instr_block' s []) diff --git a/interpreter/binary/encode.ml b/interpreter/binary/encode.ml index adbf418a44..d074433559 100644 --- a/interpreter/binary/encode.ml +++ b/interpreter/binary/encode.ml @@ -90,14 +90,21 @@ let encode m = open Types - let value_type = function + let num_type = function | I32Type -> vs7 (-0x01) | I64Type -> vs7 (-0x02) | F32Type -> vs7 (-0x03) | F64Type -> vs7 (-0x04) - let elem_type = function + let ref_type = function | AnyFuncType -> vs7 (-0x10) + | AnyRefType -> vs7 (-0x11) + | AnyEqRefType -> vs7 (-0x12) + | NullRefType -> assert false + + let value_type = function + | NumType t -> num_type t + | RefType t -> ref_type t let stack_type = function | [] -> vs7 (-0x40) @@ -107,13 +114,14 @@ let encode m = "cannot encode stack type with arity > 1 (yet)" let func_type = function - | FuncType (ins, out) -> vs7 (-0x20); vec value_type ins; vec value_type out + | FuncType (ins, out) -> + vs7 (-0x20); vec value_type ins; vec value_type out let limits vu {min; max} = bool (max <> None); vu min; opt vu max let table_type = function - | TableType (lim, t) -> elem_type t; limits vu32 lim + | TableType (lim, t) -> ref_type t; limits vu32 lim let memory_type = function | MemoryType lim -> limits vu32 lim @@ -156,7 +164,7 @@ let encode m = | BrTable (xs, x) -> op 0x0e; vec var xs; var x | Return -> op 0x0f | Call x -> op 0x10; var x - | CallIndirect x -> op 0x11; var x; u8 0x00 + | CallIndirect (x, y) -> op 0x11; var y; var x | Drop -> op 0x1a | Select -> op 0x1b @@ -166,6 +174,8 @@ let encode m = | TeeLocal x -> op 0x22; var x | GetGlobal x -> op 0x23; var x | SetGlobal x -> op 0x24; var x + | GetTable x -> op 0x25; var x + | SetTable x -> op 0x26; var x | Load ({ty = I32Type; sz = None; _} as mo) -> op 0x28; memop mo | Load ({ty = I64Type; sz = None; _} as mo) -> op 0x29; memop mo @@ -363,6 +373,11 @@ let encode m = | Convert (F64 F64Op.DemoteF64) -> assert false | Convert (F64 F64Op.ReinterpretInt) -> op 0xbf + (* TODO: Allocate more adequate opcodes *) + | Null -> op 0xd0 + | IsNull -> op 0xd1 + | Same -> op 0xd2 + let const c = list instr c.it; end_ () diff --git a/interpreter/exec/eval.ml b/interpreter/exec/eval.ml index a6bc8f3971..b601d80494 100644 --- a/interpreter/exec/eval.ml +++ b/interpreter/exec/eval.ml @@ -17,6 +17,13 @@ exception Trap = Trap.Error exception Crash = Crash.Error (* failure that cannot happen in valid code *) exception Exhaustion = Exhaustion.Error +let table_error at = function + | Table.Bounds -> "out of bounds table access" + | Table.SizeOverflow -> "table size overflow" + | Table.SizeLimit -> "table size limit reached" + | Table.Type -> Crash.error at "type mismatch at table access" + | exn -> raise exn + let memory_error at = function | Memory.Bounds -> "out of bounds memory access" | Memory.SizeOverflow -> "memory size overflow" @@ -30,8 +37,8 @@ let numeric_error at = function | Numeric_error.InvalidConversionToInteger -> "invalid conversion to integer" | Eval_numeric.TypeError (i, v, t) -> Crash.error at - ("type error, expected " ^ Types.string_of_value_type t ^ " as operand " ^ - string_of_int i ^ ", got " ^ Types.string_of_value_type (type_of v)) + ("type error, expected " ^ Types.string_of_num_type t ^ " as operand " ^ + string_of_int i ^ ", got " ^ Types.string_of_num_type (type_of_num v)) | exn -> raise exn @@ -80,17 +87,14 @@ let memory (inst : module_inst) x = lookup "memory" inst.memories x let global (inst : module_inst) x = lookup "global" inst.globals x let local (frame : frame) x = lookup "local" frame.locals x -let elem inst x i at = - match Table.load (table inst x) i with - | Table.Uninitialized -> - Trap.error at ("uninitialized element " ^ Int32.to_string i) - | f -> f - | exception Table.Bounds -> +let any_ref inst x i at = + try Table.load (table inst x) i with Table.Bounds -> Trap.error at ("undefined element " ^ Int32.to_string i) -let func_elem inst x i at = - match elem inst x i at with - | FuncElem f -> f +let func_ref inst x i at = + match any_ref inst x i at with + | FuncRef f -> f + | NullRef -> Trap.error at ("uninitialized element " ^ Int32.to_string i) | _ -> Crash.error at ("type mismatch for element " ^ Int32.to_string i) let take n (vs : 'a stack) at = @@ -130,25 +134,26 @@ let rec step (c : config) : config = | Loop (ts, es'), vs -> vs, [Label (0, [e' @@ e.at], ([], List.map plain es')) @@ e.at] - | If (ts, es1, es2), I32 0l :: vs' -> + | If (ts, es1, es2), Num (I32 0l) :: vs' -> vs', [Plain (Block (ts, es2)) @@ e.at] - | If (ts, es1, es2), I32 i :: vs' -> + | If (ts, es1, es2), Num (I32 i) :: vs' -> vs', [Plain (Block (ts, es1)) @@ e.at] | Br x, vs -> [], [Breaking (x.it, vs) @@ e.at] - | BrIf x, I32 0l :: vs' -> + | BrIf x, Num (I32 0l) :: vs' -> vs', [] - | BrIf x, I32 i :: vs' -> + | BrIf x, Num (I32 i) :: vs' -> vs', [Plain (Br x) @@ e.at] - | BrTable (xs, x), I32 i :: vs' when I32.ge_u i (Lib.List32.length xs) -> + | BrTable (xs, x), Num (I32 i) :: vs' + when I32.ge_u i (Lib.List32.length xs) -> vs', [Plain (Br x) @@ e.at] - | BrTable (xs, x), I32 i :: vs' -> + | BrTable (xs, x), Num (I32 i) :: vs' -> vs', [Plain (Br (Lib.List32.nth xs i)) @@ e.at] | Return, vs -> @@ -157,9 +162,9 @@ let rec step (c : config) : config = | Call x, vs -> vs, [Invoke (func frame.inst x) @@ e.at] - | CallIndirect x, I32 i :: vs -> - let func = func_elem frame.inst (0l @@ e.at) i e.at in - if type_ frame.inst x <> Func.type_of func then + | CallIndirect (x, y), Num (I32 i) :: vs -> + let func = func_ref frame.inst x i e.at in + if type_ frame.inst y <> Func.type_of func then vs, [Trapping "indirect call type mismatch" @@ e.at] else vs, [Invoke func @@ e.at] @@ -167,10 +172,10 @@ let rec step (c : config) : config = | Drop, v :: vs' -> vs', [] - | Select, I32 0l :: v2 :: v1 :: vs' -> + | Select, Num (I32 0l) :: v2 :: v1 :: vs' -> v2 :: vs', [] - | Select, I32 i :: v2 :: v1 :: vs' -> + | Select, Num (I32 i) :: v2 :: v1 :: vs' -> v1 :: vs', [] | GetLocal x, vs -> @@ -192,66 +197,89 @@ let rec step (c : config) : config = with Global.NotMutable -> Crash.error e.at "write to immutable global" | Global.Type -> Crash.error e.at "type mismatch at global write") - | Load {offset; ty; sz; _}, I32 i :: vs' -> + | GetTable x, Num (I32 i) :: vs' -> + (try Ref (Table.load (table frame.inst x) i) :: vs', [] + with exn -> vs', [Trapping (table_error e.at exn) @@ e.at]) + + | SetTable x, Ref r :: Num (I32 i) :: vs' -> + (try Table.store (table frame.inst x) i r; vs', [] + with exn -> vs', [Trapping (table_error e.at exn) @@ e.at]) + + | Load {offset; ty; sz; _}, Num (I32 i) :: vs' -> let mem = memory frame.inst (0l @@ e.at) in let addr = I64_convert.extend_u_i32 i in (try - let v = + let n = match sz with - | None -> Memory.load_value mem addr offset ty + | None -> Memory.load_num mem addr offset ty | Some (sz, ext) -> Memory.load_packed sz ext mem addr offset ty - in v :: vs', [] + in Num n :: vs', [] with exn -> vs', [Trapping (memory_error e.at exn) @@ e.at]) - | Store {offset; sz; _}, v :: I32 i :: vs' -> + | Store {offset; sz; _}, Num n :: Num (I32 i) :: vs' -> let mem = memory frame.inst (0l @@ e.at) in let addr = I64_convert.extend_u_i32 i in (try (match sz with - | None -> Memory.store_value mem addr offset v - | Some sz -> Memory.store_packed sz mem addr offset v + | None -> Memory.store_num mem addr offset n + | Some sz -> Memory.store_packed sz mem addr offset n ); vs', [] with exn -> vs', [Trapping (memory_error e.at exn) @@ e.at]); | CurrentMemory, vs -> let mem = memory frame.inst (0l @@ e.at) in - I32 (Memory.size mem) :: vs, [] + Num (I32 (Memory.size mem)) :: vs, [] - | GrowMemory, I32 delta :: vs' -> + | GrowMemory, Num (I32 delta) :: vs' -> let mem = memory frame.inst (0l @@ e.at) in let old_size = Memory.size mem in let result = try Memory.grow mem delta; old_size with Memory.SizeOverflow | Memory.SizeLimit | Memory.OutOfMemory -> -1l - in I32 result :: vs', [] + in Num (I32 result) :: vs', [] + + | Null, vs' -> + Ref NullRef :: vs', [] + + | IsNull, Ref NullRef :: vs' -> + Num (I32 1l) :: vs', [] + + | IsNull, v :: vs' -> + Num (I32 0l) :: vs', [] + + | Same, Ref r2 :: Ref r1 :: vs' when r1 = r2 -> + Num (I32 1l) :: vs', [] + + | Same, Ref r2 :: Ref r1 :: vs' -> + Num (I32 0l) :: vs', [] - | Const v, vs -> - v.it :: vs, [] + | Const n, vs -> + Num n.it :: vs, [] - | Test testop, v :: vs' -> - (try value_of_bool (Eval_numeric.eval_testop testop v) :: vs', [] + | Test testop, Num n :: vs' -> + (try value_of_bool (Eval_numeric.eval_testop testop n) :: vs', [] with exn -> vs', [Trapping (numeric_error e.at exn) @@ e.at]) - | Compare relop, v2 :: v1 :: vs' -> - (try value_of_bool (Eval_numeric.eval_relop relop v1 v2) :: vs', [] + | Compare relop, Num n2 :: Num n1 :: vs' -> + (try value_of_bool (Eval_numeric.eval_relop relop n1 n2) :: vs', [] with exn -> vs', [Trapping (numeric_error e.at exn) @@ e.at]) - | Unary unop, v :: vs' -> - (try Eval_numeric.eval_unop unop v :: vs', [] + | Unary unop, Num n :: vs' -> + (try Num (Eval_numeric.eval_unop unop n) :: vs', [] with exn -> vs', [Trapping (numeric_error e.at exn) @@ e.at]) - | Binary binop, v2 :: v1 :: vs' -> - (try Eval_numeric.eval_binop binop v1 v2 :: vs', [] + | Binary binop, Num n2 :: Num n1 :: vs' -> + (try Num (Eval_numeric.eval_binop binop n1 n2) :: vs', [] with exn -> vs', [Trapping (numeric_error e.at exn) @@ e.at]) - | Convert cvtop, v :: vs' -> - (try Eval_numeric.eval_cvtop cvtop v :: vs', [] + | Convert cvtop, Num n :: vs' -> + (try Num (Eval_numeric.eval_cvtop cvtop n) :: vs', [] with exn -> vs', [Trapping (numeric_error e.at exn) @@ e.at]) | _ -> let s1 = string_of_values (List.rev vs) in - let s2 = string_of_value_types (List.map type_of (List.rev vs)) in + let s2 = string_of_value_types (List.map type_of_value (List.rev vs)) in Crash.error e.at ("missing or ill-typed operand on stack (" ^ s1 ^ " : " ^ s2 ^ ")") ) @@ -349,7 +377,7 @@ let eval_const (inst : module_inst) (const : const) : value = let i32 (v : value) at = match v with - | I32 i -> i + | Num (I32 i) -> i | _ -> Crash.error at "type error: i32 value expected" @@ -396,7 +424,7 @@ let init_table (inst : module_inst) (seg : table_segment) = if I32.lt_u bound end_ || I32.lt_u end_ offset then Link.error seg.at "elements segment does not fit table"; fun () -> - Table.blit tab offset (List.map (fun x -> FuncElem (func inst x)) init) + Table.blit tab offset (List.map (fun x -> FuncRef (func inst x)) init) let init_memory (inst : module_inst) (seg : memory_segment) = let {index; offset = const; init} = seg.it in diff --git a/interpreter/exec/eval_numeric.ml b/interpreter/exec/eval_numeric.ml index dd40255875..7a84a2ca8b 100644 --- a/interpreter/exec/eval_numeric.ml +++ b/interpreter/exec/eval_numeric.ml @@ -2,29 +2,59 @@ open Types open Values -(* Runtime type errors *) +(* Injection & projection *) -exception TypeError of int * value * value_type +exception TypeError of int * num * num_type -let of_arg f n v = - try f v with Value t -> raise (TypeError (n, v, t)) +module type NumType = +sig + type t + val to_num : t -> num + val of_num : int -> num -> t +end + +module I32Num = +struct + type t = I32.t + let to_num i = I32 i + let of_num n = function I32 i -> i | v -> raise (TypeError (n, v, I32Type)) +end + +module I64Num = +struct + type t = I64.t + let to_num i = I64 i + let of_num n = function I64 i -> i | v -> raise (TypeError (n, v, I64Type)) +end + +module F32Num = +struct + type t = F32.t + let to_num i = F32 i + let of_num n = function F32 z -> z | v -> raise (TypeError (n, v, F32Type)) +end + +module F64Num = +struct + type t = F64.t + let to_num i = F64 i + let of_num n = function F64 z -> z | v -> raise (TypeError (n, v, F64Type)) +end (* Int operators *) -module IntOp (IXX : Int.S) (Value : ValueType with type t = IXX.t) = +module IntOp (IXX : Int.S) (Num : NumType with type t = IXX.t) = struct open Ast.IntOp - - let to_value = Value.to_value - let of_value = of_arg Value.of_value + open Num let unop op = let f = match op with | Clz -> IXX.clz | Ctz -> IXX.ctz | Popcnt -> IXX.popcnt - in fun v -> to_value (f (of_value 1 v)) + in fun v -> to_num (f (of_num 1 v)) let binop op = let f = match op with @@ -43,12 +73,12 @@ struct | ShrS -> IXX.shr_s | Rotl -> IXX.rotl | Rotr -> IXX.rotr - in fun v1 v2 -> to_value (f (of_value 1 v1) (of_value 2 v2)) + in fun v1 v2 -> to_num (f (of_num 1 v1) (of_num 2 v2)) let testop op = let f = match op with | Eqz -> IXX.eqz - in fun v -> f (of_value 1 v) + in fun v -> f (of_num 1 v) let relop op = let f = match op with @@ -62,21 +92,19 @@ struct | GtU -> IXX.gt_u | GeS -> IXX.ge_s | GeU -> IXX.ge_u - in fun v1 v2 -> f (of_value 1 v1) (of_value 2 v2) + in fun v1 v2 -> f (of_num 1 v1) (of_num 2 v2) end -module I32Op = IntOp (I32) (Values.I32Value) -module I64Op = IntOp (I64) (Values.I64Value) +module I32Op = IntOp (I32) (I32Num) +module I64Op = IntOp (I64) (I64Num) (* Float operators *) -module FloatOp (FXX : Float.S) (Value : ValueType with type t = FXX.t) = +module FloatOp (FXX : Float.S) (Num : NumType with type t = FXX.t) = struct open Ast.FloatOp - - let to_value = Value.to_value - let of_value = of_arg Value.of_value + open Num let unop op = let f = match op with @@ -87,7 +115,7 @@ struct | Floor -> FXX.floor | Trunc -> FXX.trunc | Nearest -> FXX.nearest - in fun v -> to_value (f (of_value 1 v)) + in fun v -> to_num (f (of_num 1 v)) let binop op = let f = match op with @@ -98,7 +126,7 @@ struct | Min -> FXX.min | Max -> FXX.max | CopySign -> FXX.copysign - in fun v1 v2 -> to_value (f (of_value 1 v1) (of_value 2 v2)) + in fun v1 v2 -> to_num (f (of_num 1 v1) (of_num 2 v2)) let testop op = assert false @@ -110,11 +138,11 @@ struct | Le -> FXX.le | Gt -> FXX.gt | Ge -> FXX.ge - in fun v1 v2 -> f (of_value 1 v1) (of_value 2 v2) + in fun v1 v2 -> f (of_num 1 v1) (of_num 2 v2) end -module F32Op = FloatOp (F32) (Values.F32Value) -module F64Op = FloatOp (F64) (Values.F64Value) +module F32Op = FloatOp (F32) (F32Num) +module F64Op = FloatOp (F64) (F64Num) (* Conversion operators *) @@ -124,15 +152,16 @@ struct open Ast.IntOp let cvtop op v = - match op with - | WrapI64 -> I32 (I32_convert.wrap_i64 (I64Op.of_value 1 v)) - | TruncSF32 -> I32 (I32_convert.trunc_s_f32 (F32Op.of_value 1 v)) - | TruncUF32 -> I32 (I32_convert.trunc_u_f32 (F32Op.of_value 1 v)) - | TruncSF64 -> I32 (I32_convert.trunc_s_f64 (F64Op.of_value 1 v)) - | TruncUF64 -> I32 (I32_convert.trunc_u_f64 (F64Op.of_value 1 v)) - | ReinterpretFloat -> I32 (I32_convert.reinterpret_f32 (F32Op.of_value 1 v)) - | ExtendSI32 -> raise (TypeError (1, v, I32Type)) - | ExtendUI32 -> raise (TypeError (1, v, I32Type)) + let i = match op with + | WrapI64 -> I32_convert.wrap_i64 (I64Num.of_num 1 v) + | TruncSF32 -> I32_convert.trunc_s_f32 (F32Num.of_num 1 v) + | TruncUF32 -> I32_convert.trunc_u_f32 (F32Num.of_num 1 v) + | TruncSF64 -> I32_convert.trunc_s_f64 (F64Num.of_num 1 v) + | TruncUF64 -> I32_convert.trunc_u_f64 (F64Num.of_num 1 v) + | ReinterpretFloat -> I32_convert.reinterpret_f32 (F32Num.of_num 1 v) + | ExtendSI32 -> raise (TypeError (1, v, I32Type)) + | ExtendUI32 -> raise (TypeError (1, v, I32Type)) + in I32Num.to_num i end module I64CvtOp = @@ -140,15 +169,16 @@ struct open Ast.IntOp let cvtop op v = - match op with - | ExtendSI32 -> I64 (I64_convert.extend_s_i32 (I32Op.of_value 1 v)) - | ExtendUI32 -> I64 (I64_convert.extend_u_i32 (I32Op.of_value 1 v)) - | TruncSF32 -> I64 (I64_convert.trunc_s_f32 (F32Op.of_value 1 v)) - | TruncUF32 -> I64 (I64_convert.trunc_u_f32 (F32Op.of_value 1 v)) - | TruncSF64 -> I64 (I64_convert.trunc_s_f64 (F64Op.of_value 1 v)) - | TruncUF64 -> I64 (I64_convert.trunc_u_f64 (F64Op.of_value 1 v)) - | ReinterpretFloat -> I64 (I64_convert.reinterpret_f64 (F64Op.of_value 1 v)) - | WrapI64 -> raise (TypeError (1, v, I64Type)) + let i = match op with + | ExtendSI32 -> I64_convert.extend_s_i32 (I32Num.of_num 1 v) + | ExtendUI32 -> I64_convert.extend_u_i32 (I32Num.of_num 1 v) + | TruncSF32 -> I64_convert.trunc_s_f32 (F32Num.of_num 1 v) + | TruncUF32 -> I64_convert.trunc_u_f32 (F32Num.of_num 1 v) + | TruncSF64 -> I64_convert.trunc_s_f64 (F64Num.of_num 1 v) + | TruncUF64 -> I64_convert.trunc_u_f64 (F64Num.of_num 1 v) + | ReinterpretFloat -> I64_convert.reinterpret_f64 (F64Num.of_num 1 v) + | WrapI64 -> raise (TypeError (1, v, I64Type)) + in I64Num.to_num i end module F32CvtOp = @@ -156,14 +186,15 @@ struct open Ast.FloatOp let cvtop op v = - match op with - | DemoteF64 -> F32 (F32_convert.demote_f64 (F64Op.of_value 1 v)) - | ConvertSI32 -> F32 (F32_convert.convert_s_i32 (I32Op.of_value 1 v)) - | ConvertUI32 -> F32 (F32_convert.convert_u_i32 (I32Op.of_value 1 v)) - | ConvertSI64 -> F32 (F32_convert.convert_s_i64 (I64Op.of_value 1 v)) - | ConvertUI64 -> F32 (F32_convert.convert_u_i64 (I64Op.of_value 1 v)) - | ReinterpretInt -> F32 (F32_convert.reinterpret_i32 (I32Op.of_value 1 v)) - | PromoteF32 -> raise (TypeError (1, v, F32Type)) + let z = match op with + | DemoteF64 -> F32_convert.demote_f64 (F64Num.of_num 1 v) + | ConvertSI32 -> F32_convert.convert_s_i32 (I32Num.of_num 1 v) + | ConvertUI32 -> F32_convert.convert_u_i32 (I32Num.of_num 1 v) + | ConvertSI64 -> F32_convert.convert_s_i64 (I64Num.of_num 1 v) + | ConvertUI64 -> F32_convert.convert_u_i64 (I64Num.of_num 1 v) + | ReinterpretInt -> F32_convert.reinterpret_i32 (I32Num.of_num 1 v) + | PromoteF32 -> raise (TypeError (1, v, F32Type)) + in F32Num.to_num z end module F64CvtOp = @@ -171,14 +202,15 @@ struct open Ast.FloatOp let cvtop op v = - match op with - | PromoteF32 -> F64 (F64_convert.promote_f32 (F32Op.of_value 1 v)) - | ConvertSI32 -> F64 (F64_convert.convert_s_i32 (I32Op.of_value 1 v)) - | ConvertUI32 -> F64 (F64_convert.convert_u_i32 (I32Op.of_value 1 v)) - | ConvertSI64 -> F64 (F64_convert.convert_s_i64 (I64Op.of_value 1 v)) - | ConvertUI64 -> F64 (F64_convert.convert_u_i64 (I64Op.of_value 1 v)) - | ReinterpretInt -> F64 (F64_convert.reinterpret_i64 (I64Op.of_value 1 v)) - | DemoteF64 -> raise (TypeError (1, v, F64Type)) + let z = match op with + | PromoteF32 -> F64_convert.promote_f32 (F32Num.of_num 1 v) + | ConvertSI32 -> F64_convert.convert_s_i32 (I32Num.of_num 1 v) + | ConvertUI32 -> F64_convert.convert_u_i32 (I32Num.of_num 1 v) + | ConvertSI64 -> F64_convert.convert_s_i64 (I64Num.of_num 1 v) + | ConvertUI64 -> F64_convert.convert_u_i64 (I64Num.of_num 1 v) + | ReinterpretInt -> F64_convert.reinterpret_i64 (I64Num.of_num 1 v) + | DemoteF64 -> raise (TypeError (1, v, F64Type)) + in F64Num.to_num z end diff --git a/interpreter/exec/eval_numeric.mli b/interpreter/exec/eval_numeric.mli index 7435b3c6bb..969e447490 100644 --- a/interpreter/exec/eval_numeric.mli +++ b/interpreter/exec/eval_numeric.mli @@ -1,9 +1,9 @@ open Values -exception TypeError of int * value * Types.value_type +exception TypeError of int * num * Types.num_type -val eval_unop : Ast.unop -> value -> value -val eval_binop : Ast.binop -> value -> value -> value -val eval_testop : Ast.testop -> value -> bool -val eval_relop : Ast.relop -> value -> value -> bool -val eval_cvtop : Ast.cvtop -> value -> value +val eval_unop : Ast.unop -> num -> num +val eval_binop : Ast.binop -> num -> num -> num +val eval_testop : Ast.testop -> num -> bool +val eval_relop : Ast.relop -> num -> num -> bool +val eval_cvtop : Ast.cvtop -> num -> num diff --git a/interpreter/host/env.ml b/interpreter/host/env.ml index a23838c503..58239d10bc 100644 --- a/interpreter/host/env.ml +++ b/interpreter/host/env.ml @@ -14,7 +14,7 @@ let error msg = raise (Eval.Crash (Source.no_region, msg)) let type_error v t = error ("type error, expected " ^ string_of_value_type t ^ - ", got " ^ string_of_value_type (type_of v)) + ", got " ^ string_of_value_type (type_of_value v)) let empty = function | [] -> () @@ -26,8 +26,8 @@ let single = function | vs -> error "type error, too many arguments" let int = function - | I32 i -> Int32.to_int i - | v -> type_error v I32Type + | Num (I32 i) -> Int32.to_int i + | v -> type_error v (NumType I32Type) let abort vs = diff --git a/interpreter/host/spectest.ml b/interpreter/host/spectest.ml index ae543f91e9..b7812e99bf 100644 --- a/interpreter/host/spectest.ml +++ b/interpreter/host/spectest.ml @@ -10,10 +10,11 @@ open Instance let global (GlobalType (t, _) as gt) = let v = match t with - | I32Type -> I32 666l - | I64Type -> I64 666L - | F32Type -> F32 (F32.of_float 666.6) - | F64Type -> F64 (F64.of_float 666.6) + | NumType I32Type -> Num (I32 666l) + | NumType I64Type -> Num (I64 666L) + | NumType F32Type -> Num (F32 (F32.of_float 666.6)) + | NumType F64Type -> Num (F64 (F64.of_float 666.6)) + | RefType _ -> Ref NullRef in Global.alloc gt v let table = Table.alloc (TableType ({min = 10l; max = Some 20l}, AnyFuncType)) @@ -22,7 +23,8 @@ let func f t = Func.alloc_host t (f t) let print_value v = Printf.printf "%s : %s\n" - (Values.string_of_value v) (Types.string_of_value_type (Values.type_of v)) + (Values.string_of_value v) + (Types.string_of_value_type (Values.type_of_value v)) let print (FuncType (_, out)) vs = List.iter print_value vs; @@ -33,16 +35,16 @@ let print (FuncType (_, out)) vs = let lookup name t = match Utf8.encode name, t with | "print", _ -> ExternFunc (func print (FuncType ([], []))) - | "print_i32", _ -> ExternFunc (func print (FuncType ([I32Type], []))) + | "print_i32", _ -> ExternFunc (func print (FuncType ([NumType I32Type], []))) | "print_i32_f32", _ -> - ExternFunc (func print (FuncType ([I32Type; F32Type], []))) + ExternFunc (func print (FuncType ([NumType I32Type; NumType F32Type], []))) | "print_f64_f64", _ -> - ExternFunc (func print (FuncType ([F64Type; F64Type], []))) - | "print_f32", _ -> ExternFunc (func print (FuncType ([F32Type], []))) - | "print_f64", _ -> ExternFunc (func print (FuncType ([F64Type], []))) - | "global_i32", _ -> ExternGlobal (global (GlobalType (I32Type, Immutable))) - | "global_f32", _ -> ExternGlobal (global (GlobalType (F32Type, Immutable))) - | "global_f64", _ -> ExternGlobal (global (GlobalType (F64Type, Immutable))) + ExternFunc (func print (FuncType ([NumType F64Type; NumType F64Type], []))) + | "print_f32", _ -> ExternFunc (func print (FuncType ([NumType F32Type], []))) + | "print_f64", _ -> ExternFunc (func print (FuncType ([NumType F64Type], []))) + | "global_i32", _ -> ExternGlobal (global (GlobalType (NumType I32Type, Immutable))) + | "global_f32", _ -> ExternGlobal (global (GlobalType (NumType F32Type, Immutable))) + | "global_f64", _ -> ExternGlobal (global (GlobalType (NumType F64Type, Immutable))) | "table", _ -> ExternTable table | "memory", _ -> ExternMemory memory | _ -> raise Not_found diff --git a/interpreter/runtime/global.ml b/interpreter/runtime/global.ml index c5375d7384..828da61d44 100644 --- a/interpreter/runtime/global.ml +++ b/interpreter/runtime/global.ml @@ -1,21 +1,20 @@ open Types open Values -type global = {mutable content : value; mut : mutability} +type global = {mutable content : value; ty : value_type; mut : mutability} type t = global exception Type exception NotMutable -let alloc (GlobalType (t, mut)) v = - if type_of v <> t then raise Type; - {content = v; mut = mut} +let alloc (GlobalType (ty, mut)) v = + if not (match_value_type (type_of_value v) ty) then raise Type; + {content = v; ty; mut} -let type_of glob = - GlobalType (type_of glob.content, glob.mut) +let type_of glob = GlobalType (glob.ty, glob.mut) let load glob = glob.content let store glob v = if glob.mut <> Mutable then raise NotMutable; - if Values.type_of v <> Values.type_of glob.content then raise Type; + if not (match_value_type (type_of_value v) glob.ty) then raise Type; glob.content <- v diff --git a/interpreter/runtime/instance.ml b/interpreter/runtime/instance.ml index 6ac583742d..2097f6a477 100644 --- a/interpreter/runtime/instance.ml +++ b/interpreter/runtime/instance.ml @@ -22,7 +22,22 @@ and extern = | ExternMemory of memory_inst | ExternGlobal of global_inst -type Table.elem += FuncElem of func_inst + +(* Reference type extensions *) + +type Values.ref_ += FuncRef of func_inst + +let () = + let type_of_ref' = !Values.type_of_ref' in + Values.type_of_ref' := function + | FuncRef _ -> AnyFuncType + | r -> type_of_ref' r + +let () = + let string_of_ref' = !Values.string_of_ref' in + Values.string_of_ref' := function + | FuncRef _ -> "func" + | r -> string_of_ref' r (* Auxiliary functions *) diff --git a/interpreter/runtime/memory.ml b/interpreter/runtime/memory.ml index fd9783d934..d9c150f47f 100644 --- a/interpreter/runtime/memory.ml +++ b/interpreter/runtime/memory.ml @@ -104,7 +104,7 @@ let storen mem a o n x = end in loop (effective_address a o) n x -let load_value mem a o t = +let load_num mem a o t = let n = loadn mem a o (Types.size t) in match t with | I32Type -> I32 (Int64.to_int32 n) @@ -112,14 +112,14 @@ let load_value mem a o t = | F32Type -> F32 (F32.of_bits (Int64.to_int32 n)) | F64Type -> F64 (F64.of_bits n) -let store_value mem a o v = +let store_num mem a o n = let x = - match v with + match n with | I32 x -> Int64.of_int32 x | I64 x -> x | F32 x -> Int64.of_int32 (F32.to_bits x) | F64 x -> F64.to_bits x - in storen mem a o (Types.size (Values.type_of v)) x + in storen mem a o (Types.size (Values.type_of_num n)) x let extend x n = function | ZX -> x @@ -127,19 +127,19 @@ let extend x n = function let load_packed sz ext mem a o t = assert (mem_size sz <= Types.size t); - let n = mem_size sz in - let x = extend (loadn mem a o n) n ext in + let w = mem_size sz in + let x = extend (loadn mem a o w) w ext in match t with | I32Type -> I32 (Int64.to_int32 x) | I64Type -> I64 x | _ -> raise Type -let store_packed sz mem a o v = - assert (mem_size sz <= Types.size (Values.type_of v)); - let n = mem_size sz in +let store_packed sz mem a o n = + assert (mem_size sz <= Types.size (Values.type_of_num n)); + let w = mem_size sz in let x = - match v with + match n with | I32 x -> Int64.of_int32 x | I64 x -> x | _ -> raise Type - in storen mem a o n x + in storen mem a o w x diff --git a/interpreter/runtime/memory.mli b/interpreter/runtime/memory.mli index c5586e7b9e..0a93901407 100644 --- a/interpreter/runtime/memory.mli +++ b/interpreter/runtime/memory.mli @@ -32,13 +32,13 @@ val store_byte : memory -> address -> int -> unit (* raises Bounds *) val load_bytes : memory -> address -> int -> string (* raises Bounds *) val store_bytes : memory -> address -> string -> unit (* raises Bounds *) -val load_value : - memory -> address -> offset -> value_type -> value (* raises Bounds *) -val store_value : - memory -> address -> offset -> value -> unit (* raises Bounds *) +val load_num : + memory -> address -> offset -> num_type -> num (* raises Bounds *) +val store_num : + memory -> address -> offset -> num -> unit (* raises Bounds *) val load_packed : - mem_size -> extension -> memory -> address -> offset -> value_type -> value + mem_size -> extension -> memory -> address -> offset -> num_type -> num (* raises Type, Bounds *) val store_packed : - mem_size -> memory -> address -> offset -> value -> unit + mem_size -> memory -> address -> offset -> num -> unit (* raises Type, Bounds *) diff --git a/interpreter/runtime/table.ml b/interpreter/runtime/table.ml index f48004d6cf..9958b7f76f 100644 --- a/interpreter/runtime/table.ml +++ b/interpreter/runtime/table.ml @@ -1,16 +1,15 @@ open Types +open Values type size = int32 type index = int32 -type elem = .. -type elem += Uninitialized - -type table' = elem array +type table' = ref_ array type table = - {mutable content : table'; max : size option; elem_type : elem_type} + {mutable content : table'; max : size option; elem_type : ref_type} type t = table +exception Type exception Bounds exception SizeOverflow exception SizeLimit @@ -20,7 +19,7 @@ let within_limits size = function | Some max -> I32.le_u size max let create size = - try Lib.Array32.make size Uninitialized + try Lib.Array32.make size NullRef with Invalid_argument _ -> raise Out_of_memory let alloc (TableType ({min; max}, elem_type)) = @@ -45,10 +44,11 @@ let grow tab delta = let load tab i = try Lib.Array32.get tab.content i with Invalid_argument _ -> raise Bounds -let store tab i v = - try Lib.Array32.set tab.content i v with Invalid_argument _ -> raise Bounds +let store tab i r = + if not (match_ref_type (type_of_ref r) tab.elem_type) then raise Type; + try Lib.Array32.set tab.content i r with Invalid_argument _ -> raise Bounds -let blit tab offset elems = - let data = Array.of_list elems in +let blit tab offset rs = + let data = Array.of_list rs in try Lib.Array32.blit data 0l tab.content offset (Lib.Array32.length data) with Invalid_argument _ -> raise Bounds diff --git a/interpreter/runtime/table.mli b/interpreter/runtime/table.mli index 7956d986d2..ae5fe69105 100644 --- a/interpreter/runtime/table.mli +++ b/interpreter/runtime/table.mli @@ -1,4 +1,5 @@ open Types +open Values type table type t = table @@ -6,9 +7,7 @@ type t = table type size = int32 type index = int32 -type elem = .. -type elem += Uninitialized - +exception Type exception Bounds exception SizeOverflow exception SizeLimit @@ -18,6 +17,6 @@ val type_of : table -> table_type val size : table -> size val grow : table -> size -> unit (* raises SizeOverflow, SizeLimit *) -val load : table -> index -> elem (* raises Bounds *) -val store : table -> index -> elem -> unit (* raises Bounds *) -val blit : table -> index -> elem list -> unit (* raises Bounds *) +val load : table -> index -> ref_ (* raises Bounds *) +val store : table -> index -> ref_ -> unit (* raises Type, Bounds *) +val blit : table -> index -> ref_ list -> unit (* raises Bounds *) diff --git a/interpreter/script/js.ml b/interpreter/script/js.ml index 3165756b44..5739c5614c 100644 --- a/interpreter/script/js.ml +++ b/interpreter/script/js.ml @@ -9,7 +9,23 @@ open Source let harness = "'use strict';\n" ^ "\n" ^ + "let hostrefs = {};\n" ^ + "let hostsym = Symbol(\"hostref\");\n" ^ + "function hostref(s) {\n" ^ + " if (! (s in hostrefs)) hostrefs[s] = {[hostsym]: s};\n" ^ + " return hostrefs[s];\n" ^ + "}\n" ^ + "function is_hostref(x) {\n" ^ + " return (x !== null && hostsym in x) ? 1 : 0;\n" ^ + "}\n" ^ + "function is_funcref(x) {\n" ^ + " return typeof x === \"function\" ? 1 : 0;\n" ^ + "}\n" ^ + "\n" ^ "let spectest = {\n" ^ + " hostref: hostref,\n" ^ + " is_hostref: is_hostref,\n" ^ + " is_funcref: is_funcref,\n" ^ " print: console.log.bind(console),\n" ^ " print_i32: console.log.bind(console),\n" ^ " print_i32_f32: console.log.bind(console),\n" ^ @@ -22,6 +38,7 @@ let harness = " table: new WebAssembly.Table({initial: 10, maximum: 20, element: 'anyfunc'}),\n" ^ " memory: new WebAssembly.Memory({initial: 1, maximum: 2})\n" ^ "};\n" ^ + "\n" ^ "let handler = {\n" ^ " get(target, prop) {\n" ^ " return (prop in target) ? target[prop] : {};\n" ^ @@ -64,8 +81,8 @@ let harness = " return instance.exports[name];\n" ^ "}\n" ^ "\n" ^ - "function exports(name, instance) {\n" ^ - " return {[name]: instance.exports};\n" ^ + "function exports(instance) {\n" ^ + " return {module: instance.exports, host: {ref: hostref}};\n" ^ "}\n" ^ "\n" ^ "function run(action) {\n" ^ @@ -143,6 +160,20 @@ let harness = " throw new Error(\"Wasm return value NaN expected, got \" + actual);\n" ^ " };\n" ^ "}\n" ^ + "\n" ^ + "function assert_return_ref(action) {\n" ^ + " let actual = action();\n" ^ + " if (actual === null || typeof actual !== \"object\" && typeof actual !== \"function\") {\n" ^ + " throw new Error(\"Wasm reference return value expected, got \" + actual);\n" ^ + " };\n" ^ + "}\n" ^ + "\n" ^ + "function assert_return_func(action) {\n" ^ + " let actual = action();\n" ^ + " if (typeof actual !== \"function\") {\n" ^ + " throw new Error(\"Wasm function return value expected, got \" + actual);\n" ^ + " };\n" ^ + "}\n" ^ "\n" @@ -185,6 +216,12 @@ let lookup (mods : modules) x_opt name at = (* Wrappers *) +let subject_idx = 0l +let hostref_idx = 1l +let _is_hostref_idx = 2l +let is_funcref_idx = 3l +let subject_type_idx = 4l + let eq_of = function | I32Type -> Values.I32 I32Op.Eq | I64Type -> Values.I64 I64Op.Eq @@ -209,53 +246,103 @@ let abs_mask_of = function | I32Type | F32Type -> Values.I32 Int32.max_int | I64Type | F64Type -> Values.I64 Int64.max_int -let invoke ft lits at = - [ft @@ at], FuncImport (1l @@ at) @@ at, - List.map (fun lit -> Const lit @@ at) lits @ [Call (0l @@ at) @@ at] +let value v = + match v.it with + | Values.Num num -> [Const (num @@ v.at) @@ v.at] + | Values.Ref Values.NullRef -> [Null @@ v.at] + | Values.Ref (HostRef n) -> + [Const (Values.I32 n @@ v.at) @@ v.at; Call (hostref_idx @@ v.at) @@ v.at] + | Values.Ref _ -> assert false + +let invoke ft vs at = + [ft @@ at], FuncImport (subject_type_idx @@ at) @@ at, + List.concat (List.map value vs) @ [Call (subject_idx @@ at) @@ at] let get t at = - [], GlobalImport t @@ at, [GetGlobal (0l @@ at) @@ at] + [], GlobalImport t @@ at, [GetGlobal (subject_idx @@ at) @@ at] let run ts at = [], [] -let assert_return lits ts at = - let test lit = - let t', reinterpret = reinterpret_of (Values.type_of lit.it) in - [ reinterpret @@ at; - Const lit @@ at; - reinterpret @@ at; - Compare (eq_of t') @@ at; - Test (Values.I32 I32Op.Eqz) @@ at; - BrIf (0l @@ at) @@ at ] - in [], List.flatten (List.rev_map test lits) +let assert_return vs ts at = + let test v = + match v.it with + | Values.Num num -> + let t', reinterpret = reinterpret_of (Values.type_of_num num) in + [ reinterpret @@ at; + Const (num @@ v.at) @@ at; + reinterpret @@ at; + Compare (eq_of t') @@ at; + Test (Values.I32 I32Op.Eqz) @@ at; + BrIf (0l @@ at) @@ at ] + | Values.Ref Values.NullRef -> + [ IsNull @@ at; + Test (Values.I32 I32Op.Eqz) @@ at; + BrIf (0l @@ at) @@ at ] + | Values.Ref (HostRef n) -> + [ Const (Values.I32 n @@ at) @@ at; + Call (hostref_idx @@ at) @@ at; + Same @@ at; + Test (Values.I32 I32Op.Eqz) @@ at; + BrIf (0l @@ at) @@ at ] + | _ -> assert false + in [], List.flatten (List.rev_map test vs) let assert_return_nan_bitpattern nan_bitmask_of ts at = - let test t = - let t', reinterpret = reinterpret_of t in - [ reinterpret @@ at; - Const (nan_bitmask_of t' @@ at) @@ at; - Binary (and_of t') @@ at; - Const (canonical_nan_of t' @@ at) @@ at; - Compare (eq_of t') @@ at; - Test (Values.I32 I32Op.Eqz) @@ at; - BrIf (0l @@ at) @@ at ] + let test = function + | NumType t -> + let t', reinterpret = reinterpret_of t in + [ reinterpret @@ at; + Const (nan_bitmask_of t' @@ at) @@ at; + Binary (and_of t') @@ at; + Const (canonical_nan_of t' @@ at) @@ at; + Compare (eq_of t') @@ at; + Test (Values.I32 I32Op.Eqz) @@ at; + BrIf (0l @@ at) @@ at ] + | RefType _ -> [Br (0l @@ at) @@ at] in [], List.flatten (List.rev_map test ts) -let assert_return_canonical_nan = - (* The result may only differ from the canonical NaN in its sign bit *) - assert_return_nan_bitpattern abs_mask_of +let assert_return_canonical_nan = assert_return_nan_bitpattern abs_mask_of +let assert_return_arithmetic_nan = assert_return_nan_bitpattern canonical_nan_of -let assert_return_arithmetic_nan = - (* The result can be any NaN that's one everywhere the canonical NaN is one *) - assert_return_nan_bitpattern canonical_nan_of +let assert_return_ref ts at = + let test = function + | NumType _ -> [Br (0l @@ at) @@ at] + | RefType _ -> + [ Null @@ at; + Same @@ at; + BrIf (0l @@ at) @@ at ] + in [], List.flatten (List.rev_map test ts) + +let assert_return_func ts at = + let test = function + | NumType _ -> [Br (0l @@ at) @@ at] + | RefType _ -> + [ Call (is_funcref_idx @@ at) @@ at; + Test (Values.I32 I32Op.Eqz) @@ at; + BrIf (0l @@ at) @@ at ] + in [], List.flatten (List.rev_map test ts) -let wrap module_name item_name wrap_action wrap_assertion at = +let wrap item_name wrap_action wrap_assertion at = let itypes, idesc, action = wrap_action at in let locals, assertion = wrap_assertion at in let item = Lib.List32.length itypes @@ at in - let types = (FuncType ([], []) @@ at) :: itypes in - let imports = [{module_name; item_name; idesc} @@ at] in + let types = + (FuncType ([], []) @@ at) :: + (FuncType ([NumType I32Type], [RefType AnyEqRefType]) @@ at) :: + (FuncType ([RefType AnyEqRefType], [NumType I32Type]) @@ at) :: + (FuncType ([RefType AnyEqRefType], [NumType I32Type]) @@ at) :: + itypes + in + let imports = + [ {module_name = Utf8.decode "module"; item_name; idesc} @@ at; + {module_name = Utf8.decode "spectest"; item_name = Utf8.decode "hostref"; + idesc = FuncImport (1l @@ at) @@ at} @@ at; + {module_name = Utf8.decode "spectest"; item_name = Utf8.decode "is_hostref"; + idesc = FuncImport (2l @@ at) @@ at} @@ at; + {module_name = Utf8.decode "spectest"; item_name = Utf8.decode "is_funcref"; + idesc = FuncImport (3l @@ at) @@ at} @@ at ] + in let edesc = FuncExport item @@ at in let exports = [{name = Utf8.decode "run"; edesc} @@ at] in let body = @@ -267,10 +354,14 @@ let wrap module_name item_name wrap_action wrap_assertion at = Encode.encode m -let is_js_value_type = function +let is_js_num_type = function | I32Type -> true | I64Type | F32Type | F64Type -> false +let is_js_value_type = function + | NumType t -> is_js_num_type t + | RefType t -> true + let is_js_global_type = function | GlobalType (t, mut) -> is_js_value_type t && mut = Immutable @@ -302,7 +393,6 @@ let of_string_with iter add_char s = Buffer.contents buf let of_bytes = of_string_with String.iter add_hex_char -let of_string = of_string_with String.iter add_char let of_name = of_string_with List.iter add_unicode_char let of_float z = @@ -313,12 +403,16 @@ let of_float z = | "-inf" -> "-Infinity" | s -> s -let of_literal lit = - match lit.it with - | Values.I32 i -> I32.to_string_s i - | Values.I64 i -> "int64(\"" ^ I64.to_string_s i ^ "\")" - | Values.F32 z -> of_float (F32.to_float z) - | Values.F64 z -> of_float (F64.to_float z) +let of_value v = + let open Values in + match v.it with + | Num (I32 i) -> I32.to_string_s i + | Num (I64 i) -> "int64(\"" ^ I64.to_string_s i ^ "\")" + | Num (F32 z) -> of_float (F32.to_float z) + | Num (F64 z) -> of_float (F64.to_float z) + | Ref NullRef -> "null" + | Ref (HostRef n) -> "hostref(" ^ Int32.to_string n ^ ")" + | _ -> assert false let rec of_definition def = match def.it with @@ -330,19 +424,19 @@ let rec of_definition def = let of_wrapper mods x_opt name wrap_action wrap_assertion at = let x = of_var_opt mods x_opt in - let bs = wrap (Utf8.decode x) name wrap_action wrap_assertion at in + let bs = wrap name wrap_action wrap_assertion at in "call(instance(" ^ of_bytes bs ^ ", " ^ - "exports(" ^ of_string x ^ ", " ^ x ^ ")), " ^ " \"run\", [])" + "exports(" ^ x ^ ")), " ^ " \"run\", [])" let of_action mods act = match act.it with - | Invoke (x_opt, name, lits) -> + | Invoke (x_opt, name, vs) -> "call(" ^ of_var_opt mods x_opt ^ ", " ^ of_name name ^ ", " ^ - "[" ^ String.concat ", " (List.map of_literal lits) ^ "])", + "[" ^ String.concat ", " (List.map of_value vs) ^ "])", (match lookup mods x_opt name act.at with | ExternFuncType ft when not (is_js_func_type ft) -> let FuncType (_, out) = ft in - Some (of_wrapper mods x_opt name (invoke ft lits), out) + Some (of_wrapper mods x_opt name (invoke ft vs), out) | _ -> None ) | Get (x_opt, name) -> @@ -376,13 +470,19 @@ let of_assertion mods ass = "assert_unlinkable(" ^ of_definition def ^ ");" | AssertUninstantiable (def, _) -> "assert_uninstantiable(" ^ of_definition def ^ ");" - | AssertReturn (act, lits) -> - of_assertion' mods act "assert_return" (List.map of_literal lits) - (Some (assert_return lits)) + | AssertReturn (act, vs) -> + of_assertion' mods act "assert_return" (List.map of_value vs) + (Some (assert_return vs)) | AssertReturnCanonicalNaN act -> - of_assertion' mods act "assert_return_canonical_nan" [] (Some assert_return_canonical_nan) + of_assertion' mods act "assert_return_canonical_nan" [] + (Some assert_return_canonical_nan) | AssertReturnArithmeticNaN act -> - of_assertion' mods act "assert_return_arithmetic_nan" [] (Some assert_return_arithmetic_nan) + of_assertion' mods act "assert_return_arithmetic_nan" [] + (Some assert_return_arithmetic_nan) + | AssertReturnRef act -> + of_assertion' mods act "assert_return_ref" [] (Some assert_return_ref) + | AssertReturnFunc act -> + of_assertion' mods act "assert_return_func" [] (Some assert_return_func) | AssertTrap (act, _) -> of_assertion' mods act "assert_trap" [] None | AssertExhaustion (act, _) -> diff --git a/interpreter/script/run.ml b/interpreter/script/run.ml index d1ec2866b6..0dfdd0f7d3 100644 --- a/interpreter/script/run.ml +++ b/interpreter/script/run.ml @@ -239,7 +239,7 @@ let print_module x_opt m = flush_all () let print_result vs = - let ts = List.map Values.type_of vs in + let ts = List.map Values.type_of_value vs in Printf.printf "%s : %s\n" (Values.string_of_values vs) (Types.string_of_value_types ts); flush_all () @@ -387,9 +387,10 @@ let run_assertion ass = trace ("Asserting return..."); let got_vs = run_action act in let is_canonical_nan = + let open Values in match got_vs with - | [Values.F32 got_f32] -> got_f32 = F32.pos_nan || got_f32 = F32.neg_nan - | [Values.F64 got_f64] -> got_f64 = F64.pos_nan || got_f64 = F64.neg_nan + | [Num (F32 got_f32)] -> got_f32 = F32.pos_nan || got_f32 = F32.neg_nan + | [Num (F64 got_f64)] -> got_f64 = F64.pos_nan || got_f64 = F64.neg_nan | _ -> false in assert_result ass.at is_canonical_nan got_vs print_endline "nan" @@ -397,16 +398,37 @@ let run_assertion ass = trace ("Asserting return..."); let got_vs = run_action act in let is_arithmetic_nan = + let open Values in match got_vs with - | [Values.F32 got_f32] -> + | [Num (F32 got_f32)] -> let pos_nan = F32.to_bits F32.pos_nan in Int32.logand (F32.to_bits got_f32) pos_nan = pos_nan - | [Values.F64 got_f64] -> + | [Num (F64 got_f64)] -> let pos_nan = F64.to_bits F64.pos_nan in Int64.logand (F64.to_bits got_f64) pos_nan = pos_nan | _ -> false in assert_result ass.at is_arithmetic_nan got_vs print_endline "nan" + | AssertReturnRef act -> + trace ("Asserting return..."); + let got_vs = run_action act in + let is_ref = + let open Values in + match got_vs with + | [Ref r] -> r <> NullRef + | _ -> false + in assert_result ass.at is_ref got_vs print_endline "ref" + + | AssertReturnFunc act -> + trace ("Asserting return..."); + let got_vs = run_action act in + let is_func = + let open Values in + match got_vs with + | [Ref r] -> r <> NullRef + | _ -> false + in assert_result ass.at is_func got_vs print_endline "func" + | AssertTrap (act, re) -> trace ("Asserting trap..."); (match run_action act with diff --git a/interpreter/script/script.ml b/interpreter/script/script.ml index ca83025408..af96ee0080 100644 --- a/interpreter/script/script.ml +++ b/interpreter/script/script.ml @@ -1,5 +1,8 @@ type var = string Source.phrase +type Values.ref_ += HostRef of int32 +type value = Values.value Source.phrase + type definition = definition' Source.phrase and definition' = | Textual of Ast.module_ @@ -8,7 +11,7 @@ and definition' = type action = action' Source.phrase and action' = - | Invoke of var option * Ast.name * Ast.literal list + | Invoke of var option * Ast.name * value list | Get of var option * Ast.name type assertion = assertion' Source.phrase @@ -17,9 +20,11 @@ and assertion' = | AssertInvalid of definition * string | AssertUnlinkable of definition * string | AssertUninstantiable of definition * string - | AssertReturn of action * Ast.literal list + | AssertReturn of action * value list | AssertReturnCanonicalNaN of action | AssertReturnArithmeticNaN of action + | AssertReturnRef of action + | AssertReturnFunc of action | AssertTrap of action * string | AssertExhaustion of action * string @@ -40,3 +45,16 @@ and meta' = and script = command list exception Syntax of Source.region * string + + +let () = + let type_of_ref' = !Values.type_of_ref' in + Values.type_of_ref' := function + | HostRef _ -> Types.AnyEqRefType + | r -> type_of_ref' r + +let () = + let string_of_ref' = !Values.string_of_ref' in + Values.string_of_ref' := function + | HostRef n -> "ref " ^ Int32.to_string n + | r -> string_of_ref' r diff --git a/interpreter/syntax/ast.ml b/interpreter/syntax/ast.ml index e2efa7ee89..7b7837420c 100644 --- a/interpreter/syntax/ast.ml +++ b/interpreter/syntax/ast.ml @@ -56,7 +56,7 @@ type relop = (I32Op.relop, I64Op.relop, F32Op.relop, F64Op.relop) Values.op type cvtop = (I32Op.cvtop, I64Op.cvtop, F32Op.cvtop, F64Op.cvtop) Values.op type 'a memop = - {ty : value_type; align : int; offset : Memory.offset; sz : 'a option} + {ty : num_type; align : int; offset : Memory.offset; sz : 'a option} type loadop = (Memory.mem_size * Memory.extension) memop type storeop = Memory.mem_size memop @@ -64,7 +64,7 @@ type storeop = Memory.mem_size memop (* Expressions *) type var = int32 Source.phrase -type literal = Values.value Source.phrase +type literal = Values.num Source.phrase type name = int list type instr = instr' Source.phrase @@ -79,7 +79,7 @@ and instr' = | BrTable of var list * var (* indexed break *) | Return (* break from function body *) | Call of var (* call function *) - | CallIndirect of var (* call function through table *) + | CallIndirect of var * var (* call function through table *) | Drop (* forget a value *) | Select (* branchless conditional *) | GetLocal of var (* read local variable *) @@ -87,10 +87,15 @@ and instr' = | TeeLocal of var (* write local variable and keep value *) | GetGlobal of var (* read global variable *) | SetGlobal of var (* write global variable *) + | GetTable of var (* read table element *) + | SetTable of var (* write table element *) | Load of loadop (* read memory at address *) | Store of storeop (* write memory at address *) | CurrentMemory (* size of linear memory *) | GrowMemory (* grow linear memory *) + | Null (* null reference *) + | IsNull (* null test *) + | Same (* reference equality *) | Const of literal (* constant *) | Test of testop (* numeric test *) | Compare of relop (* numeric comparison *) diff --git a/interpreter/syntax/operators.ml b/interpreter/syntax/operators.ml index b207b193db..05253bb19d 100644 --- a/interpreter/syntax/operators.ml +++ b/interpreter/syntax/operators.ml @@ -9,6 +9,10 @@ let i32_const n = Const (I32 n.it @@ n.at) let i64_const n = Const (I64 n.it @@ n.at) let f32_const n = Const (F32 n.it @@ n.at) let f64_const n = Const (F64 n.it @@ n.at) +let ref_null = Null + +let ref_isnull = IsNull +let ref_eq = Same let unreachable = Unreachable let nop = Nop @@ -23,13 +27,15 @@ let if_ ts es1 es2 = If (ts, es1, es2) let select = Select let call x = Call x -let call_indirect x = CallIndirect x +let call_indirect x y = CallIndirect (x, y) let get_local x = GetLocal x let set_local x = SetLocal x let tee_local x = TeeLocal x let get_global x = GetGlobal x let set_global x = SetGlobal x +let get_table x = GetTable x +let set_table x = SetTable x let i32_load align offset = Load {ty = I32Type; align; offset; sz = None} let i64_load align offset = Load {ty = I64Type; align; offset; sz = None} diff --git a/interpreter/syntax/types.ml b/interpreter/syntax/types.ml index f708e4b890..39db555bd0 100644 --- a/interpreter/syntax/types.ml +++ b/interpreter/syntax/types.ml @@ -1,13 +1,14 @@ (* Types *) -type value_type = I32Type | I64Type | F32Type | F64Type -type elem_type = AnyFuncType +type num_type = I32Type | I64Type | F32Type | F64Type +type ref_type = NullRefType | AnyEqRefType | AnyRefType | AnyFuncType +type value_type = NumType of num_type | RefType of ref_type type stack_type = value_type list type func_type = FuncType of stack_type * stack_type type 'a limits = {min : 'a; max : 'a option} type mutability = Immutable | Mutable -type table_type = TableType of Int32.t limits * elem_type +type table_type = TableType of Int32.t limits * ref_type type memory_type = MemoryType of Int32.t limits type global_type = GlobalType of value_type * mutability type extern_type = @@ -26,6 +27,21 @@ let size = function (* Subtyping *) +let match_num_type t1 t2 = + t1 = t2 + +let match_ref_type t1 t2 = + match t1, t2 with + | _, AnyRefType -> true + | NullRefType, _ -> true + | _, _ -> t1 = t2 + +let match_value_type t1 t2 = + match t1, t2 with + | NumType t1', NumType t2' -> match_num_type t1' t2' + | RefType t1', RefType t2' -> match_ref_type t1' t2' + | _, _ -> false + let match_limits lim1 lim2 = I32.ge_u lim1.min lim2.min && match lim1.max, lim2.max with @@ -42,8 +58,9 @@ let match_table_type (TableType (lim1, et1)) (TableType (lim2, et2)) = let match_memory_type (MemoryType lim1) (MemoryType lim2) = match_limits lim1 lim2 -let match_global_type gt1 gt2 = - gt1 = gt2 +let match_global_type (GlobalType (t1, mut1)) (GlobalType (t2, mut2)) = + mut1 = mut2 && + (t1 = t2 || mut2 = Immutable && match_value_type t1 t2) let match_extern_type et1 et2 = match et1, et2 with @@ -54,6 +71,50 @@ let match_extern_type et1 et2 = | _, _ -> false +(* Meet and join *) + +let join_num_type t1 t2 = + if t1 = t2 then Some t1 else None + +let join_ref_type t1 t2 = + match t1, t2 with + | AnyRefType, _ | _, NullRefType -> Some t1 + | _, AnyRefType | NullRefType, _ -> Some t2 + | _, _ when t1 = t2 -> Some t1 + | _, _ -> Some AnyRefType + +let join_value_type t1 t2 = + match t1, t2 with + | NumType t1', NumType t2' -> + Lib.Option.map (fun t' -> NumType t') (join_num_type t1' t2') + | RefType t1', RefType t2' -> + Lib.Option.map (fun t' -> RefType t') (join_ref_type t1' t2') + | _, _ -> None + + +let meet_num_type t1 t2 = + if t1 = t2 then Some t1 else None + +let meet_ref_type t1 t2 = + match t1, t2 with + | _, AnyRefType | NullRefType, _ -> Some t1 + | AnyRefType, _ | _, NullRefType -> Some t2 + | _, _ when t1 = t2 -> Some t1 + | _, _ -> Some NullRefType + +let meet_value_type t1 t2 = + match t1, t2 with + | NumType t1', NumType t2' -> + Lib.Option.map (fun t' -> NumType t') (meet_num_type t1' t2') + | RefType t1', RefType t2' -> + Lib.Option.map (fun t' -> RefType t') (meet_ref_type t1' t2') + | _, _ -> None + +let meet_stack_type ts1 ts2 = + try Some (List.map Lib.Option.force (List.map2 meet_value_type ts1 ts2)) + with Invalid_argument _ -> None + + (* Filters *) let funcs = @@ -68,19 +129,26 @@ let globals = (* String conversion *) -let string_of_value_type = function +let string_of_num_type = function | I32Type -> "i32" | I64Type -> "i64" | F32Type -> "f32" | F64Type -> "f64" +let string_of_ref_type = function + | NullRefType -> "nullref" + | AnyEqRefType -> "anyeqref" + | AnyRefType -> "anyref" + | AnyFuncType -> "anyfunc" + +let string_of_value_type = function + | NumType t -> string_of_num_type t + | RefType t -> string_of_ref_type t + let string_of_value_types = function | [t] -> string_of_value_type t | ts -> "[" ^ String.concat " " (List.map string_of_value_type ts) ^ "]" -let string_of_elem_type = function - | AnyFuncType -> "anyfunc" - let string_of_limits {min; max} = I32.to_string_u min ^ (match max with None -> "" | Some n -> " " ^ I32.to_string_u n) @@ -89,7 +157,7 @@ let string_of_memory_type = function | MemoryType lim -> string_of_limits lim let string_of_table_type = function - | TableType (lim, t) -> string_of_limits lim ^ " " ^ string_of_elem_type t + | TableType (lim, t) -> string_of_limits lim ^ " " ^ string_of_ref_type t let string_of_global_type = function | GlobalType (t, Immutable) -> string_of_value_type t diff --git a/interpreter/syntax/values.ml b/interpreter/syntax/values.ml index dedc14ab7c..de22eb36cc 100644 --- a/interpreter/syntax/values.ml +++ b/interpreter/syntax/values.ml @@ -6,74 +6,63 @@ open Types type ('i32, 'i64, 'f32, 'f64) op = I32 of 'i32 | I64 of 'i64 | F32 of 'f32 | F64 of 'f64 -type value = (I32.t, I64.t, F32.t, F64.t) op +type num = (I32.t, I64.t, F32.t, F64.t) op + +type ref_ = .. +type ref_ += NullRef + +type value = Num of num | Ref of ref_ (* Typing *) -let type_of = function +let type_of_num = function | I32 _ -> I32Type | I64 _ -> I64Type | F32 _ -> F32Type | F64 _ -> F64Type -let default_value = function +let type_of_ref' = ref (function NullRef -> NullRefType | _ -> AnyRefType) +let type_of_ref r = !type_of_ref' r + +let type_of_value = function + | Num n -> NumType (type_of_num n) + | Ref r -> RefType (type_of_ref r) + + +(* Defaults *) + +let default_num = function | I32Type -> I32 I32.zero | I64Type -> I64 I64.zero | F32Type -> F32 F32.zero | F64Type -> F64 F64.zero +let default_ref = function + | _ -> NullRef + +let default_value = function + | NumType t' -> Num (default_num t') + | RefType t' -> Ref (default_ref t') + (* Conversion *) -let value_of_bool b = I32 (if b then 1l else 0l) +let value_of_bool b = Num (I32 (if b then 1l else 0l)) -let string_of_value = function +let string_of_num = function | I32 i -> I32.to_string_s i | I64 i -> I64.to_string_s i | F32 z -> F32.to_string z | F64 z -> F64.to_string z +let string_of_ref' = ref (function NullRef -> "null" | _ -> "ref") +let string_of_ref r = !string_of_ref' r + +let string_of_value = function + | Num n -> string_of_num n + | Ref r -> string_of_ref r + let string_of_values = function | [v] -> string_of_value v | vs -> "[" ^ String.concat " " (List.map string_of_value vs) ^ "]" - - -(* Injection & projection *) - -exception Value of value_type - -module type ValueType = -sig - type t - val to_value : t -> value - val of_value : value -> t (* raise Value *) -end - -module I32Value = -struct - type t = I32.t - let to_value i = I32 i - let of_value = function I32 i -> i | _ -> raise (Value I32Type) -end - -module I64Value = -struct - type t = I64.t - let to_value i = I64 i - let of_value = function I64 i -> i | _ -> raise (Value I64Type) -end - -module F32Value = -struct - type t = F32.t - let to_value i = F32 i - let of_value = function F32 z -> z | _ -> raise (Value F32Type) -end - -module F64Value = -struct - type t = F64.t - let to_value i = F64 i - let of_value = function F64 z -> z | _ -> raise (Value F64Type) -end diff --git a/interpreter/text/arrange.ml b/interpreter/text/arrange.ml index c12d268b82..bd67ea0a3a 100644 --- a/interpreter/text/arrange.ml +++ b/interpreter/text/arrange.ml @@ -55,10 +55,10 @@ let break_string s = (* Types *) +let num_type t = string_of_num_type t +let ref_type t = string_of_ref_type t let value_type t = string_of_value_type t -let elem_type t = string_of_elem_type t - let decls kind ts = tab kind (atom value_type) ts let stack_type ts = decls "result" ts @@ -173,7 +173,7 @@ struct end let oper (intop, floatop) op = - value_type (type_of op) ^ "." ^ + num_type (type_of_num op) ^ "." ^ (match op with | I32 o -> intop "32" o | I64 o -> intop "64" o @@ -197,7 +197,7 @@ let extension = function | Memory.ZX -> "_u" let memop name {ty; align; offset; _} = - value_type ty ^ "." ^ name ^ + num_type ty ^ "." ^ name ^ (if offset = 0l then "" else " offset=" ^ nat32 offset) ^ (if 1 lsl align = size ty then "" else " align=" ^ nat (1 lsl align)) @@ -215,8 +215,8 @@ let storeop op = (* Expressions *) let var x = nat32 x.it -let value v = string_of_value v.it -let constop v = value_type (type_of v.it) ^ ".const" +let num v = string_of_num v.it +let constop v = num_type (type_of_num v.it) ^ ".const" let rec instr e = let head, inner = @@ -234,7 +234,8 @@ let rec instr e = "br_table " ^ String.concat " " (list var (xs @ [x])), [] | Return -> "return", [] | Call x -> "call " ^ var x, [] - | CallIndirect x -> "call_indirect", [Node ("type " ^ var x, [])] + | CallIndirect (x, y) -> + "call_indirect " ^ var x, [Node ("type " ^ var y, [])] | Drop -> "drop", [] | Select -> "select", [] | GetLocal x -> "get_local " ^ var x, [] @@ -242,11 +243,16 @@ let rec instr e = | TeeLocal x -> "tee_local " ^ var x, [] | GetGlobal x -> "get_global " ^ var x, [] | SetGlobal x -> "set_global " ^ var x, [] + | GetTable x -> "get_table " ^ var x, [] + | SetTable x -> "set_table " ^ var x, [] | Load op -> loadop op, [] | Store op -> storeop op, [] | CurrentMemory -> "current_memory", [] | GrowMemory -> "grow_memory", [] - | Const lit -> constop lit ^ " " ^ value lit, [] + | Null -> "ref.null", [] + | IsNull -> "ref.isnull", [] + | Same -> "ref.eq", [] + | Const lit -> constop lit ^ " " ^ num lit, [] | Test op -> testop op, [] | Compare op -> relop op, [] | Unary op -> unop op, [] @@ -282,7 +288,7 @@ let start x = Node ("start " ^ var x, []) let table off i tab = let {ttype = TableType (lim, t)} = tab.it in Node ("table $" ^ nat (off + i) ^ " " ^ limits nat32 lim, - [atom elem_type t] + [atom ref_type t] ) let memory off i mem = @@ -382,12 +388,15 @@ let module_ = module_with_var_opt None (* Scripts *) -let literal lit = - match lit.it with - | Values.I32 i -> Node ("i32.const " ^ I32.to_string_s i, []) - | Values.I64 i -> Node ("i64.const " ^ I64.to_string_s i, []) - | Values.F32 z -> Node ("f32.const " ^ F32.to_string z, []) - | Values.F64 z -> Node ("f64.const " ^ F64.to_string z, []) +let value v = + match v.it with + | Num (Values.I32 i) -> Node ("i32.const " ^ I32.to_string_s i, []) + | Num (Values.I64 i) -> Node ("i64.const " ^ I64.to_string_s i, []) + | Num (Values.F32 z) -> Node ("f32.const " ^ F32.to_string z, []) + | Num (Values.F64 z) -> Node ("f64.const " ^ F64.to_string z, []) + | Ref NullRef -> Node ("ref.null", []) + | Ref (HostRef n) -> Node ("ref.host " ^ Int32.to_string n, []) + | _ -> assert false let definition mode x_opt def = try @@ -416,8 +425,8 @@ let access x_opt n = let action act = match act.it with - | Invoke (x_opt, name, lits) -> - Node ("invoke" ^ access x_opt name, List.map literal lits) + | Invoke (x_opt, name, vs) -> + Node ("invoke" ^ access x_opt name, List.map value vs) | Get (x_opt, name) -> Node ("get" ^ access x_opt name, []) @@ -431,12 +440,16 @@ let assertion mode ass = Node ("assert_unlinkable", [definition mode None def; Atom (string re)]) | AssertUninstantiable (def, re) -> Node ("assert_trap", [definition mode None def; Atom (string re)]) - | AssertReturn (act, lits) -> - Node ("assert_return", action act :: List.map literal lits) + | AssertReturn (act, vs) -> + Node ("assert_return", action act :: List.map value vs) | AssertReturnCanonicalNaN act -> Node ("assert_return_canonical_nan", [action act]) | AssertReturnArithmeticNaN act -> Node ("assert_return_arithmetic_nan", [action act]) + | AssertReturnRef act -> + Node ("assert_return_ref", [action act]) + | AssertReturnFunc act -> + Node ("assert_return_func", [action act]) | AssertTrap (act, re) -> Node ("assert_trap", [action act; Atom (string re)]) | AssertExhaustion (act, re) -> diff --git a/interpreter/text/lexer.mll b/interpreter/text/lexer.mll index 2a41d8cfe7..fefb13eae1 100644 --- a/interpreter/text/lexer.mll +++ b/interpreter/text/lexer.mll @@ -45,7 +45,7 @@ let string s = done; Buffer.contents b -let value_type = function +let num_type = function | "i32" -> Types.I32Type | "i64" -> Types.I64Type | "f32" -> Types.F32Type @@ -160,7 +160,12 @@ rule token = parse | '"'character*'\\'_ { error_nest (Lexing.lexeme_end_p lexbuf) lexbuf "illegal escape" } - | (nxx as t) { VALUE_TYPE (value_type t) } + | "anyref" { ANYREF } + | "anyeqref" { ANYEQREF } + | "anyfunc" { ANYFUNC } + | (nxx as t) { NUM_TYPE (num_type t) } + | "mut" { MUT } + | (nxx as t)".const" { let open Source in CONST (numop t @@ -173,8 +178,10 @@ rule token = parse (fun s -> let n = F64.of_string s.it in f64_const (n @@ s.at), Values.F64 n)) } - | "anyfunc" { ANYFUNC } - | "mut" { MUT } + | "ref.null" { REF_NULL } + | "ref.host" { REF_HOST } + | "ref.isnull" { REF_ISNULL } + | "ref.eq" { REF_EQ } | "nop" { NOP } | "unreachable" { UNREACHABLE } @@ -198,6 +205,8 @@ rule token = parse | "tee_local" { TEE_LOCAL } | "get_global" { GET_GLOBAL } | "set_global" { SET_GLOBAL } + | "get_table" { GET_TABLE } + | "set_table" { SET_TABLE } | (nxx as t)".load" { LOAD (fun a o -> @@ -346,6 +355,8 @@ rule token = parse | "assert_return" { ASSERT_RETURN } | "assert_return_canonical_nan" { ASSERT_RETURN_CANONICAL_NAN } | "assert_return_arithmetic_nan" { ASSERT_RETURN_ARITHMETIC_NAN } + | "assert_return_ref" { ASSERT_RETURN_REF } + | "assert_return_func" { ASSERT_RETURN_FUNC } | "assert_trap" { ASSERT_TRAP } | "assert_exhaustion" { ASSERT_EXHAUSTION } | "input" { INPUT } diff --git a/interpreter/text/parser.mly b/interpreter/text/parser.mly index 685a05b0ca..13e646b1ea 100644 --- a/interpreter/text/parser.mly +++ b/interpreter/text/parser.mly @@ -145,11 +145,14 @@ let inline_type_explicit (c : context) x ft at = %} -%token NAT INT FLOAT STRING VAR VALUE_TYPE ANYFUNC MUT LPAR RPAR +%token LPAR RPAR +%token NAT INT FLOAT STRING VAR +%token ANYREF ANYEQREF ANYFUNC NUM_TYPE MUT %token NOP DROP BLOCK END IF THEN ELSE SELECT LOOP BR BR_IF BR_TABLE %token CALL CALL_INDIRECT RETURN -%token GET_LOCAL SET_LOCAL TEE_LOCAL GET_GLOBAL SET_GLOBAL +%token GET_LOCAL SET_LOCAL TEE_LOCAL GET_GLOBAL SET_GLOBAL GET_TABLE SET_TABLE %token LOAD STORE OFFSET_EQ_NAT ALIGN_EQ_NAT +%token REF_NULL REF_HOST REF_ISNULL REF_EQ %token CONST UNARY BINARY TEST COMPARE CONVERT %token UNREACHABLE CURRENT_MEMORY GROW_MEMORY %token FUNC START TYPE PARAM RESULT LOCAL GLOBAL @@ -157,7 +160,8 @@ let inline_type_explicit (c : context) x ft at = %token MODULE BIN QUOTE %token SCRIPT REGISTER INVOKE GET %token ASSERT_MALFORMED ASSERT_INVALID ASSERT_SOFT_INVALID ASSERT_UNLINKABLE -%token ASSERT_RETURN ASSERT_RETURN_CANONICAL_NAN ASSERT_RETURN_ARITHMETIC_NAN ASSERT_TRAP ASSERT_EXHAUSTION +%token ASSERT_RETURN ASSERT_RETURN_CANONICAL_NAN ASSERT_RETURN_ARITHMETIC_NAN +%token ASSERT_RETURN_REF ASSERT_RETURN_FUNC ASSERT_TRAP ASSERT_EXHAUSTION %token INPUT OUTPUT %token EOF @@ -166,8 +170,8 @@ let inline_type_explicit (c : context) x ft at = %token FLOAT %token STRING %token VAR -%token VALUE_TYPE -%token Ast.instr' * Values.value> CONST +%token NUM_TYPE +%token Ast.instr' * Values.num> CONST %token UNARY %token BINARY %token TEST @@ -200,16 +204,22 @@ string_list : /* Types */ +ref_type : + | ANYREF { AnyRefType } + | ANYEQREF { AnyEqRefType } + | ANYFUNC { AnyFuncType } + +value_type : + | NUM_TYPE { NumType $1 } + | ref_type { RefType $1 } + value_type_list : | /* empty */ { [] } - | VALUE_TYPE value_type_list { $1 :: $2 } - -elem_type : - | ANYFUNC { AnyFuncType } + | value_type value_type_list { $1 :: $2 } global_type : - | VALUE_TYPE { GlobalType ($1, Immutable) } - | LPAR MUT VALUE_TYPE RPAR { GlobalType ($3, Mutable) } + | value_type { GlobalType ($1, Immutable) } + | LPAR MUT value_type RPAR { GlobalType ($3, Mutable) } def_type : | LPAR FUNC func_type RPAR { $3 } @@ -223,11 +233,11 @@ func_type : FuncType (ins, $3 @ out) } | LPAR PARAM value_type_list RPAR func_type { let FuncType (ins, out) = $5 in FuncType ($3 @ ins, out) } - | LPAR PARAM bind_var VALUE_TYPE RPAR func_type /* Sugar */ + | LPAR PARAM bind_var value_type RPAR func_type /* Sugar */ { let FuncType (ins, out) = $6 in FuncType ($4 :: ins, out) } table_type : - | limits elem_type { TableType ($1, $2) } + | limits ref_type { TableType ($1, $2) } memory_type : | limits { MemoryType $1 } @@ -315,10 +325,15 @@ plain_instr : | TEE_LOCAL var { fun c -> tee_local ($2 c local) } | GET_GLOBAL var { fun c -> get_global ($2 c global) } | SET_GLOBAL var { fun c -> set_global ($2 c global) } + | GET_TABLE var { fun c -> get_table ($2 c table) } + | SET_TABLE var { fun c -> set_table ($2 c table) } | LOAD offset_opt align_opt { fun c -> $1 $3 $2 } | STORE offset_opt align_opt { fun c -> $1 $3 $2 } | CURRENT_MEMORY { fun c -> current_memory } | GROW_MEMORY { fun c -> grow_memory } + | REF_NULL { fun c -> ref_null } + | REF_ISNULL { fun c -> ref_isnull } + | REF_EQ { fun c -> ref_eq } | CONST literal { fun c -> fst (literal $1 $2) } | TEST { fun c -> $1 } | COMPARE { fun c -> $1 } @@ -327,9 +342,12 @@ plain_instr : | CONVERT { fun c -> $1 } call_instr : - | CALL_INDIRECT call_instr_type + | CALL_INDIRECT var call_instr_type + { let at1 = ati 1 in + fun c -> let x, es = $3 c in call_indirect ($2 c table) x @@ at1, es } + | CALL_INDIRECT call_instr_type /* Sugar */ { let at1 = ati 1 in - fun c -> let x, es = $2 c in call_indirect x @@ at1, es } + fun c -> let x, es = $2 c in call_indirect (0l @@ at1) x @@ at1, es } call_instr_type : | type_use call_instr_params @@ -367,7 +385,7 @@ block_instr : let ts, es1 = $3 c' in if_ ts es1 ($6 c') } block_type : - | LPAR RESULT VALUE_TYPE RPAR { [$3] } + | LPAR RESULT value_type RPAR { [$3] } block : | block_type instr_list @@ -380,8 +398,11 @@ expr : /* Sugar */ expr1 : /* Sugar */ | plain_instr expr_list { fun c -> $2 c, $1 c } - | CALL_INDIRECT call_expr_type - { fun c -> let x, es = $2 c in es, call_indirect x } + | CALL_INDIRECT var call_expr_type + { fun c -> let x, es = $3 c in es, call_indirect ($2 c table) x } + | CALL_INDIRECT call_expr_type /* Sugar */ + { let at1 = ati 1 in + fun c -> let x, es = $2 c in es, call_indirect (0l @@ at1) x } | BLOCK labeling_opt block { fun c -> let c' = $2 c [] in let ts, es = $3 c' in [], block ts es } | LOOP labeling_opt block @@ -476,7 +497,7 @@ func_fields_import : /* Sugar */ | func_fields_import_result { $1 } | LPAR PARAM value_type_list RPAR func_fields_import { let FuncType (ins, out) = $5 in FuncType ($3 @ ins, out) } - | LPAR PARAM bind_var VALUE_TYPE RPAR func_fields_import /* Sugar */ + | LPAR PARAM bind_var value_type RPAR func_fields_import /* Sugar */ { let FuncType (ins, out) = $6 in FuncType ($4 :: ins, out) } func_fields_import_result : /* Sugar */ @@ -490,7 +511,7 @@ func_fields_body : { let FuncType (ins, out) = fst $5 in FuncType ($3 @ ins, out), fun c -> ignore (anon_locals c $3); snd $5 c } - | LPAR PARAM bind_var VALUE_TYPE RPAR func_fields_body /* Sugar */ + | LPAR PARAM bind_var value_type RPAR func_fields_body /* Sugar */ { let FuncType (ins, out) = fst $6 in FuncType ($4 :: ins, out), fun c -> ignore (bind_local c $3); snd $6 c } @@ -508,7 +529,7 @@ func_body : | LPAR LOCAL value_type_list RPAR func_body { fun c -> ignore (anon_locals c $3); let f = $5 c in {f with locals = $3 @ f.locals} } - | LPAR LOCAL bind_var VALUE_TYPE RPAR func_body /* Sugar */ + | LPAR LOCAL bind_var value_type RPAR func_body /* Sugar */ { fun c -> ignore (bind_local c $3); let f = $6 c in {f with locals = $4 :: f.locals} } @@ -544,7 +565,7 @@ table_fields : | inline_export table_fields /* Sugar */ { fun c x at -> let tabs, elems, ims, exs = $2 c x at in tabs, elems, ims, $1 (TableExport x) c :: exs } - | elem_type LPAR ELEM var_list RPAR /* Sugar */ + | ref_type LPAR ELEM var_list RPAR /* Sugar */ { fun c x at -> let init = $4 c func in let size = Int32.of_int (List.length init) in [{ttype = TableType ({min = size; max = Some size}, $1)} @@ at], @@ -768,6 +789,8 @@ assertion : | LPAR ASSERT_RETURN action const_list RPAR { AssertReturn ($3, $4) @@ at () } | LPAR ASSERT_RETURN_CANONICAL_NAN action RPAR { AssertReturnCanonicalNaN $3 @@ at () } | LPAR ASSERT_RETURN_ARITHMETIC_NAN action RPAR { AssertReturnArithmeticNaN $3 @@ at () } + | LPAR ASSERT_RETURN_REF action RPAR { AssertReturnRef $3 @@ at () } + | LPAR ASSERT_RETURN_FUNC action RPAR { AssertReturnFunc $3 @@ at () } | LPAR ASSERT_TRAP action STRING RPAR { AssertTrap ($3, $4) @@ at () } | LPAR ASSERT_EXHAUSTION action STRING RPAR { AssertExhaustion ($3, $4) @@ at () } @@ -789,7 +812,9 @@ meta : | LPAR OUTPUT script_var_opt RPAR { Output ($3, None) @@ at () } const : - | LPAR CONST literal RPAR { snd (literal $2 $3) @@ ati 3 } + | LPAR CONST literal RPAR { Values.Num (snd (literal $2 $3)) @@ at () } + | LPAR REF_NULL RPAR { Values.Ref Values.NullRef @@ at () } + | LPAR REF_HOST NAT RPAR { Values.Ref (HostRef (nat32 $3 (ati 3))) @@ at () } const_list : | /* empty */ { [] } diff --git a/interpreter/util/lib.ml b/interpreter/util/lib.ml index 1be774ba1d..eac639d9c9 100644 --- a/interpreter/util/lib.ml +++ b/interpreter/util/lib.ml @@ -168,6 +168,11 @@ struct | Some y -> y | None -> x + let force o = + match o with + | Some y -> y + | None -> raise (Invalid_argument "Option.force") + let map f = function | Some x -> Some (f x) | None -> None diff --git a/interpreter/util/lib.mli b/interpreter/util/lib.mli index 5c3b80157e..2789ad5174 100644 --- a/interpreter/util/lib.mli +++ b/interpreter/util/lib.mli @@ -54,6 +54,7 @@ end module Option : sig val get : 'a option -> 'a -> 'a + val force : 'a option -> 'a (* raises Invalid_argument *) val map : ('a -> 'b) -> 'a option -> 'b option val app : ('a -> unit) -> 'a option -> unit end diff --git a/interpreter/valid/valid.ml b/interpreter/valid/valid.ml index 3bdb5e2823..e0ff3e888c 100644 --- a/interpreter/valid/valid.ml +++ b/interpreter/valid/valid.ml @@ -69,18 +69,29 @@ let string_of_infer_type t = let string_of_infer_types ts = "[" ^ String.concat " " (List.map string_of_infer_type ts) ^ "]" -let eq_ty t1 t2 = (t1 = t2 || t1 = None || t2 = None) +let match_type t1 t2 = + match t1, t2 with + | Some t1, Some t2 -> match_value_type t1 t2 + | _, _ -> true + +let join_type t1 t2 = + match t1, t2 with + | _, None -> t1 + | None, _ -> t2 + | Some t1, Some t2 -> join_value_type t1 t2 + let check_stack ts1 ts2 at = - require (List.length ts1 = List.length ts2 && List.for_all2 eq_ty ts1 ts2) at - ("type mismatch: operator requires " ^ string_of_infer_types ts1 ^ - " but stack has " ^ string_of_infer_types ts2) + require + (List.length ts1 = List.length ts2 && List.for_all2 match_type ts1 ts2) at + ("type mismatch: operator requires " ^ string_of_infer_types ts2 ^ + " but stack has " ^ string_of_infer_types ts1) let pop (ell1, ts1) (ell2, ts2) at = let n1 = List.length ts1 in let n2 = List.length ts2 in let n = min n1 n2 in let n3 = if ell2 = Ellipses then (n1 - n) else 0 in - check_stack ts1 (Lib.List.make n3 None @ Lib.List.drop (n2 - n) ts2) at; + check_stack (Lib.List.make n3 None @ Lib.List.drop (n2 - n) ts2) ts1 at; (ell2, if ell1 = Ellipses then [] else Lib.List.take (n2 - n) ts2) let push (ell1, ts1) (ell2, ts2) = @@ -94,11 +105,11 @@ let peek i (ell, ts) = (* Type Synthesis *) -let type_value = Values.type_of -let type_unop = Values.type_of -let type_binop = Values.type_of -let type_testop = Values.type_of -let type_relop = Values.type_of +let type_num = Values.type_of_num +let type_unop = Values.type_of_num +let type_binop = Values.type_of_num +let type_testop = Values.type_of_num +let type_relop = Values.type_of_num let type_cvtop at = function | Values.I32 cvtop -> @@ -196,18 +207,22 @@ let rec check_instr (c : context) (e : instr) (s : infer_stack_type) : op_type = check_arity (List.length ts) e.at; check_block {c with labels = ts :: c.labels} es1 ts e.at; check_block {c with labels = ts :: c.labels} es2 ts e.at; - [I32Type] --> ts + [NumType I32Type] --> ts | Br x -> label c x -->... [] | BrIf x -> - (label c x @ [I32Type]) --> label c x + (label c x @ [NumType I32Type]) --> label c x | BrTable (xs, x) -> - let ts = label c x in + let ts = + List.fold_left (fun t1 t2 -> Lib.Option.get (meet_stack_type t1 t2) t1) + (label c x) (List.map (label c) xs) + in + check_stack (known ts) (known (label c x)) x.at; List.iter (fun x' -> check_stack (known ts) (known (label c x')) x'.at) xs; - (label c x @ [I32Type]) -->... [] + (ts @ [NumType I32Type]) -->... [] | Return -> c.results -->... [] @@ -216,17 +231,22 @@ let rec check_instr (c : context) (e : instr) (s : infer_stack_type) : op_type = let FuncType (ins, out) = func c x in ins --> out - | CallIndirect x -> - ignore (table c (0l @@ e.at)); - let FuncType (ins, out) = type_ c x in - (ins @ [I32Type]) --> out + | CallIndirect (x, y) -> + let TableType (lim, t) = table c x in + let FuncType (ins, out) = type_ c y in + require (match_ref_type t AnyFuncType) x.at + ("type mismatch: operator requires table of functions, " ^ + "but table has " ^ string_of_ref_type t); + (ins @ [NumType I32Type]) --> out | Drop -> [peek 0 s] -~> [] | Select -> - let t = peek 1 s in - [t; t; Some I32Type] -~> [t] + let t1 = peek 1 s in + let t2 = peek 0 s in + let t = join_type t1 t2 in + [t; t; Some (NumType I32Type)] -~> [t] | GetLocal x -> [] --> [local c x] @@ -246,45 +266,62 @@ let rec check_instr (c : context) (e : instr) (s : infer_stack_type) : op_type = require (mut = Mutable) x.at "global is immutable"; [t] --> [] + | GetTable x -> + let TableType (lim, t) = table c x in + [NumType I32Type] --> [RefType t] + + | SetTable x -> + let TableType (lim, t) = table c x in + [NumType I32Type; RefType t] --> [] + | Load memop -> check_memop c memop (Lib.Option.map fst) e.at; - [I32Type] --> [memop.ty] + [NumType I32Type] --> [NumType memop.ty] | Store memop -> check_memop c memop (fun sz -> sz) e.at; - [I32Type; memop.ty] --> [] + [NumType I32Type; NumType memop.ty] --> [] | CurrentMemory -> ignore (memory c (0l @@ e.at)); - [] --> [I32Type] + [] --> [NumType I32Type] | GrowMemory -> ignore (memory c (0l @@ e.at)); - [I32Type] --> [I32Type] + [NumType I32Type] --> [NumType I32Type] + + | Null -> + [] --> [RefType NullRefType] + + | IsNull -> + [RefType AnyRefType] --> [NumType I32Type] + + | Same -> + [RefType AnyEqRefType; RefType AnyEqRefType] --> [NumType I32Type] | Const v -> - let t = type_value v.it in + let t = NumType (type_num v.it) in [] --> [t] | Test testop -> - let t = type_testop testop in - [t] --> [I32Type] + let t = NumType (type_testop testop) in + [t] --> [NumType I32Type] | Compare relop -> - let t = type_relop relop in - [t; t] --> [I32Type] + let t = NumType (type_relop relop) in + [t; t] --> [NumType I32Type] | Unary unop -> - let t = type_unop unop in + let t = NumType (type_unop unop) in [t] --> [t] | Binary binop -> - let t = type_binop binop in + let t = NumType (type_binop binop) in [t; t] --> [t] | Convert cvtop -> let t1, t2 = type_cvtop e.at cvtop in - [t1] --> [t2] + [NumType t1] --> [NumType t2] and check_seq (c : context) (es : instr list) : infer_stack_type = match es with @@ -314,9 +351,17 @@ let check_limits {min; max} at = require (I32.le_u min max) at "size minimum must not be greater than maximum" -let check_value_type (t : value_type) at = +let check_num_type (t : num_type) at = + () + +let check_ref_type (t : ref_type) at = () +let check_value_type (t : value_type) at = + match t with + | NumType t' -> check_num_type t' at + | RefType t' -> check_ref_type t' at + let check_func_type (ft : func_type) at = let FuncType (ins, out) = ft in List.iter (fun t -> check_value_type t at) ins; @@ -324,8 +369,9 @@ let check_func_type (ft : func_type) at = check_arity (List.length out) at let check_table_type (tt : table_type) at = - let TableType (lim, _) = tt in - check_limits lim at + let TableType (lim, t) = tt in + check_limits lim at; + check_ref_type t at let check_memory_size (sz : I32.t) at = require (I32.le_u sz 65536l) at @@ -368,6 +414,7 @@ let check_func (c : context) (f : func) = let is_const (c : context) (e : instr) = match e.it with + | Null | Const _ -> true | GetGlobal x -> let GlobalType (_, mut) = global c x in mut = Immutable | _ -> false @@ -390,13 +437,13 @@ let check_memory (c : context) (mem : memory) = let check_elem (c : context) (seg : table_segment) = let {index; offset; init} = seg.it in - check_const c offset I32Type; + check_const c offset (NumType I32Type); ignore (table c index); ignore (List.map (func c) init) let check_data (c : context) (seg : memory_segment) = let {index; offset; init} = seg.it in - check_const c offset I32Type; + check_const c offset (NumType I32Type); ignore (memory c index) let check_global (c : context) (glob : global) = @@ -475,7 +522,5 @@ let check_module (m : module_) = List.iter (check_func c) funcs; check_start c start; ignore (List.fold_left (check_export c) NameSet.empty exports); - require (List.length c.tables <= 1) m.at - "multiple tables are not allowed (yet)"; require (List.length c.memories <= 1) m.at "multiple memories are not allowed (yet)" diff --git a/test/core/binary.wast b/test/core/binary.wast index 8cfeed46f7..15f51bebe9 100644 --- a/test/core/binary.wast +++ b/test/core/binary.wast @@ -43,25 +43,6 @@ (assert_malformed (module binary "\00asm\00\00\01\00") "unknown binary version") (assert_malformed (module binary "\00asm\00\00\00\01") "unknown binary version") -;; call_indirect reserved byte equal to zero. -(assert_malformed - (module binary - "\00asm" "\01\00\00\00" - "\01\04\01\60\00\00" ;; Type section - "\03\02\01\00" ;; Function section - "\04\04\01\70\00\00" ;; Table section - "\0a\09\01" ;; Code section - - ;; function 0 - "\07\00" - "\41\00" ;; i32.const 0 - "\11\00" ;; call_indirect (type 0) - "\01" ;; call_indirect reserved byte is not equal to zero! - "\0b" ;; end - ) - "zero flag expected" -) - ;; grow_memory reserved byte equal to zero. (assert_malformed (module binary diff --git a/test/core/br_table.wast b/test/core/br_table.wast index 9860892392..086c3c32ee 100644 --- a/test/core/br_table.wast +++ b/test/core/br_table.wast @@ -1228,6 +1228,43 @@ (i32.const 3) ) ) + + (func (export "meet-anyref") (param i32) (param anyref) (result anyref) + (block $l1 (result anyref) + (block $l2 (result anyref) + (br_table $l1 $l2 $l1 (get_local 1) (get_local 0)) + ) + ) + ) + + (func (export "meet-anyeqref") (param i32) (param anyeqref) (result anyref) + (block $l1 (result anyref) + (block $l2 (result anyeqref) + (br_table $l1 $l2 $l1 (get_local 1) (get_local 0)) + ) + ) + ) + + (func (export "meet-anyfunc") (param i32) (result anyref) + (block $l1 (result anyref) + (block $l2 (result anyfunc) + (br_table $l2 $l1 $l2 (get_table 0 (i32.const 0)) (get_local 0)) + ) + ) + ) + + (func (export "meet-nullref") (param i32) (result anyref) + (block $l1 (result anyref) + (block $l2 (result anyeqref) + (drop + (block $l3 (result anyfunc) + (br_table $l1 $l2 $l3 (ref.null) (get_local 0)) + ) + ) + (ref.null) + ) + ) + ) ) (assert_return (invoke "type-i32")) @@ -1409,6 +1446,22 @@ (assert_return (invoke "nested-br_table-loop-block" (i32.const 1)) (i32.const 3)) +(assert_return (invoke "meet-anyref" (i32.const 0) (ref.host 1)) (ref.host 1)) +(assert_return (invoke "meet-anyref" (i32.const 1) (ref.host 1)) (ref.host 1)) +(assert_return (invoke "meet-anyref" (i32.const 2) (ref.host 1)) (ref.host 1)) + +(assert_return (invoke "meet-anyeqref" (i32.const 0) (ref.host 1)) (ref.host 1)) +(assert_return (invoke "meet-anyeqref" (i32.const 1) (ref.host 1)) (ref.host 1)) +(assert_return (invoke "meet-anyeqref" (i32.const 2) (ref.host 1)) (ref.host 1)) + +(assert_return_func (invoke "meet-anyfunc" (i32.const 0))) +(assert_return_func (invoke "meet-anyfunc" (i32.const 1))) +(assert_return_func (invoke "meet-anyfunc" (i32.const 2))) + +(assert_return (invoke "meet-nullref" (i32.const 0)) (ref.null)) +(assert_return (invoke "meet-nullref" (i32.const 1)) (ref.null)) +(assert_return (invoke "meet-nullref" (i32.const 2)) (ref.null)) + (assert_invalid (module (func $type-arg-void-vs-num (result i32) (block (br_table 0 (i32.const 1)) (i32.const 1)) @@ -1475,6 +1528,20 @@ "type mismatch" ) +(assert_invalid + (module (func $meet-bottom (param i32) (result anyref) + (block $l1 (result anyref) + (drop + (block $l2 (result i32) + (br_table $l2 $l1 $l2 (ref.null) (get_local 0)) + ) + ) + (ref.null) + ) + )) + "type mismatch" +) + (assert_invalid (module (func $unbound-label (block (br_table 2 1 (i32.const 1))) diff --git a/test/core/exports.wast b/test/core/exports.wast index 6841aa873e..0f4e35577d 100644 --- a/test/core/exports.wast +++ b/test/core/exports.wast @@ -104,8 +104,7 @@ (module (table 0 anyfunc) (export "a" (table 0))) (module (table 0 anyfunc) (export "a" (table 0)) (export "b" (table 0))) -;; No multiple tables yet. -;; (module (table 0 anyfunc) (table 0 anyfunc) (export "a" (table 0)) (export "b" (table 1))) +(module (table 0 anyfunc) (table 0 anyfunc) (export "a" (table 0)) (export "b" (table 1))) (module (table (export "a") 0 anyfunc)) (module (table (export "a") 0 1 anyfunc)) @@ -130,11 +129,10 @@ (module (table 0 anyfunc) (export "a" (table 0)) (export "a" (table 0))) "duplicate export name" ) -;; No multiple tables yet. -;; (assert_invalid -;; (module (table 0 anyfunc) (table 0 anyfunc) (export "a" (table 0)) (export "a" (table 1))) -;; "duplicate export name" -;; ) +(assert_invalid + (module (table 0 anyfunc) (table 0 anyfunc) (export "a" (table 0)) (export "a" (table 1))) + "duplicate export name" +) (assert_invalid (module (table 0 anyfunc) (func) (export "a" (table 0)) (export "a" (func 0))) "duplicate export name" diff --git a/test/core/get_table.wast b/test/core/get_table.wast new file mode 100644 index 0000000000..6b7e6750c7 --- /dev/null +++ b/test/core/get_table.wast @@ -0,0 +1,45 @@ +(module + (table $t1 2 eqref) + (table $t2 2 anyref) + (table $t3 3 anyfunc) (elem $t3 (i32.const 1) $dummy) + (func $dummy) + + (func (export "init") (param $r eqref) + (set_table $t1 (i32.const 1) (get_local $r)) + (set_table $t2 (i32.const 1) (get_local $r)) + (set_table $t3 (i32.const 2) (get_table $t3 (i32.const 1))) + ) + + (func (export "get-eqref") (param $i i32) (result eqref) + (get_table $t1 (get_local $i)) + ) + (func (export "get-anyref") (param $i i32) (result anyref) + (get_table $t2 (get_local $i)) + ) + (func $f3 (export "get-anyfunc") (param $i i32) (result anyfunc) + (get_table $t3 (get_local $i)) + ) + + (func (export "isnull-anyfunc") (param $i i32) (result i32) + (ref.isnull (call $f3 (get_local $i))) + ) +) + +(invoke "init" (ref.host 1)) + +(assert_return (invoke "get-eqref" (i32.const 0)) (ref.null)) +(assert_return (invoke "get-eqref" (i32.const 1)) (ref.host 1)) + +(assert_return (invoke "get-anyref" (i32.const 0)) (ref.null)) +(assert_return (invoke "get-anyref" (i32.const 1)) (ref.host 1)) + +(assert_return (invoke "get-anyfunc" (i32.const 0)) (ref.null)) +(assert_return (invoke "isnull-anyfunc" (i32.const 1)) (i32.const 0)) +(assert_return (invoke "isnull-anyfunc" (i32.const 2)) (i32.const 0)) + +(assert_trap (invoke "get-eqref" (i32.const 2)) "out of bounds") +(assert_trap (invoke "get-anyref" (i32.const 2)) "out of bounds") +(assert_trap (invoke "get-anyfunc" (i32.const 3)) "out of bounds") +(assert_trap (invoke "get-eqref" (i32.const -1)) "out of bounds") +(assert_trap (invoke "get-anyref" (i32.const -1)) "out of bounds") +(assert_trap (invoke "get-anyfunc" (i32.const -1)) "out of bounds") diff --git a/test/core/globals.wast b/test/core/globals.wast index c4edfed3e6..5ce11544fb 100644 --- a/test/core/globals.wast +++ b/test/core/globals.wast @@ -11,12 +11,19 @@ (global (;6;) (mut f64) (f64.const -14)) (global $y (mut i64) (i64.const -15)) + (global $r anyref (ref.null)) + (global anyfunc (ref.null)) + (global $z (mut anyeqref) (ref.null)) + (func (export "get-a") (result i32) (get_global $a)) (func (export "get-b") (result i64) (get_global $b)) + (func (export "get-r") (result anyref) (get_global $r)) (func (export "get-x") (result i32) (get_global $x)) (func (export "get-y") (result i64) (get_global $y)) + (func (export "get-z") (result anyeqref) (get_global $z)) (func (export "set-x") (param i32) (set_global $x (get_local 0))) (func (export "set-y") (param i64) (set_global $y (get_local 0))) + (func (export "set-z") (param anyeqref) (set_global $z (get_local 0))) (func (export "get-1") (result f32) (get_global 1)) (func (export "get-2") (result f64) (get_global 2)) @@ -28,8 +35,10 @@ (assert_return (invoke "get-a") (i32.const -2)) (assert_return (invoke "get-b") (i64.const -5)) +(assert_return (invoke "get-r") (ref.null)) (assert_return (invoke "get-x") (i32.const -12)) (assert_return (invoke "get-y") (i64.const -15)) +(assert_return (invoke "get-z") (ref.null)) (assert_return (invoke "get-1") (f32.const -3)) (assert_return (invoke "get-2") (f64.const -4)) @@ -38,11 +47,13 @@ (assert_return (invoke "set-x" (i32.const 6))) (assert_return (invoke "set-y" (i64.const 7))) +(assert_return (invoke "set-z" (ref.host 33))) (assert_return (invoke "set-5" (f32.const 8))) (assert_return (invoke "set-6" (f64.const 9))) (assert_return (invoke "get-x") (i32.const 6)) (assert_return (invoke "get-y") (i64.const 7)) +(assert_return (invoke "get-z") (ref.host 33)) (assert_return (invoke "get-5") (f32.const 8)) (assert_return (invoke "get-6") (f64.const 9)) @@ -111,6 +122,11 @@ "type mismatch" ) +(assert_invalid + (module (global (import "" "") anyref) (global anyeqref (get_global 0))) + "type mismatch" +) + (assert_invalid (module (global i32 (get_global 0))) "unknown global" diff --git a/test/core/imports.wast b/test/core/imports.wast index 7c17f805bc..37033e90de 100644 --- a/test/core/imports.wast +++ b/test/core/imports.wast @@ -11,7 +11,7 @@ (global (export "global-i32") i32 (i32.const 55)) (global (export "global-f32") f32 (f32.const 44)) (table (export "table-10-inf") 10 anyfunc) - ;; (table (export "table-10-20") 10 20 anyfunc) + (table (export "table-10-20") 10 20 anyfunc) (memory (export "memory-2-inf") 2) ;; (memory (export "memory-2-4") 2 4) ) @@ -298,22 +298,18 @@ (assert_trap (invoke "call" (i32.const 100)) "undefined element") -(assert_invalid - (module (import "" "" (table 10 anyfunc)) (import "" "" (table 10 anyfunc))) - "multiple tables" -) -(assert_invalid - (module (import "" "" (table 10 anyfunc)) (table 10 anyfunc)) - "multiple tables" -) -(assert_invalid - (module (table 10 anyfunc) (table 10 anyfunc)) - "multiple tables" -) - (module (import "test" "table-10-inf" (table 10 anyfunc))) (module (import "test" "table-10-inf" (table 5 anyfunc))) (module (import "test" "table-10-inf" (table 0 anyfunc))) +(module (import "test" "table-10-20" (table 10 anyfunc))) +(module (import "test" "table-10-20" (table 5 anyfunc))) +(module (import "test" "table-10-20" (table 0 anyfunc))) +(module (import "test" "table-10-20" (table 10 20 anyfunc))) +(module (import "test" "table-10-20" (table 5 20 anyfunc))) +(module (import "test" "table-10-20" (table 0 20 anyfunc))) +(module (import "test" "table-10-20" (table 10 25 anyfunc))) +(module (import "test" "table-10-20" (table 5 25 anyfunc))) +(module (import "test" "table-10-20" (table 0 25 anyfunc))) (module (import "spectest" "table" (table 10 anyfunc))) (module (import "spectest" "table" (table 5 anyfunc))) (module (import "spectest" "table" (table 0 anyfunc))) @@ -340,6 +336,14 @@ (module (import "test" "table-10-inf" (table 10 20 anyfunc))) "incompatible import type" ) +(assert_unlinkable + (module (import "test" "table-10-20" (table 12 20 anyfunc))) + "incompatible import type" +) +(assert_unlinkable + (module (import "test" "table-10-20" (table 10 18 anyfunc))) + "incompatible import type" +) (assert_unlinkable (module (import "spectest" "table" (table 12 anyfunc))) "incompatible import type" diff --git a/test/core/linking.wast b/test/core/linking.wast index 898d5a215f..5f47ce677f 100644 --- a/test/core/linking.wast +++ b/test/core/linking.wast @@ -58,6 +58,23 @@ (assert_return (invoke $Ng "Mg.get") (i32.const 42)) (assert_return (invoke $Ng "get") (i32.const 43)) +(module $Mref-ex + (global (export "g-const") anyeqref (ref.null)) + ;; Mutable globals cannot be exported yet + ;; (global (export "g-var") (mut anyeqref) (ref.null)) +) +(register "Mref-ex" $Mref-ex) + +(module $Mref-im + (global (import "Mref-ex" "g-const") anyref) +) + +;; Mutable globals cannot be imported yet +;;(assert_unlinkable +;; (module (global (import "Mref-ex" "g-var") (mut anyref))) +;; "type mismatch" +;;) + ;; Tables diff --git a/test/core/ref_eq.wast b/test/core/ref_eq.wast new file mode 100644 index 0000000000..c17458b29e --- /dev/null +++ b/test/core/ref_eq.wast @@ -0,0 +1,50 @@ +(module + (func $eq (export "eq") (param $x eqref) (param $y eqref) (result i32) + (ref.eq (get_local $x) (get_local $y)) + ) + + (table $t 2 eqref) + + (func (export "init") (param $r eqref) + (set_table $t (i32.const 1) (get_local $r)) + ) + + (func (export "eq-elem") (param $i i32) (param $x eqref) (result i32) + (call $eq (get_table $t (get_local $i)) (get_local $x)) + ) +) + +(assert_return (invoke "eq" (ref.null) (ref.null)) (i32.const 1)) +(assert_return (invoke "eq" (ref.host 1) (ref.host 1)) (i32.const 1)) + +(assert_return (invoke "eq" (ref.null) (ref.host 0)) (i32.const 0)) +(assert_return (invoke "eq" (ref.host 0) (ref.null)) (i32.const 0)) +(assert_return (invoke "eq" (ref.host 1) (ref.host 2)) (i32.const 0)) + +(invoke "init" (ref.host 0)) + +(assert_return (invoke "eq-elem" (i32.const 0) (ref.null)) (i32.const 1)) +(assert_return (invoke "eq-elem" (i32.const 1) (ref.host 0)) (i32.const 1)) + +(assert_return (invoke "eq-elem" (i32.const 0) (ref.host 0)) (i32.const 0)) +(assert_return (invoke "eq-elem" (i32.const 1) (ref.null)) (i32.const 0)) +(assert_return (invoke "eq-elem" (i32.const 1) (ref.host 1)) (i32.const 0)) + + +(assert_invalid + (module + (func (param $x anyref) (param $y eqref) (result i32) + (ref.eq (get_local $x) (get_local $y)) + ) + ) + "type mismatch" +) + +(assert_invalid + (module + (func (param $x anyfunc) (param $y eqref) (result i32) + (ref.eq (get_local $x) (get_local $y)) + ) + ) + "type mismatch" +) diff --git a/test/core/ref_isnull.wast b/test/core/ref_isnull.wast new file mode 100644 index 0000000000..89b840983e --- /dev/null +++ b/test/core/ref_isnull.wast @@ -0,0 +1,64 @@ +(module + (func $f1 (export "eqref") (param $x eqref) (result i32) + (ref.isnull (get_local $x)) + ) + (func $f2 (export "anyref") (param $x anyref) (result i32) + (ref.isnull (get_local $x)) + ) + (func $f3 (export "anyfunc") (param $x anyfunc) (result i32) + (ref.isnull (get_local $x)) + ) + + (table $t1 2 eqref) + (table $t2 2 anyref) + (table $t3 2 anyfunc) (elem $t3 (i32.const 1) $dummy) + (func $dummy) + + (func (export "init") (param $r eqref) + (set_table $t1 (i32.const 1) (get_local $r)) + (set_table $t2 (i32.const 1) (get_local $r)) + ) + (func (export "deinit") + (set_table $t1 (i32.const 1) (ref.null)) + (set_table $t2 (i32.const 1) (ref.null)) + (set_table $t3 (i32.const 1) (ref.null)) + ) + + (func (export "eqref-elem") (param $x i32) (result i32) + (call $f1 (get_table $t1 (get_local $x))) + ) + (func (export "anyref-elem") (param $x i32) (result i32) + (call $f2 (get_table $t2 (get_local $x))) + ) + (func (export "anyfunc-elem") (param $x i32) (result i32) + (call $f3 (get_table $t3 (get_local $x))) + ) +) + +(assert_return (invoke "eqref" (ref.null)) (i32.const 1)) +(assert_return (invoke "anyref" (ref.null)) (i32.const 1)) +(assert_return (invoke "anyfunc" (ref.null)) (i32.const 1)) + +(assert_return (invoke "eqref" (ref.host 1)) (i32.const 0)) +(assert_return (invoke "anyref" (ref.host 1)) (i32.const 0)) +(assert_return (invoke "anyfunc" (ref.host 1)) (i32.const 0)) + +(invoke "init" (ref.host 0)) + +(assert_return (invoke "eqref-elem" (i32.const 0)) (i32.const 1)) +(assert_return (invoke "anyref-elem" (i32.const 0)) (i32.const 1)) +(assert_return (invoke "anyfunc-elem" (i32.const 0)) (i32.const 1)) + +(assert_return (invoke "eqref-elem" (i32.const 1)) (i32.const 0)) +(assert_return (invoke "anyref-elem" (i32.const 1)) (i32.const 0)) +(assert_return (invoke "anyfunc-elem" (i32.const 1)) (i32.const 0)) + +(invoke "deinit") + +(assert_return (invoke "eqref-elem" (i32.const 0)) (i32.const 1)) +(assert_return (invoke "anyref-elem" (i32.const 0)) (i32.const 1)) +(assert_return (invoke "anyfunc-elem" (i32.const 0)) (i32.const 1)) + +(assert_return (invoke "eqref-elem" (i32.const 1)) (i32.const 1)) +(assert_return (invoke "anyref-elem" (i32.const 1)) (i32.const 1)) +(assert_return (invoke "anyfunc-elem" (i32.const 1)) (i32.const 1)) diff --git a/test/core/ref_null.wast b/test/core/ref_null.wast new file mode 100644 index 0000000000..a627b31ed4 --- /dev/null +++ b/test/core/ref_null.wast @@ -0,0 +1,9 @@ +(module + (func (export "eqref") (result eqref) (ref.null)) + (func (export "anyref") (result anyref) (ref.null)) + (func (export "anyfunc") (result anyfunc) (ref.null)) +) + +(assert_return (invoke "eqref") (ref.null)) +(assert_return (invoke "anyref") (ref.null)) +(assert_return (invoke "anyfunc") (ref.null)) diff --git a/test/core/select.wast b/test/core/select.wast index 4dfa456121..7d9a4ac0ec 100644 --- a/test/core/select.wast +++ b/test/core/select.wast @@ -1,4 +1,8 @@ (module + ;; Auxiliary + (func $dummy) + (table $tab anyfunc (elem $dummy)) + (func (export "select_i32") (param $lhs i32) (param $rhs i32) (param $cond i32) (result i32) (select (get_local $lhs) (get_local $rhs) (get_local $cond))) @@ -26,6 +30,22 @@ (unreachable) (f32.const 0) (i32.const 0) (select) (unreachable) ) + + (func (export "join-nullref") (param i32) (result anyref) + (select (ref.null) (ref.null) (get_local 0)) + ) + + (func (export "join-anyeqref") (param i32) (param anyeqref) (result anyref) + (select (get_local 1) (ref.null) (get_local 0)) + ) + + (func (export "join-anyfunc") (param i32) (result anyref) + (select (get_table $tab (i32.const 0)) (ref.null) (get_local 0)) + ) + + (func (export "join-anyref") (param i32) (param anyeqref) (result anyref) + (select (get_table $tab (i32.const 0)) (get_local 1) (get_local 0)) + ) ) (assert_return (invoke "select_i32" (i32.const 1) (i32.const 2) (i32.const 1)) (i32.const 1)) @@ -56,6 +76,18 @@ (assert_return (invoke "select_f64" (f64.const 2) (f64.const nan) (i32.const 0)) (f64.const nan)) (assert_return (invoke "select_f64" (f64.const 2) (f64.const nan:0x20304) (i32.const 0)) (f64.const nan:0x20304)) +(assert_return (invoke "join-nullref" (i32.const 1)) (ref.null)) +(assert_return (invoke "join-nullref" (i32.const 0)) (ref.null)) + +(assert_return (invoke "join-anyeqref" (i32.const 1) (ref.host 1)) (ref.host 1)) +(assert_return (invoke "join-anyeqref" (i32.const 0) (ref.host 1)) (ref.null)) + +(assert_return_func (invoke "join-anyfunc" (i32.const 1))) +(assert_return (invoke "join-anyfunc" (i32.const 0)) (ref.null)) + +(assert_return_func (invoke "join-anyref" (i32.const 1) (ref.host 1))) +(assert_return (invoke "join-anyref" (i32.const 0) (ref.host 1)) (ref.host 1)) + (assert_trap (invoke "select_trap_l" (i32.const 1)) "unreachable executed") (assert_trap (invoke "select_trap_l" (i32.const 0)) "unreachable executed") (assert_trap (invoke "select_trap_r" (i32.const 1)) "unreachable executed") diff --git a/test/core/set_table.wast b/test/core/set_table.wast new file mode 100644 index 0000000000..0a6747bc05 --- /dev/null +++ b/test/core/set_table.wast @@ -0,0 +1,65 @@ +(module + (table $t1 1 eqref) + (table $t2 1 anyref) + (table $t3 2 anyfunc) (elem $t3 (i32.const 1) $dummy) + (func $dummy) + + (func (export "get-eqref") (param $i i32) (result eqref) + (get_table $t1 (get_local $i)) + ) + (func (export "get-anyref") (param $i i32) (result anyref) + (get_table $t2 (get_local $i)) + ) + (func $f3 (export "get-anyfunc") (param $i i32) (result anyfunc) + (get_table $t3 (get_local $i)) + ) + + (func (export "set-eqref") (param $i i32) (param $r eqref) + (set_table $t1 (get_local $i) (get_local $r)) + ) + (func (export "set-anyref") (param $i i32) (param $r anyref) + (set_table $t2 (get_local $i) (get_local $r)) + ) + (func (export "set-anyfunc") (param $i i32) (param $r anyfunc) + (set_table $t3 (get_local $i) (get_local $r)) + ) + (func (export "set-anyfunc-from") (param $i i32) (param $j i32) + (set_table $t3 (get_local $i) (get_table $t3 (get_local $j))) + ) + + (func (export "isnull-anyfunc") (param $i i32) (result i32) + (ref.isnull (call $f3 (get_local $i))) + ) +) + +(assert_return (invoke "get-eqref" (i32.const 0)) (ref.null)) +(assert_return (invoke "set-eqref" (i32.const 0) (ref.host 1))) +(assert_return (invoke "get-eqref" (i32.const 0)) (ref.host 1)) +(assert_return (invoke "set-eqref" (i32.const 0) (ref.null))) +(assert_return (invoke "get-eqref" (i32.const 0)) (ref.null)) + +(assert_return (invoke "get-anyref" (i32.const 0)) (ref.null)) +(assert_return (invoke "set-anyref" (i32.const 0) (ref.host 1))) +(assert_return (invoke "get-anyref" (i32.const 0)) (ref.host 1)) +(assert_return (invoke "set-anyref" (i32.const 0) (ref.null))) +(assert_return (invoke "get-anyref" (i32.const 0)) (ref.null)) + +(assert_return (invoke "get-anyfunc" (i32.const 0)) (ref.null)) +(assert_return (invoke "set-anyfunc-from" (i32.const 0) (i32.const 1))) +(assert_return (invoke "isnull-anyfunc" (i32.const 0)) (i32.const 0)) +(assert_return (invoke "set-anyfunc" (i32.const 0) (ref.null))) +(assert_return (invoke "get-anyfunc" (i32.const 0)) (ref.null)) + +(assert_trap (invoke "set-eqref" (i32.const 2) (ref.null)) "out of bounds") +(assert_trap (invoke "set-anyref" (i32.const 2) (ref.null)) "out of bounds") +(assert_trap (invoke "set-anyfunc" (i32.const 3) (ref.null)) "out of bounds") +(assert_trap (invoke "set-eqref" (i32.const -1) (ref.null)) "out of bounds") +(assert_trap (invoke "set-anyref" (i32.const -1) (ref.null)) "out of bounds") +(assert_trap (invoke "set-anyfunc" (i32.const -1) (ref.null)) "out of bounds") + +(assert_trap (invoke "set-eqref" (i32.const 2) (ref.host 0)) "out of bounds") +(assert_trap (invoke "set-anyref" (i32.const 2) (ref.host 0)) "out of bounds") +(assert_trap (invoke "set-anyfunc-from" (i32.const 3) (i32.const 1)) "out of bounds") +(assert_trap (invoke "set-eqref" (i32.const -1) (ref.host 0)) "out of bounds") +(assert_trap (invoke "set-anyref" (i32.const -1) (ref.host 0)) "out of bounds") +(assert_trap (invoke "set-anyfunc-from" (i32.const -1) (i32.const 1)) "out of bounds") From 1f29a8ee7af86c45769fd130c67e09ad0f9b197f Mon Sep 17 00:00:00 2001 From: Andreas Rossberg Date: Wed, 4 Apr 2018 15:43:22 +0200 Subject: [PATCH 014/199] [spec] First go at specification (#3) --- document/core/appendix/algorithm.rst | 71 ++++-- document/core/appendix/index-instructions.rst | 25 +- document/core/appendix/index-rules.rst | 9 +- document/core/appendix/index-types.rst | 18 +- document/core/binary/instructions.rst | 53 ++++- document/core/binary/types.rst | 66 ++++-- document/core/exec/instructions.rst | 221 +++++++++++++++--- document/core/exec/modules.rst | 50 ++-- document/core/exec/runtime.rst | 64 +++-- document/core/syntax/instructions.rst | 61 ++++- document/core/syntax/modules.rst | 6 +- document/core/syntax/types.rst | 94 ++++++-- document/core/text/instructions.rst | 52 ++++- document/core/text/modules.rst | 24 +- document/core/text/types.rst | 52 +++-- document/core/util/macros.def | 41 +++- document/core/valid/instructions.rst | 154 ++++++++++-- document/core/valid/modules.rst | 10 +- document/core/valid/types.rst | 102 +++++++- 19 files changed, 967 insertions(+), 206 deletions(-) diff --git a/document/core/appendix/algorithm.rst b/document/core/appendix/algorithm.rst index d11095afb0..5253a4a9c7 100644 --- a/document/core/appendix/algorithm.rst +++ b/document/core/appendix/algorithm.rst @@ -21,15 +21,49 @@ The algorithm is expressed in typed pseudo code whose semantics is intended to b Data Structures ~~~~~~~~~~~~~~~ +Types are representable as an enumeration. +In addition to the plain types from the WebAssembly validation semantics, an extended notion of operand type includes a bottom type `Unknown` that is used as the type of :ref:`polymorphic ` operands. + +A simple subtyping check can be defined on these types. +In addition, corresponding functions computing the join (least upper bound) and meet (greatest lower bound) of two types are used. +Because there is no top type, a join does not exist in all cases. +Similarly, a meet must always be defined on known value types that exclude the auxiliary bottom type `Unknown`, +hence a meet does not exist in all cases either. +A type error is encountered if a join or meet is required when it does not exist. + +.. code-block:: pseudo + + type val_type = I32 | I64 | F32 | F64 | Anyref | Anyfunc | Anyeqref | Nullref + type opd_type = val_type | Unknown + + func is_ref(t : opd_type) : bool = + return t = Anyref || t = Anyfunc || t = Anyeqref || t = Nullref + + func matches(t1 : opd_type, t2 : opd_type) : bool = + return t1 = t2 || t1 = Unknown || + (t1 = Nullref && is_ref(t2)) || (is_ref(t1) && t2 = Anyref) + + func join(t1 : opd_type, t2 : opd_type) : opd_type = + if (t1 = t2) return t1 + if (matches(t1, t2)) return t2 + if (matches(t2, t1)) return t1 + error_if(not (is_ref(t1) && is_ref(t2))) + return Anyref + + func meet(t1 : val_type, t2 : val_type) : val_type = + if (t1 = t2) return t1 + if (matches(t1, t2)) return t1 + if (matches(t2, t1)) return t2 + error_if(not (is_ref(t1) && is_ref(t2))) + return Nullref + The algorithm uses two separate stacks: the *operand stack* and the *control stack*. The former tracks the :ref:`types ` of operand values on the :ref:`stack `, the latter surrounding :ref:`structured control instructions ` and their associated :ref:`blocks `. .. code-block:: pseudo - type val_type = I32 | I64 | F32 | F64 - - type opd_stack = stack(val_type | Unknown) + type opd_stack = stack(opd_type) type ctrl_stack = stack(ctrl_frame) type ctrl_frame = { @@ -58,20 +92,17 @@ However, these variables are not manipulated directly by the main checking funct .. code-block:: pseudo - func push_opd(type : val_type | Unknown) = + func push_opd(type : opd_type) = opds.push(type) - func pop_opd() : val_type | Unknown = + func pop_opd() : opd_type = if (opds.size() = ctrls[0].height && ctrls[0].unreachable) return Unknown error_if(opds.size() = ctrls[0].height) return opds.pop() - func pop_opd(expect : val_type | Unknown) : val_type | Unknown = + func pop_opd(expect : val_type) = let actual = pop_opd() - if (actual = Unknown) return expect - if (expect = Unknown) return actual - error_if(actual =/= expect) - return actual + error_if(not matches(actual, expect)) func push_opds(types : list(val_type)) = foreach (t in types) push_opd(t) func pop_opds(types : list(val_type)) = foreach (t in reverse(types)) pop_opd(t) @@ -83,9 +114,8 @@ But first, a special case is handled where the block contains no known operands, That can occur after an unconditional branch, when the stack is typed :ref:`polymorphically `. In that case, an unknown type is returned. -A second function for popping an operand takes an expected type, which the actual operand type is checked against. -The types may differ in case one of them is Unknown. -The more specific type is returned. +A second function for popping an operand takes an expected (known) type, which the actual operand type is checked against. +The types may differ by subtyping, inlcuding the case where the actual type is unknown. Finally, there are accumulative functions for pushing or popping multiple operand types. @@ -150,14 +180,19 @@ Other instructions are checked in a similar manner. pop_opd(I32) push_opd(I32) + case (ref.eq) + pop_opd(Anyeqref) + pop_opd(Anyeqref) + push_opd(I32) + case (drop) pop_opd() case (select) pop_opd(I32) let t1 = pop_opd() - let t2 = pop_opd(t1) - push_opd(t2) + let t2 = pop_opd() + push_opd(join(t1, t2))    case (unreachable)       unreachable() @@ -193,10 +228,12 @@ Other instructions are checked in a similar manner.    case (br_table n* m)       error_if(ctrls.size() < m) + var ts = ctrls[m].label_types       foreach (n in n*) -         error_if(ctrls.size() < n || ctrls[n].label_types =/= ctrls[m].label_types) +         error_if(ctrls.size() < n) + ts := meet(ts, ctrls[n].label_types) pop_opd(I32) -       pop_opds(ctrls[m].label_types) +       pop_opds(ts)       unreachable() .. note:: diff --git a/document/core/appendix/index-instructions.rst b/document/core/appendix/index-instructions.rst index f5811e024f..d199779185 100644 --- a/document/core/appendix/index-instructions.rst +++ b/document/core/appendix/index-instructions.rst @@ -24,7 +24,7 @@ Instruction Binary Opcode Type :math:`\BRTABLE~l^\ast~l` :math:`\hex{0E}` :math:`[t_1^\ast~t^?~\I32] \to [t_2^\ast]` :ref:`validation ` :ref:`execution ` :math:`\RETURN` :math:`\hex{0F}` :math:`[t_1^\ast~t^?] \to [t_2^\ast]` :ref:`validation ` :ref:`execution ` :math:`\CALL~x` :math:`\hex{10}` :math:`[t_1^\ast] \to [t_2^\ast]` :ref:`validation ` :ref:`execution ` -:math:`\CALLINDIRECT~x` :math:`\hex{11}` :math:`[t_1^\ast~\I32] \to [t_2^\ast]` :ref:`validation ` :ref:`execution ` +:math:`\CALLINDIRECT~x~y` :math:`\hex{11}` :math:`[t_1^\ast~\I32] \to [t_2^\ast]` :ref:`validation ` :ref:`execution ` (reserved) :math:`\hex{12}` (reserved) :math:`\hex{13}` (reserved) :math:`\hex{14}` @@ -44,8 +44,8 @@ Instruction Binary Opcode Type :math:`\TEELOCAL~x` :math:`\hex{22}` :math:`[t] \to [t]` :ref:`validation ` :ref:`execution ` :math:`\GETGLOBAL~x` :math:`\hex{23}` :math:`[] \to [t]` :ref:`validation ` :ref:`execution ` :math:`\SETGLOBAL~x` :math:`\hex{24}` :math:`[t] \to []` :ref:`validation ` :ref:`execution ` -(reserved) :math:`\hex{25}` -(reserved) :math:`\hex{26}` +:math:`\GETTABLE~x` :math:`\hex{25}` :math:`[\I32] \to [t]` :ref:`validation ` :ref:`execution ` +:math:`\SETTABLE~x` :math:`\hex{26}` :math:`[\I32~t] \to []` :ref:`validation ` :ref:`execution ` (reserved) :math:`\hex{27}` :math:`\I32.\LOAD~\memarg` :math:`\hex{28}` :math:`[\I32] \to [\I32]` :ref:`validation ` :ref:`execution ` :math:`\I64.\LOAD~\memarg` :math:`\hex{29}` :math:`[\I32] \to [\I64]` :ref:`validation ` :ref:`execution ` @@ -199,5 +199,24 @@ Instruction Binary Opcode Type :math:`\I64.\REINTERPRET\K{/}\F64` :math:`\hex{BD}` :math:`[\F64] \to [\I64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` :math:`\F32.\REINTERPRET\K{/}\I32` :math:`\hex{BE}` :math:`[\I32] \to [\F32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` :math:`\F64.\REINTERPRET\K{/}\I64` :math:`\hex{BF}` :math:`[\I64] \to [\F64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +(reserved) :math:`\hex{C0}` +(reserved) :math:`\hex{C1}` +(reserved) :math:`\hex{C2}` +(reserved) :math:`\hex{C3}` +(reserved) :math:`\hex{C4}` +(reserved) :math:`\hex{C5}` +(reserved) :math:`\hex{C6}` +(reserved) :math:`\hex{C7}` +(reserved) :math:`\hex{C8}` +(reserved) :math:`\hex{C9}` +(reserved) :math:`\hex{CA}` +(reserved) :math:`\hex{CB}` +(reserved) :math:`\hex{CC}` +(reserved) :math:`\hex{CD}` +(reserved) :math:`\hex{CE}` +(reserved) :math:`\hex{CF}` +:math:`\REFNULL` :math:`\hex{D0}` :math:`[] \to [\NULLREF]` :ref:`validation ` :ref:`execution ` +:math:`\REFISNULL` :math:`\hex{D1}` :math:`[\ANYREF] \to [\I32]` :ref:`validation ` :ref:`execution ` +:math:`\REFEQ` :math:`\hex{D2}` :math:`[\ANYEQREF~\ANYEQREF] \to [\I32]` :ref:`validation ` :ref:`execution ` =================================== ================ ========================================== ======================================== =============================================================== diff --git a/document/core/appendix/index-rules.rst b/document/core/appendix/index-rules.rst index 2815480634..75ba290e0a 100644 --- a/document/core/appendix/index-rules.rst +++ b/document/core/appendix/index-rules.rst @@ -71,14 +71,15 @@ Construct Judgement =============================================== =============================================================================== -Import Matching -~~~~~~~~~~~~~~~ +Matching +~~~~~~~~ =============================================== =============================================================================== Construct Judgement =============================================== =============================================================================== -:ref:`Limits ` :math:`\vdashlimitsmatch \limits_1 \matches \limits_2` -:ref:`External type ` :math:`\vdashexterntypematch \externtype_1 \matches \externtype_2` +:ref:`Value type ` :math:`\vdashvaltypematch \valtype_1 \matchesvaltype \valtype_2` +:ref:`External type ` :math:`\vdashexterntypematch \externtype_1 \matchesexterntype \externtype_2` +:ref:`Limits ` :math:`\vdashlimitsmatch \limits_1 \matcheslimits \limits_2` =============================================== =============================================================================== diff --git a/document/core/appendix/index-types.rst b/document/core/appendix/index-types.rst index 972ae6b49a..8199229412 100644 --- a/document/core/appendix/index-types.rst +++ b/document/core/appendix/index-types.rst @@ -8,17 +8,19 @@ Index of Types Category Constructor Binary Opcode ======================================== =========================================== =============================================================================== :ref:`Type index ` :math:`x` (positive number as |Bs32| or |Bu32|) -:ref:`Value type ` |I32| :math:`\hex{7F}` (-1 as |Bs7|) -:ref:`Value type ` |I64| :math:`\hex{7E}` (-2 as |Bs7|) -:ref:`Value type ` |F32| :math:`\hex{7D}` (-3 as |Bs7|) -:ref:`Value type ` |F64| :math:`\hex{7C}` (-4 as |Bs7|) -(reserved) :math:`\hex{7C}` .. :math:`\hex{71}` -:ref:`Element type ` |ANYFUNC| :math:`\hex{70}` (-16 as |Bs7|) -(reserved) :math:`\hex{6F}` .. :math:`\hex{61}` +:ref:`Number type ` |I32| :math:`\hex{7F}` (-1 as |Bs7|) +:ref:`Number type ` |I64| :math:`\hex{7E}` (-2 as |Bs7|) +:ref:`Number type ` |F32| :math:`\hex{7D}` (-3 as |Bs7|) +:ref:`Number type ` |F64| :math:`\hex{7C}` (-4 as |Bs7|) +(reserved) :math:`\hex{7B}` .. :math:`\hex{71}` +:ref:`Reference type ` |ANYFUNC| :math:`\hex{70}` (-16 as |Bs7|) +:ref:`Reference type ` |ANYREF| :math:`\hex{6F}` (-17 as |Bs7|) +:ref:`Reference type ` |ANYEQREF| :math:`\hex{6E}` (-18 as |Bs7|) +(reserved) :math:`\hex{6D}` .. :math:`\hex{61}` :ref:`Function type ` :math:`[\valtype^\ast] \to [\valtype^\ast]` :math:`\hex{60}` (-32 as |Bs7|) (reserved) :math:`\hex{5F}` .. :math:`\hex{41}` :ref:`Result type ` :math:`\epsilon` :math:`\hex{40}` (-64 as |Bs7|) -:ref:`Table type ` :math:`\limits~\elemtype` (none) +:ref:`Table type ` :math:`\limits~\reftype` (none) :ref:`Memory type ` :math:`\limits` (none) :ref:`Global type ` :math:`\mut~\valtype` (none) ======================================== =========================================== =============================================================================== diff --git a/document/core/binary/instructions.rst b/document/core/binary/instructions.rst index faf5411de8..e83c57ac17 100644 --- a/document/core/binary/instructions.rst +++ b/document/core/binary/instructions.rst @@ -54,17 +54,39 @@ Control Instructions &\Rightarrow& \BRTABLE~l^\ast~l_N \\ &&|& \hex{0F} &\Rightarrow& \RETURN \\ &&|& \hex{10}~~x{:}\Bfuncidx &\Rightarrow& \CALL~x \\ &&|& - \hex{11}~~x{:}\Btypeidx~~\hex{00} &\Rightarrow& \CALLINDIRECT~x \\ + \hex{11}~~y{:}\Btypeidx~~x{:}\Btableidx &\Rightarrow& \CALLINDIRECT~x~y \\ \end{array} .. note:: The |ELSE| opcode :math:`\hex{05}` in the encoding of an |IF| instruction can be omitted if the following instruction sequence is empty. + +.. index:: reference instruction + pair: binary format; instruction +.. _binary-instr-ref: + +Reference Instructions +~~~~~~~~~~~~~~~~~~~~~~ + +:ref:`Reference instructions ` are represented by single byte codes. + +.. _binary-ref_null: +.. _binary-ref_isnull: +.. _binary-ref_eq: + +.. math:: + \begin{array}{llclll} + \production{instruction} & \Binstr &::=& \dots \\ &&|& + \hex{D0} &\Rightarrow& \REFNULL \\ &&|& + \hex{D1} &\Rightarrow& \REFISNULL \\ &&|& + \hex{D2} &\Rightarrow& \REFEQ \\ + \end{array} + .. note:: - In future versions of WebAssembly, the zero byte occurring in the encoding - of the |CALLINDIRECT| instruction may be used to index additional tables. + These opcode assignments are preliminary. + -.. index:: value type, polymorphism +.. index:: parametric instruction, value type, polymorphism pair: binary format; instruction .. _binary-instr-parametric: @@ -110,6 +132,29 @@ Variable Instructions \end{array} +.. index:: table instruction, table index + pair: binary format; instruction +.. _binary-instr-table: + +Table Instructions +~~~~~~~~~~~~~~~~~~ + +:ref:`Table instructions ` are represented by single byte codes. + +.. _binary-get_table: +.. _binary-set_table: + +.. math:: + \begin{array}{llclll} + \production{instruction} & \Binstr &::=& \dots \\ &&|& + \hex{25}~~x{:}\Btableidx &\Rightarrow& \GETTABLE~x \\ &&|& + \hex{26}~~x{:}\Btableidx &\Rightarrow& \SETTABLE~x \\ + \end{array} + +.. note:: + These opcode assignments are preliminary. + + .. index:: memory instruction, memory index pair: binary format; instruction .. _binary-instr-memory: diff --git a/document/core/binary/types.rst b/document/core/binary/types.rst index e5342259c9..21b4ec1bdc 100644 --- a/document/core/binary/types.rst +++ b/document/core/binary/types.rst @@ -5,27 +5,63 @@ Types ----- -.. index:: value type - pair: binary format; value type -.. _binary-valtype: +.. note:: + In future versions of WebAssembly, value types may include types denoted by :ref:`type indices `. + Thus, the binary format for types corresponds to the encodings of small negative :math:`\xref{binary/values}{binary-sint}{\sN}` values, so that they can coexist with (positive) type indices in the future. -Value Types -~~~~~~~~~~~ -:ref:`Value types ` are encoded by a single byte. +.. index:: number type + pair: binary format; number type +.. _binary-numtype: + +Number Types +~~~~~~~~~~~~ + +:ref:`Number types ` are encoded by a single byte. .. math:: \begin{array}{llclll@{\qquad\qquad}l} - \production{value type} & \Bvaltype &::=& + \production{number type} & \Bnumtype &::=& \hex{7F} &\Rightarrow& \I32 \\ &&|& \hex{7E} &\Rightarrow& \I64 \\ &&|& \hex{7D} &\Rightarrow& \F32 \\ &&|& \hex{7C} &\Rightarrow& \F64 \\ \end{array} -.. note:: - In future versions of WebAssembly, value types may include types denoted by :ref:`type indices `. - Thus, the binary format for types corresponds to the encodings of small negative :math:`\xref{binary/values}{binary-sint}{\sN}` values, so that they can coexist with (positive) type indices in the future. + +.. index:: reference type + pair: binary format; reference type +.. _binary-reftype: + +Reference Types +~~~~~~~~~~~~~~~ + +:ref:`Reference types ` are also encoded by a single byte. + +.. math:: + \begin{array}{llclll@{\qquad\qquad}l} + \production{reference type} & \Breftype &::=& + \hex{70} &\Rightarrow& \ANYFUNC \\ &&|& + \hex{6F} &\Rightarrow& \ANYREF \\ &&|& + \hex{6E} &\Rightarrow& \ANYEQREF \\ + \end{array} + + +.. index:: value type, number type, reference type + pair: binary format; value type +.. _binary-valtype: + +Value Types +~~~~~~~~~~~ + +:ref:`Value types ` are encoded with their respective encoding as a :ref:`number type ` or :ref:`reference type `. + +.. math:: + \begin{array}{llclll@{\qquad\qquad}l} + \production{value type} & \Bvaltype &::=& + t{:}\Bnumtype &\Rightarrow& t \\ &&|& + t{:}\Breftype &\Rightarrow& t \\ + \end{array} .. index:: result type, value type @@ -99,23 +135,19 @@ Memory Types \end{array} -.. index:: table type, element type, limits +.. index:: table type, reference type, limits pair: binary format; table type - pair: binary format; element type -.. _binary-elemtype: .. _binary-tabletype: Table Types ~~~~~~~~~~~ -:ref:`Table types ` are encoded with their :ref:`limits ` and a constant byte indicating their :ref:`element type `. +:ref:`Table types ` are encoded with their :ref:`limits ` and the encoding of their element :ref:`reference type `. .. math:: \begin{array}{llclll} \production{table type} & \Btabletype &::=& - \X{et}{:}\Belemtype~~\X{lim}{:}\Blimits &\Rightarrow& \X{lim}~\X{et} \\ - \production{element type} & \Belemtype &::=& - \hex{70} &\Rightarrow& \ANYFUNC \\ + \X{et}{:}\Breftype~~\X{lim}{:}\Blimits &\Rightarrow& \X{lim}~\X{et} \\ \end{array} diff --git a/document/core/exec/instructions.rst b/document/core/exec/instructions.rst index f0990ad26f..41620bd08e 100644 --- a/document/core/exec/instructions.rst +++ b/document/core/exec/instructions.rst @@ -43,7 +43,7 @@ Where the underlying operators are non-deterministic, because they may return on 1. Push the value :math:`t.\CONST~c` to the stack. .. note:: - No formal reduction rule is required for this instruction, since |CONST| instructions coincide with :ref:`values `. + No formal reduction rule is required for this instruction, since |CONST| instructions already are :ref:`values `. .. _exec-unop: @@ -174,6 +174,79 @@ Where the underlying operators are non-deterministic, because they may return on \end{array} +.. index:: reference instructions, reference + pair: execution; instruction + single: abstract syntax; instruction +.. _exec-instr-ref: + +Reference Instructions +~~~~~~~~~~~~~~~~~~~~~~ + +.. _exec-ref_null: + +:math:`\REFNULL` +................ + +1. Push the value :math:`\REFNULL` to the stack. + +.. note:: + No formal reduction rule is required for this instruction, since the |REFNULL| instruction is already a :ref:`value `. + + +.. _exec-ref_isnull: + +:math:`\REFISNULL` +.................. + +1. Assert: due to :ref:`validation `, a :ref:`reference value ` is on the top of the stack. + +2. Pop the value :math:`\val` from the stack. + +3. If :math:`\val` is |REFNULL|, then: + + a. Push the value :math:`\I32.\CONST~1` to the stack. + +4. Else: + + a. Push the value :math:`\I32.\CONST~0` to the stack. + +.. math:: + \begin{array}{lcl@{\qquad}l} + \val~\REFISNULL &\stepto& \I32.\CONST~1 + & (\iff \val = \REFNULL) \\ + \val~\REFISNULL &\stepto& \I32.\CONST~0 + & (\iff \val \neq \REFNULL) \\ + \end{array} + + +.. _exec-ref_eq: + +:math:`\REFEQ` +.............. + +1. Assert: due to :ref:`validation `, two :ref:`reference values ` are on the top of the stack. + +2. Pop the value :math:`\val_2` from the stack. + +3. Pop the value :math:`\val_1` from the stack. + +3. If :math:`\val_1` is the same as :math:`\val_2`, then: + + a. Push the value :math:`\I32.\CONST~1` to the stack. + +4. Else: + + a. Push the value :math:`\I32.\CONST~0` to the stack. + +.. math:: + \begin{array}{lcl@{\qquad}l} + \val_1~\val_2~\REFEQ &\stepto& \I32.\CONST~1 + & (\iff \val_1 = \val_2) \\ + \val_1~\val_2~\REFEQ &\stepto& \I32.\CONST~0 + & (\iff \val_1 \neq \val_2) \\ + \end{array} + + .. index:: parametric instructions, value pair: execution; instruction single: abstract syntax; instruction @@ -363,7 +436,101 @@ Variable Instructions :ref:`Validation ` ensures that the global is, in fact, marked as mutable. -.. index:: memory instruction, memory index, store, frame, address, memory address, memory instance, store, frame, value, integer, limits, value type, bit width +.. index:: table instruction, table index, store, frame, address, table address, table instance, value, integer, limits, reference, reference type + pair: execution; instruction + single: abstract syntax; instruction +.. _exec-instr-table: + +Table Instructions +~~~~~~~~~~~~~~~~~~ + +.. _exec-get_table: + +:math:`\GETTABLE~x` +................... + +1. Let :math:`F` be the :ref:`current ` :ref:`frame `. + +2. Assert: due to :ref:`validation `, :math:`F.\AMODULE.\MITABLES[x]` exists. + +3. Let :math:`a` be the :ref:`table address ` :math:`F.\AMODULE.\MITABLES[x]`. + +4. Assert: due to :ref:`validation `, :math:`S.\STABLES[a]` exists. + +5. Let :math:`\X{tab}` be the :ref:`table instance ` :math:`S.\STABLES[a]`. + +6. Assert: due to :ref:`validation `, a value of :ref:`value type ` |I32| is on the top of the stack. + +7. Pop the value :math:`\I32.\CONST~i` from the stack. + +8. If :math:`i` is not smaller than the length of :math:`\X{tab}.\TIELEM`, then: + + a. Trap. + +6. Let :math:`\val` be the value :math:`\X{tab}.\TIELEM[i]`. + +7. Push the value :math:`\val` to the stack. + +.. math:: + \begin{array}{l} + \begin{array}{lcl@{\qquad}l} + S; F; (\I32.\CONST~i)~(\GETTABLE~x) &\stepto& S; F; \val + \end{array} + \\ \qquad + (\iff S.\STABLES[F.\AMODULE.\MITABLES[x]][i] = \val) \\ + \begin{array}{lcl@{\qquad}l} + S; F; (\I32.\CONST~i)~(\GETTABLE~x) &\stepto& S; F; \TRAP + \end{array} + \\ \qquad + (\otherwise) \\ + \end{array} + + +.. _exec-set_table: + +:math:`\SETTABLE~x` +................... + +1. Let :math:`F` be the :ref:`current ` :ref:`frame `. + +2. Assert: due to :ref:`validation `, :math:`F.\AMODULE.\MITABLES[x]` exists. + +3. Let :math:`a` be the :ref:`table address ` :math:`F.\AMODULE.\MITABLES[x]`. + +4. Assert: due to :ref:`validation `, :math:`S.\STABLES[a]` exists. + +5. Let :math:`\X{tab}` be the :ref:`table instance ` :math:`S.\STABLES[a]`. + +6. Assert: due to :ref:`validation `, a :ref:`reference value ` is on the top of the stack. + +7. Pop the value :math:`\val` from the stack. + +8. Assert: due to :ref:`validation `, a value of :ref:`value type ` |I32| is on the top of the stack. + +9. Pop the value :math:`\I32.\CONST~i` from the stack. + +10. If :math:`i` is not smaller than the length of :math:`\X{tab}.\TIELEM`, then: + + a. Trap. + +11. Replace the element :math:`\X{tab}.\TIELEM[i]` with :math:`\val`. + +.. math:: + \begin{array}{l} + \begin{array}{lcl@{\qquad}l} + S; F; (\I32.\CONST~i)~\val~(\SETTABLE~x) &\stepto& S'; F; \epsilon + \end{array} + \\ \qquad + (\iff S' = S \with \STABLES[F.\AMODULE.\MITABLES[x]][i] = \val) \\ + \begin{array}{lcl@{\qquad}l} + S; F; (\I32.\CONST~i)~\val~(\SETTABLE~x) &\stepto& S; F; \TRAP + \end{array} + \\ \qquad + (\otherwise) \\ + \end{array} + + +.. index:: memory instruction, memory index, store, frame, address, memory address, memory instance, value, integer, limits, value type, bit width pair: execution; instruction single: abstract syntax; instruction .. _exec-memarg: @@ -512,7 +679,7 @@ Memory Instructions \begin{array}[t]{@{}r@{~}l@{}} (\iff & \X{ea} = i + \memarg.\OFFSET \\ \wedge & \X{ea} + |t|/8 \leq |S.\SMEMS[F.\AMODULE.\MIMEMS[0]].\MIDATA| \\ - \wedge & S' = S \with \SMEMS[F.\AMODULE.\MIMEMS[0]].\MIDATA[\X{ea} \slice |t|/8] = \bytes_t(c) + \wedge & S' = S \with \SMEMS[F.\AMODULE.\MIMEMS[0]].\MIDATA[\X{ea} \slice |t|/8] = \bytes_t(c)) \end{array} \\[1ex] \begin{array}{lcl@{\qquad}l} @@ -870,22 +1037,22 @@ Control Instructions .. _exec-call_indirect: -:math:`\CALLINDIRECT~x` -....................... +:math:`\CALLINDIRECT~x~y` +......................... 1. Let :math:`F` be the :ref:`current ` :ref:`frame `. -2. Assert: due to :ref:`validation `, :math:`F.\AMODULE.\MITABLES[0]` exists. +2. Assert: due to :ref:`validation `, :math:`F.\AMODULE.\MITABLES[x]` exists. -3. Let :math:`\X{ta}` be the :ref:`table address ` :math:`F.\AMODULE.\MITABLES[0]`. +3. Let :math:`\X{ta}` be the :ref:`table address ` :math:`F.\AMODULE.\MITABLES[x]`. 4. Assert: due to :ref:`validation `, :math:`S.\STABLES[\X{ta}]` exists. 5. Let :math:`\X{tab}` be the :ref:`table instance ` :math:`S.\STABLES[\X{ta}]`. -6. Assert: due to :ref:`validation `, :math:`F.\AMODULE.\MITYPES[x]` exists. +6. Assert: due to :ref:`validation `, :math:`F.\AMODULE.\MITYPES[y]` exists. -7. Let :math:`\X{ft}_{\F{expect}}` be the :ref:`function type ` :math:`F.\AMODULE.\MITYPES[x]`. +7. Let :math:`\X{ft}_{\F{expect}}` be the :ref:`function type ` :math:`F.\AMODULE.\MITYPES[y]`. 8. Assert: due to :ref:`validation `, a value with :ref:`value type ` |I32| is on the top of the stack. @@ -895,39 +1062,43 @@ Control Instructions a. Trap. -11. If :math:`\X{tab}.\TIELEM[i]` is uninitialized, then: +11. Let :math:`r` be the :ref:`reference ` :math:`\X{tab}.\TIELEM[i]`. + +12. If :math:`r` is |REFNULL|, then: a. Trap. -12. Let :math:`a` be the :ref:`function address ` :math:`\X{tab}.\TIELEM[i]`. +13. Assert: due to :ref:`validation of table mutation `, :math:`r` is a :ref:`function reference `. + +14. Let :math:`\REFFUNC~a` be the :ref:`function reference ` :math:`r`. -13. Assert: due to :ref:`validation `, :math:`S.\SFUNCS[a]` exists. +15. Assert: due to :ref:`validation of table mutation `, :math:`S.\SFUNCS[a]` exists. -14. Let :math:`\X{f}` be the :ref:`function instance ` :math:`S.\SFUNCS[a]`. +16. Let :math:`\X{f}` be the :ref:`function instance ` :math:`S.\SFUNCS[a]`. -15. Let :math:`\X{ft}_{\F{actual}}` be the :ref:`function type ` :math:`\X{f}.\FITYPE`. +17. Let :math:`\X{ft}_{\F{actual}}` be the :ref:`function type ` :math:`\X{f}.\FITYPE`. -16. If :math:`\X{ft}_{\F{actual}}` and :math:`\X{ft}_{\F{expect}}` differ, then: +18. If :math:`\X{ft}_{\F{actual}}` and :math:`\X{ft}_{\F{expect}}` differ, then: a. Trap. -17. :ref:`Invoke ` the function instance at address :math:`a`. +19. :ref:`Invoke ` the function instance at address :math:`a`. .. math:: ~\\[-1ex] \begin{array}{l} \begin{array}{lcl@{\qquad}l} - S; F; (\I32.\CONST~i)~(\CALLINDIRECT~x) &\stepto& S; F; (\INVOKE~a) + S; F; (\I32.\CONST~i)~(\CALLINDIRECT~x~y) &\stepto& S; F; (\INVOKE~a) \end{array} \\ \qquad \begin{array}[t]{@{}r@{~}l@{}} - (\iff & S.\STABLES[F.\AMODULE.\MITABLES[0]].\TIELEM[i] = a \\ + (\iff & S.\STABLES[F.\AMODULE.\MITABLES[x]].\TIELEM[i] = \REFFUNC~a \\ \wedge & S.\SFUNCS[a] = f \\ - \wedge & F.\AMODULE.\MITYPES[x] = f.\FITYPE) + \wedge & F.\AMODULE.\MITYPES[y] = f.\FITYPE) \end{array} \\[1ex] \begin{array}{lcl@{\qquad}l} - S; F; (\I32.\CONST~i)~(\CALLINDIRECT~x) &\stepto& S; F; \TRAP + S; F; (\I32.\CONST~i)~(\CALLINDIRECT~x~y) &\stepto& S; F; \TRAP \end{array} \\ \qquad (\otherwise) @@ -1019,13 +1190,11 @@ Invocation of :ref:`function address ` :math:`a` 8. Pop the values :math:`\val^n` from the stack. -9. Let :math:`\val_0^\ast` be the list of zero values of types :math:`t^\ast`. - -10. Let :math:`F` be the :ref:`frame ` :math:`\{ \AMODULE~f.\FIMODULE, \ALOCALS~\val^n~\val_0^\ast \}`. +9. Let :math:`F` be the :ref:`frame ` :math:`\{ \AMODULE~f.\FIMODULE, \ALOCALS~\val^n~(\default_t)^\ast \}`. -11. Push the activation of :math:`F` with arity :math:`m` to the stack. +10. Push the activation of :math:`F` with arity :math:`m` to the stack. -12. :ref:`Execute ` the instruction :math:`\BLOCK~[t_2^m]~\instr^\ast~\END`. +11. :ref:`Execute ` the instruction :math:`\BLOCK~[t_2^m]~\instr^\ast~\END`. .. math:: ~\\[-1ex] @@ -1039,7 +1208,7 @@ Invocation of :ref:`function address ` :math:`a` \wedge & f.\FITYPE = [t_1^n] \to [t_2^m] \\ \wedge & m \leq 1 \\ \wedge & f.\FICODE = \{ \FTYPE~x, \FLOCALS~t^k, \FBODY~\instr^\ast~\END \} \\ - \wedge & F = \{ \AMODULE~f.\FIMODULE, ~\ALOCALS~\val^n~(t.\CONST~0)^k \}) + \wedge & F = \{ \AMODULE~f.\FIMODULE, ~\ALOCALS~\val^n~(\default_t)^k \}) \end{array} \\ \end{array} diff --git a/document/core/exec/modules.rst b/document/core/exec/modules.rst index bc772ddcce..aa1d82be39 100644 --- a/document/core/exec/modules.rst +++ b/document/core/exec/modules.rst @@ -126,7 +126,7 @@ Limits \frac{ n_1 \geq n_2 }{ - \vdashlimitsmatch \{ \LMIN~n_1, \LMAX~m_1^? \} \matches \{ \LMIN~n_2, \LMAX~\epsilon \} + \vdashlimitsmatch \{ \LMIN~n_1, \LMAX~m_1^? \} \matcheslimits \{ \LMIN~n_2, \LMAX~\epsilon \} } \quad \frac{ @@ -134,7 +134,7 @@ Limits \qquad m_1 \leq m_2 }{ - \vdashlimitsmatch \{ \LMIN~n_1, \LMAX~m_1 \} \matches \{ \LMIN~n_2, \LMAX~m_2 \} + \vdashlimitsmatch \{ \LMIN~n_1, \LMAX~m_1 \} \matcheslimits \{ \LMIN~n_2, \LMAX~m_2 \} } @@ -154,7 +154,7 @@ An :ref:`external type ` :math:`\ETFUNC~\functype_1` matches ~\\[-1ex] \frac{ }{ - \vdashexterntypematch \ETFUNC~\functype \matches \ETFUNC~\functype + \vdashexterntypematch \ETFUNC~\functype \matchesexterntype \ETFUNC~\functype } @@ -164,17 +164,17 @@ An :ref:`external type ` :math:`\ETFUNC~\functype_1` matches Tables ...... -An :ref:`external type ` :math:`\ETTABLE~(\limits_1~\elemtype_1)` matches :math:`\ETTABLE~(\limits_2~\elemtype_2)` if and only if: +An :ref:`external type ` :math:`\ETTABLE~(\limits_1~\reftype_1)` matches :math:`\ETTABLE~(\limits_2~\reftype_2)` if and only if: * Limits :math:`\limits_1` :ref:`match ` :math:`\limits_2`. -* Both :math:`\elemtype_1` and :math:`\elemtype_2` are the same. +* Both :math:`\reftype_1` and :math:`\reftype_2` are the same. .. math:: \frac{ - \vdashlimitsmatch \limits_1 \matches \limits_2 + \vdashlimitsmatch \limits_1 \matcheslimits \limits_2 }{ - \vdashexterntypematch \ETTABLE~(\limits_1~\elemtype) \matches \ETTABLE~(\limits_2~\elemtype) + \vdashexterntypematch \ETTABLE~(\limits_1~\reftype) \matchesexterntype \ETTABLE~(\limits_2~\reftype) } @@ -190,9 +190,9 @@ An :ref:`external type ` :math:`\ETMEM~\limits_1` matches :ma .. math:: \frac{ - \vdashlimitsmatch \limits_1 \matches \limits_2 + \vdashlimitsmatch \limits_1 \matcheslimits \limits_2 }{ - \vdashexterntypematch \ETMEM~\limits_1 \matches \ETMEM~\limits_2 + \vdashexterntypematch \ETMEM~\limits_1 \matchesexterntype \ETMEM~\limits_2 } @@ -202,15 +202,23 @@ An :ref:`external type ` :math:`\ETMEM~\limits_1` matches :ma Globals ....... -An :ref:`external type ` :math:`\ETGLOBAL~\globaltype_1` matches :math:`\ETGLOBAL~\globaltype_2` if and only if: +An :ref:`external type ` :math:`\ETGLOBAL~(\mut_1~t_1)` matches :math:`\ETGLOBAL~(\mut_2~t_2)` if and only if: -* Both :math:`\globaltype_1` and :math:`\globaltype_2` are the same. +* Either both :math:`\mut_1` and :math:`\mut_2` are |MVAR| and :math:`t_1` and :math:`t_2` are the same. + +* Or both :math:`\mut_1` and :math:`\mut_2` are |MCONST| and :math:`t_1` :ref:`matches ` :math:`t_2`. .. math:: ~\\[-1ex] \frac{ }{ - \vdashexterntypematch \ETGLOBAL~\globaltype \matches \ETGLOBAL~\globaltype + \vdashexterntypematch \ETGLOBAL~(\MVAR~t) \matchesexterntype \ETGLOBAL~(\MVAR~t) + } + \qquad + \frac{ + \vdashvaltypematch t_1 \matchesvaltype t_2 + }{ + \vdashexterntypematch \ETGLOBAL~(\MCONST~t_1) \matchesexterntype \ETGLOBAL~(\MCONST~t_2) } @@ -292,11 +300,11 @@ New instances of :ref:`functions `, :ref:`tables ` to allocate. -2. Let :math:`(\{\LMIN~n, \LMAX~m^?\}~\elemtype)` be the structure of :ref:`table type ` :math:`\tabletype`. +2. Let :math:`(\{\LMIN~n, \LMAX~m^?\}~\reftype)` be the structure of :ref:`table type ` :math:`\tabletype`. 3. Let :math:`a` be the first free :ref:`table address ` in :math:`S`. -4. Let :math:`\tableinst` be the :ref:`table instance ` :math:`\{ \TIELEM~(\epsilon)^n, \TIMAX~m^? \}` with :math:`n` empty elements. +4. Let :math:`\tableinst` be the :ref:`table instance ` :math:`\{ \TIELEM~\REFNULL^n, \TIMAX~m^? \}` with :math:`n` empty elements. 5. Append :math:`\tableinst` to the |STABLES| of :math:`S`. @@ -306,9 +314,9 @@ New instances of :ref:`functions `, :ref:`tables ` 2. If :math:`\tableinst.\TIMAX` is not empty and smaller than :math:`n` added to the length of :math:`\tableinst.\TIELEM`, then fail. -3. Append :math:`n` empty elements to :math:`\tableinst.\TIELEM`. +3. Append :math:`\REFNULL^n` to :math:`\tableinst.\TIELEM`. .. math:: \begin{array}{rllll} - \growtable(\tableinst, n) &=& \tableinst \with \TIELEM = \tableinst.\TIELEM~(\epsilon)^n \\ + \growtable(\tableinst, n) &=& \tableinst \with \TIELEM = \tableinst.\TIELEM~\REFNULL^n \\ && (\iff \tableinst.\TIMAX = \epsilon \vee |\tableinst.\TIELEM| + n \leq \tableinst.\TIMAX) \\ \end{array} @@ -651,7 +659,7 @@ It is up to the :ref:`embedder ` to define how such conditions are rep ii. Let :math:`\funcaddr_{ij}` be the :ref:`function address ` :math:`\moduleinst.\MIFUNCS[\funcidx_{ij}]`. - iii. Replace :math:`\tableinst_i.\TIELEM[\X{eo}_i + j]` with :math:`\funcaddr_{ij}`. + iii. Replace :math:`\tableinst_i.\TIELEM[\X{eo}_i + j]` with :math:`\REFFUNC~\funcaddr_{ij}`. 14. For each :ref:`data segment ` :math:`\data_i` in :math:`\module.\MDATA`, do: @@ -680,7 +688,7 @@ It is up to the :ref:`embedder ` to define how such conditions are rep &(\iff & \vdashmodule \module : \externtype_{\F{im}}^n \to \externtype_{\F{ex}}^\ast \\ &\wedge& (S \vdashexternval \externval : \externtype)^n \\ - &\wedge& (\vdashexterntypematch \externtype \matches \externtype_{\F{im}})^n \\[1ex] + &\wedge& (\vdashexterntypematch \externtype \matchesexterntype \externtype_{\F{im}})^n \\[1ex] &\wedge& \module.\MGLOBALS = \global^\ast \\ &\wedge& \module.\MELEM = \elem^\ast \\ &\wedge& \module.\MDATA = \data^\ast \\ @@ -701,7 +709,7 @@ It is up to the :ref:`embedder ` to define how such conditions are rep S; F; \epsilon \\ S; F; \INITELEM~a~i~(x_0~x^\ast) &\stepto& S'; F; \INITELEM~a~(i+1)~x^\ast \\ && - (\iff S' = S \with \STABLES[a].\TIELEM[i] = F.\AMODULE.\MIFUNCS[x_0]) + (\iff S' = S \with \STABLES[a].\TIELEM[i] = \REFFUNC~F.\AMODULE.\MIFUNCS[x_0]) \\[1ex] S; F; \INITDATA~a~i~\epsilon &\stepto& S; F; \epsilon \\ diff --git a/document/core/exec/runtime.rst b/document/core/exec/runtime.rst index e798f06f4a..b730a898ed 100644 --- a/document/core/exec/runtime.rst +++ b/document/core/exec/runtime.rst @@ -7,29 +7,63 @@ Runtime Structure :ref:`Store `, :ref:`stack `, and other *runtime structure* forming the WebAssembly abstract machine, such as :ref:`values ` or :ref:`module instances `, are made precise in terms of additional auxiliary syntax. -.. index:: ! value, constant, value type, integer, floating-point +.. index:: ! value, number, reference, constant, number type, reference type, ! host address, value type, integer, floating-point, ! default value pair: abstract syntax; value +.. _syntax-num: +.. _syntax-ref: +.. _syntax-ref_func: +.. _syntax-ref_host: .. _syntax-val: Values ~~~~~~ -WebAssembly computations manipulate *values* of the four basic :ref:`value types `: :ref:`integers ` and :ref:`floating-point data ` of 32 or 64 bit width each, respectively. +WebAssembly computations manipulate *values* of either the four basic :ref:`number types `, i.e., :ref:`integers ` and :ref:`floating-point data ` of 32 or 64 bit width each, or of :ref:`reference type `. In most places of the semantics, values of different types can occur. In order to avoid ambiguities, values are therefore represented with an abstract syntax that makes their type explicit. -It is convenient to reuse the same notation as for the |CONST| :ref:`instructions ` producing them: +It is convenient to reuse the same notation as for the |CONST| :ref:`instructions ` and |REFNULL| producing them. + +References other than null are represented with additional :ref:`administrative instructions `. +They either are *function references*, pointing to a specific :ref:`function address `, +or *host references* pointing to an uninterpreted form of :ref:`host address ` that can be defined by the :ref:`embedder `. .. math:: \begin{array}{llcl} - \production{(value)} & \val &::=& + \production{(number)} & \num &::=& \I32.\CONST~\i32 \\&&|& \I64.\CONST~\i64 \\&&|& \F32.\CONST~\f32 \\&&|& - \F64.\CONST~\f64 + \F64.\CONST~\f64 \\ + \production{(reference)} & \reff &::=& + \REFNULL \\&&|& + \REFFUNC~\funcaddr \\&&|& + \REFHOST~\hostaddr \\ + \production{(value)} & \val &::=& + \num ~|~ \reff \\ + \end{array} + +.. note:: + Future versions of WebAssembly may add additional forms of reference. + +.. _default-val: + +Each :ref:`value type ` has an associated *default value*; +it is the respective value :math:`0` for :ref:`number types ` and null for :ref:`reference types `. + +.. math:: + \begin{array}{lcl@{\qquad}l} + \default_t &=& t{.}\CONST~0 & (\iff t = \numtype) \\ + \default_t &=& \REFNULL & (\iff t = \reftype) \\ \end{array} +Convention +.......... + +* The meta variable :math:`r` ranges over reference values where clear from context. + + .. index:: ! result, value, trap pair: abstract syntax; result .. _syntax-result: @@ -92,14 +126,17 @@ Convention pair: abstract syntax; table address pair: abstract syntax; memory address pair: abstract syntax; global address + pair: abstract syntax; host address pair: function; address pair: table; address pair: memory; address pair: global; address + pair: host; address .. _syntax-funcaddr: .. _syntax-tableaddr: .. _syntax-memaddr: .. _syntax-globaladdr: +.. _syntax-hostaddr: .. _syntax-addr: Addresses @@ -107,6 +144,7 @@ Addresses :ref:`Function instances `, :ref:`table instances `, :ref:`memory instances `, and :ref:`global instances ` in the :ref:`store ` are referenced with abstract *addresses*. These are simply indices into the respective store component. +In addition, an :ref:`embedder ` may supply an uninterpreted set of *host addresses*. .. math:: \begin{array}{llll} @@ -120,6 +158,8 @@ These are simply indices into the respective store component. \addr \\ \production{(global address)} & \globaladdr &::=& \addr \\ + \production{(host address)} & \hostaddr &::=& + \addr \\ \end{array} An :ref:`embedder ` may assign identity to :ref:`exported ` store objects corresponding to their addresses, @@ -212,22 +252,17 @@ Table Instances A *table instance* is the runtime representation of a :ref:`table `. It holds a vector of *function elements* and an optional maximum size, if one was specified in the :ref:`table type ` at the table's definition site. -Each function element is either empty, representing an uninitialized table entry, or a :ref:`function address `. -Function elements can be mutated through the execution of an :ref:`element segment ` or by external means provided by the :ref:`embedder `. +Each table element is a :ref:`reference value `. +Table elements can be mutated through :ref:`table instructions `, the execution of an :ref:`element segment `, or by external means provided by the :ref:`embedder `. .. math:: \begin{array}{llll} \production{(table instance)} & \tableinst &::=& - \{ \TIELEM~\vec(\funcelem), \TIMAX~\u32^? \} \\ - \production{(function element)} & \funcelem &::=& - \funcaddr^? \\ + \{ \TIELEM~\vec(\reff), \TIMAX~\u32^? \} \\ \end{array} It is an invariant of the semantics that the length of the element vector never exceeds the maximum size, if present. -.. note:: - Other table elements may be added in future versions of WebAssembly. - .. index:: ! memory instance, memory, byte, ! page size, memory type, embedder, data segment, instruction pair: abstract syntax; memory instance @@ -442,6 +477,7 @@ In order to express the reduction of :ref:`traps `, :ref:`calls `, :ref:`calls `. + The |INVOKE| instruction represents the imminent invocation of a :ref:`function instance `, identified by its :ref:`address `. It unifies the handling of different forms of calls. diff --git a/document/core/syntax/instructions.rst b/document/core/syntax/instructions.rst index 060933bf7f..3fc2996eaa 100644 --- a/document/core/syntax/instructions.rst +++ b/document/core/syntax/instructions.rst @@ -166,6 +166,30 @@ Occasionally, it is convenient to group operators together according to the foll \end{array} +.. index:: ! reference instruction, reference, null + pair: abstract syntax; instruction +.. _syntax-ref_null: +.. _syntax-ref_isnull: +.. _syntax-ref_eq: +.. _syntax-instr-ref: + +Reference Instructions +~~~~~~~~~~~~~~~~~~~~~~ + +Instructions in this group are concerned with accessing :ref:`references `. + +.. math:: + \begin{array}{llcl} + \production{instruction} & \instr &::=& + \dots \\&&|& + \REFNULL \\&&|& + \REFISNULL \\&&|& + \REFEQ \\ + \end{array} + +These instruction produce a null value, check for a null value, or compare two references, respectively. + + .. index:: ! parametric instruction, value type pair: abstract syntax; instruction .. _syntax-instr-parametric: @@ -212,6 +236,30 @@ These instructions get or set the values of variables, respectively. The |TEELOCAL| instruction is like |SETLOCAL| but also returns its argument. +.. index:: ! table instruction, table, table index, trap + pair: abstract syntax; instruction +.. _syntax-get_table: +.. _syntax-set_table: +.. _syntax-instr-table: + +Table Instructions +~~~~~~~~~~~~~~~~~~ + +Instructions in this group are concerned with accessing :ref:`tables `. + +.. math:: + \begin{array}{llcl} + \production{instruction} & \instr &::=& + \dots \\&&|& + \GETTABLE~\tableidx \\&&|& + \SETTABLE~\tableidx \\ + \end{array} + +These instructions get or set an element in a table, respectively. + +An additional instruction that accesses a table is the :ref:`control instruction ` |CALLINDIRECT|. + + .. index:: ! memory instruction, memory, memory index, page size, little endian, trap pair: abstract syntax; instruction .. _syntax-loadn: @@ -301,7 +349,7 @@ Instructions in this group affect the flow of control. \BRTABLE~\vec(\labelidx)~\labelidx \\&&|& \RETURN \\&&|& \CALL~\funcidx \\&&|& - \CALLINDIRECT~\typeidx \\ + \CALLINDIRECT~\tableidx~\typeidx \\ \end{array} The |NOP| instruction does nothing. @@ -340,14 +388,9 @@ Taking a branch *unwinds* the operand stack up to the height where the targeted However, forward branches that target a control instruction with a non-empty result type consume matching operands first and push them back on the operand stack after unwinding, as a result for the terminated structured instruction. The |CALL| instruction invokes another :ref:`function `, consuming the necessary arguments from the stack and returning the result values of the call. -The |CALLINDIRECT| instruction calls a function indirectly through an operand indexing into a :ref:`table `. -Since tables may contain function elements of heterogeneous type |ANYFUNC|, -the callee is dynamically checked against the :ref:`function type ` indexed by the instruction's immediate, and the call aborted with a :ref:`trap ` if it does not match. - -.. note:: - In the current version of WebAssembly, - |CALLINDIRECT| implicitly operates on :ref:`table ` :ref:`index ` :math:`0`. - This restriction may be lifted in future versions. +The |CALLINDIRECT| instruction calls a function indirectly through an operand indexing into a :ref:`table ` that is denoted by a :ref:`table index ` and must have type |ANYFUNC|. +Since it may contain functions of heterogeneous type, +the callee is dynamically checked against the :ref:`function type ` indexed by the instruction's second immediate, and the call is aborted with a :ref:`trap ` if it does not match. .. index:: ! expression, constant, global, offset, element, data, instruction diff --git a/document/core/syntax/modules.rst b/document/core/syntax/modules.rst index fe2b3cd7a1..ae285b64bc 100644 --- a/document/core/syntax/modules.rst +++ b/document/core/syntax/modules.rst @@ -147,7 +147,7 @@ The |MTABLES| component of a module defines a vector of *tables* described by th \{ \TTYPE~\tabletype \} \\ \end{array} -A table is a vector of opaque values of a particular table :ref:`element type `. +A table is a vector of opaque values of a particular :ref:`reference type `. The |LMIN| size in the :ref:`limits ` of the table type specifies the initial size of that table, while its |LMAX|, if present, restricts the size to which it can grow later. Tables can be initialized through :ref:`element segments `. @@ -237,8 +237,8 @@ The |MELEM| component of a module defines a vector of *element segments* that in The |EOFFSET| is given by a :ref:`constant ` :ref:`expression `. .. note:: - In the current version of WebAssembly, at most one table is allowed in a module. - Consequently, the only valid |tableidx| is :math:`0`. + In the current version of WebAssembly, only tables of element type |ANYFUNC| can be initialized with an element segment. + This limitation may be lifted in the future. .. index:: ! data, memory, memory index, expression, constant, byte, vector diff --git a/document/core/syntax/types.rst b/document/core/syntax/types.rst index 6898fb59ee..9749b97dc6 100644 --- a/document/core/syntax/types.rst +++ b/document/core/syntax/types.rst @@ -9,19 +9,19 @@ Various entitites in WebAssembly are classified by types. Types are checked during :ref:`validation `, :ref:`instantiation `, and possibly :ref:`execution `. -.. index:: ! value type, integer, floating-point, IEEE 754, bit width - pair: abstract syntax; value type - pair: value; type -.. _syntax-valtype: +.. index:: ! number type, integer, floating-point, IEEE 754, bit width, memory + pair: abstract syntax; number type + pair: number; type +.. _syntax-numtype: -Value Types -~~~~~~~~~~~ +Number Types +~~~~~~~~~~~~ -*Value types* classify the individual values that WebAssembly code can compute with and the values that a variable accepts. +*Number types* classify numeric values. .. math:: \begin{array}{llll} - \production{value type} & \valtype &::=& + \production{number type} & \numtype &::=& \I32 ~|~ \I64 ~|~ \F32 ~|~ \F64 \\ \end{array} @@ -31,15 +31,73 @@ Integers are not inherently signed or unsigned, their interpretation is determin The types |F32| and |F64| classify 32 and 64 bit floating-point data, respectively. They correspond to the respective binary floating-point representations, also known as *single* and *double* precision, as defined by the |IEEE754|_ standard (Section 3.3). +Number types are *transparent*, meaning that their bit patterns can be observed. +Values of number type can be stored in :ref:`memories `. + Conventions ........... -* The meta variable :math:`t` ranges over value types where clear from context. - -* The notation :math:`|t|` denotes the *bit width* of a value type. +* The notation :math:`|t|` denotes the *bit width* of a number type :math:`t`. That is, :math:`|\I32| = |\F32| = 32` and :math:`|\I64| = |\F64| = 64`. +.. index:: ! reference type, reference, table, function, function type, null + pair: abstract syntax; reference type + pair: reference; type +.. _syntax-reftype: + +Reference Types +~~~~~~~~~~~~~~~ + +*Reference types* classify first-class references to objects in the runtime :ref:`store `. + +.. math:: + \begin{array}{llll} + \production{reference type} & \reftype &::=& + \ANYREF ~|~ \ANYFUNC ~|~ \ANYEQREF ~|~ \NULLREF \\ + \end{array} + +The type |ANYREF| denotes the infinite union of all references, and thereby a :ref:`supertype ` of all other reference types. + +The type |ANYFUNC| denotes the infinite union of all references to :ref:`functions `, regardless of their :ref:`function types `. + +The type |ANYEQREF| denotes the infinite union of all references that can be compared for equality; +in order to avoid exposing implementation details, some reference types, such as |ANYFUNC|, do not admit equality, and therefore are not :ref:`subtypes ` of |ANYEQREF|. + +The type |NULLREF| only contains a single value: the :ref:`null ` reference. +It is a :ref:`subtype ` of all other reference types. +By virtue of not being representable in either the :ref:`binary format ` nor the :ref:`text format `, the |NULLREF| type cannot be used in a program; +it only occurs during :ref:`validation `. + +.. note:: + Future versions of WebAssembly may include reference types that do not include null and hence are not supertypes of |NULLREF|. + +Reference types are *opaque*, meaning that neither their size nor their bit pattern can be observed. +Values of reference type can be stored in :ref:`tables `. + + +.. index:: ! value type, number type, reference type + pair: abstract syntax; value type + pair: value; type +.. _syntax-valtype: + +Value Types +~~~~~~~~~~~ + +*Value types* classify the individual values that WebAssembly code can compute with and the values that a variable accepts. + +.. math:: + \begin{array}{llll} + \production{value type} & \valtype &::=& + \numtype ~|~ \reftype \\ + \end{array} + +Conventions +........... + +* The meta variable :math:`t` ranges over value types or subclasses thereof where clear from context. + + .. index:: ! result type, value type, instruction, execution, block pair: abstract syntax; result type pair: result; type @@ -126,34 +184,26 @@ The limits constrain the minimum and optionally the maximum size of a memory. The limits are given in units of :ref:`page size `. -.. index:: ! table type, ! element type, limits, table, element +.. index:: ! table type, reference type, limits, table, element pair: abstract syntax; table type - pair: abstract syntax; element type pair: table; type pair: table; limits - pair: element; type -.. _syntax-elemtype: .. _syntax-tabletype: Table Types ~~~~~~~~~~~ -*Table types* classify :ref:`tables ` over elements of *element types* within a size range. +*Table types* classify :ref:`tables ` over elements of :ref:`reference type ` within a size range. .. math:: \begin{array}{llll} \production{table type} & \tabletype &::=& - \limits~\elemtype \\ - \production{element type} & \elemtype &::=& - \ANYFUNC \\ + \limits~\reftype \\ \end{array} Like memories, tables are constrained by limits for their minimum and optionally maximum size. The limits are given in numbers of entries. -The element type |ANYFUNC| is the infinite union of all :ref:`function types `. -A table of that type thus contains references to functions of heterogeneous type. - .. note:: In future versions of WebAssembly, additional element types may be introduced. diff --git a/document/core/text/instructions.rst b/document/core/text/instructions.rst index dadd435b07..ddf773a070 100644 --- a/document/core/text/instructions.rst +++ b/document/core/text/instructions.rst @@ -97,7 +97,7 @@ All other control instruction are represented verbatim. &\Rightarrow& \BRTABLE~l^\ast~l_N \\ &&|& \text{return} &\Rightarrow& \RETURN \\ &&|& \text{call}~~x{:}\Tfuncidx_I &\Rightarrow& \CALL~x \\ &&|& - \text{call\_indirect}~~x,I'{:}\Ttypeuse_I &\Rightarrow& \CALLINDIRECT~x + \text{call\_indirect}~~x{:}\Ttableidx~~y,I'{:}\Ttypeuse_I &\Rightarrow& \CALLINDIRECT~x~y & (\iff I' = \{\}) \\ \end{array} @@ -118,8 +118,38 @@ The :math:`\text{else}` keyword of an :math:`\text{if}` instruction can be omitt \text{if}~~\Tlabel~~\Tresulttype~~\Tinstr^\ast~~\text{else}~~\text{end} \end{array} +Also, for backwards compatibility, the table index to :math:`\text{call\_indirect}` can be omitted, defaulting to :math:`0`. -.. index:: value type, polymorphism +.. math:: + \begin{array}{llclll} + \production{plain instruction} & + \text{call\_indirect}~~\Ttypeuse + &\equiv& + \text{call\_indirect}~~0~~\Ttypeuse + \end{array} + + +.. index:: reference instruction + pair: text format; instruction +.. _text-instr-ref: + +Reference Instructions +~~~~~~~~~~~~~~~~~~~~~~ + +.. _text-ref_null: +.. _text-ref_isnull: +.. _text-ref_eq: + +.. math:: + \begin{array}{llclll} + \production{instruction} & \Tplaininstr_I &::=& \dots \\ &&|& + \text{ref.null} &\Rightarrow& \REFNULL \\ &&|& + \text{ref.isnull} &\Rightarrow& \REFISNULL \\ &&|& + \text{ref.eq} &\Rightarrow& \REFEQ \\ + \end{array} + + +.. index:: parametric instruction, value type, polymorphism pair: text format; instruction .. _text-instr-parametric: @@ -161,6 +191,24 @@ Variable Instructions \end{array} +.. index:: table instructions, table index + pair: text format; instruction +.. _text-instr-table: + +Table Instructions +~~~~~~~~~~~~~~~~~~ + +.. _text-get_table: +.. _text-set_table: + +.. math:: + \begin{array}{llclll} + \production{instruction} & \Tplaininstr_I &::=& \dots \\ &&|& + \text{get\_table}~~x{:}\Ttableidx_I &\Rightarrow& \GETTABLE~x \\ &&|& + \text{set\_table}~~x{:}\Ttableidx_I &\Rightarrow& \SETTABLE~x \\ + \end{array} + + .. index:: memory instruction, memory index pair: text format; instruction .. _text-instr-memory: diff --git a/document/core/text/modules.rst b/document/core/text/modules.rst index 24e66ff81b..c718e571a5 100644 --- a/document/core/text/modules.rst +++ b/document/core/text/modules.rst @@ -278,8 +278,8 @@ An :ref:`element segment ` can be given inline with a table definitio .. math:: \begin{array}{llclll} \production{module field} & - \text{(}~\text{table}~~\Tid^?~~\Telemtype~~\text{(}~\text{elem}~~x^n{:}\Tvec(\Tfuncidx)~\text{)}~~\text{)} \quad\equiv \\ & \qquad - \text{(}~\text{table}~~\Tid'~~n~~n~~\Telemtype~\text{)}~~ + \text{(}~\text{table}~~\Tid^?~~\Treftype~~\text{(}~\text{elem}~~x^n{:}\Tvec(\Tfuncidx)~\text{)}~~\text{)} \quad\equiv \\ & \qquad + \text{(}~\text{table}~~\Tid'~~n~~n~~\Treftype~\text{)}~~ \text{(}~\text{elem}~~\Tid'~~\text{(}~\text{i32.const}~~\text{0}~\text{)}~~\Tvec(\Tfuncidx)~\text{)} \\ & \qquad\qquad (\iff \Tid' = \Tid^? \neq \epsilon \vee \Tid' \idfresh) \\ @@ -471,14 +471,12 @@ Element Segments ~~~~~~~~~~~~~~~~ Element segments allow for an optional :ref:`table index ` to identify the table to initialize. -When omitted, :math:`\T{0}` is assumed. .. math:: \begin{array}{llclll} \production{element segment} & \Telem_I &::=& - \text{(}~\text{elem}~~(x{:}\Ttableidx_I)^?~~\text{(}~\text{offset}~~e{:}\Texpr_I~\text{)}~~y^\ast{:}\Tvec(\Tfuncidx_I)~\text{)} \\ &&& \qquad - \Rightarrow\quad \{ \ETABLE~x', \EOFFSET~e, \EINIT~y^\ast \} \\ - &&& \qquad\qquad\qquad (\iff x' = x^? \neq \epsilon \vee x' = 0) \\ + \text{(}~\text{elem}~~x{:}\Ttableidx_I~~\text{(}~\text{offset}~~e{:}\Texpr_I~\text{)}~~y^\ast{:}\Tvec(\Tfuncidx_I)~\text{)} \\ &&& \qquad + \Rightarrow\quad \{ \ETABLE~x, \EOFFSET~e, \EINIT~y^\ast \} \\ \end{array} .. note:: @@ -491,13 +489,23 @@ Abbreviations As an abbreviation, a single instruction may occur in place of the offset: -.. math: +.. math:: \begin{array}{llcll} \production{element offset} & \Tinstr &\equiv& \text{(}~\text{offset}~~\Tinstr~\text{)} \end{array} +Also, the table index can be omitted, defaulting to :math:`0`. + +.. math:: + \begin{array}{llclll} + \production{element segment} & + \text{(}~\text{elem}~~\text{(}~\text{offset}~~\Texpr_I~\text{)}~~\dots~\text{)} + &\equiv& + \text{(}~\text{elem}~~0~~\text{(}~\text{offset}~~\Texpr_I~\text{)}~~\dots~\text{)} + \end{array} + As another abbreviation, element segments may also be specified inline with :ref:`table ` definitions; see the respective section. @@ -535,7 +543,7 @@ Abbreviations As an abbreviation, a single instruction may occur in place of the offset: -.. math: +.. math:: \begin{array}{llcll} \production{data offset} & \Tinstr &\equiv& diff --git a/document/core/text/types.rst b/document/core/text/types.rst index de5ed5f308..1c755abdc7 100644 --- a/document/core/text/types.rst +++ b/document/core/text/types.rst @@ -5,7 +5,40 @@ Types ----- -.. index:: value type +.. index:: number type + pair: text format; number type +.. _text-numtype: + +Number Types +~~~~~~~~~~~~ + +.. math:: + \begin{array}{llcll@{\qquad\qquad}l} + \production{number type} & \Tnumtype &::=& + \text{i32} &\Rightarrow& \I32 \\ &&|& + \text{i64} &\Rightarrow& \I64 \\ &&|& + \text{f32} &\Rightarrow& \F32 \\ &&|& + \text{f64} &\Rightarrow& \F64 \\ + \end{array} + + +.. index:: reference type + pair: text format; reference type +.. _text-reftype: + +Reference Types +~~~~~~~~~~~~~~~ + +.. math:: + \begin{array}{llcll@{\qquad\qquad}l} + \production{reference type} & \Treftype &::=& + \text{anyref} &\Rightarrow& \ANYREF \\ &&|& + \text{anyfunc} &\Rightarrow& \ANYFUNC \\ &&|& + \text{anyeqref} &\Rightarrow& \ANYEQREF \\ + \end{array} + + +.. index:: value type, number type, reference type pair: text format; value type .. _text-valtype: @@ -15,10 +48,8 @@ Value Types .. math:: \begin{array}{llcll@{\qquad\qquad}l} \production{value type} & \Tvaltype &::=& - \text{i32} &\Rightarrow& \I32 \\ &&|& - \text{i64} &\Rightarrow& \I64 \\ &&|& - \text{f32} &\Rightarrow& \F32 \\ &&|& - \text{f64} &\Rightarrow& \F64 \\ + t{:}\Tnumtype &\Rightarrow& t \\ &&|& + t{:}\Treftype &\Rightarrow& t \\ \end{array} @@ -106,10 +137,8 @@ Memory Types \end{array} -.. index:: table type, element type, limits +.. index:: table type, reference type, limits pair: text format; table type - pair: text format; element type -.. _text-elemtype: .. _text-tabletype: Table Types @@ -118,14 +147,9 @@ Table Types .. math:: \begin{array}{llclll} \production{table type} & \Ttabletype &::=& - \X{lim}{:}\Tlimits~~\X{et}{:}\Telemtype &\Rightarrow& \X{lim}~\X{et} \\ - \production{element type} & \Telemtype &::=& - \text{anyfunc} &\Rightarrow& \ANYFUNC \\ + \X{lim}{:}\Tlimits~~\X{et}{:}\Treftype &\Rightarrow& \X{lim}~\X{et} \\ \end{array} -.. note:: - Additional element types may be introduced in future versions of WebAssembly. - .. index:: global type, mutability, value type pair: text format; global type diff --git a/document/core/util/macros.def b/document/core/util/macros.def index 2216694b13..2038b503bf 100644 --- a/document/core/util/macros.def +++ b/document/core/util/macros.def @@ -171,7 +171,10 @@ .. |F32| mathdef:: \xref{syntax/types}{syntax-valtype}{\K{f32}} .. |F64| mathdef:: \xref{syntax/types}{syntax-valtype}{\K{f64}} -.. |ANYFUNC| mathdef:: \xref{syntax/types}{syntax-elemtype}{\K{anyfunc}} +.. |ANYREF| mathdef:: \xref{syntax/types}{syntax-reftype}{\K{anyref}} +.. |ANYFUNC| mathdef:: \xref{syntax/types}{syntax-reftype}{\K{anyfunc}} +.. |ANYEQREF| mathdef:: \xref{syntax/types}{syntax-reftype}{\K{anyeqref}} +.. |NULLREF| mathdef:: \xref{syntax/types}{syntax-reftype}{\K{nullref}} .. |MVAR| mathdef:: \xref{syntax/types}{syntax-mut}{\K{var}} .. |MCONST| mathdef:: \xref{syntax/types}{syntax-mut}{\K{const}} @@ -187,12 +190,13 @@ .. Types, non-terminals +.. |numtype| mathdef:: \xref{syntax/types}{syntax-numtype}{\X{numtype}} +.. |reftype| mathdef:: \xref{syntax/types}{syntax-reftype}{\X{reftype}} .. |valtype| mathdef:: \xref{syntax/types}{syntax-valtype}{\X{valtype}} .. |resulttype| mathdef:: \xref{syntax/types}{syntax-resulttype}{\X{resulttype}} .. |functype| mathdef:: \xref{syntax/types}{syntax-functype}{\X{functype}} .. |globaltype| mathdef:: \xref{syntax/types}{syntax-globaltype}{\X{globaltype}} .. |tabletype| mathdef:: \xref{syntax/types}{syntax-tabletype}{\X{tabletype}} -.. |elemtype| mathdef:: \xref{syntax/types}{syntax-elemtype}{\X{elemtype}} .. |memtype| mathdef:: \xref{syntax/types}{syntax-memtype}{\X{memtype}} .. |limits| mathdef:: \xref{syntax/types}{syntax-limits}{\X{limits}} @@ -323,11 +327,18 @@ .. |GETGLOBAL| mathdef:: \xref{syntax/instructions}{syntax-instr-variable}{\K{get\_global}} .. |SETGLOBAL| mathdef:: \xref{syntax/instructions}{syntax-instr-variable}{\K{set\_global}} +.. |GETTABLE| mathdef:: \xref{syntax/instructions}{syntax-instr-table}{\K{get\_table}} +.. |SETTABLE| mathdef:: \xref{syntax/instructions}{syntax-instr-table}{\K{set\_table}} + .. |LOAD| mathdef:: \xref{syntax/instructions}{syntax-instr-memory}{\K{load}} .. |STORE| mathdef:: \xref{syntax/instructions}{syntax-instr-memory}{\K{store}} .. |CURRENTMEMORY| mathdef:: \xref{syntax/instructions}{syntax-instr-memory}{\K{current\_memory}} .. |GROWMEMORY| mathdef:: \xref{syntax/instructions}{syntax-instr-memory}{\K{grow\_memory}} +.. |REFNULL| mathdef:: \xref{syntax/instructions}{syntax-instr-ref}{\K{ref{.}null}} +.. |REFISNULL| mathdef:: \xref{syntax/instructions}{syntax-instr-ref}{\K{ref{.}isnull}} +.. |REFEQ| mathdef:: \xref{syntax/instructions}{syntax-instr-ref}{\K{ref{.}eq}} + .. |CONST| mathdef:: \xref{syntax/instructions}{syntax-instr-numeric}{\K{const}} .. |EQZ| mathdef:: \xref{syntax/instructions}{syntax-instr-numeric}{\K{eqz}} .. |EQ| mathdef:: \xref{syntax/instructions}{syntax-instr-numeric}{\K{eq}} @@ -444,13 +455,14 @@ .. Types, non-terminals +.. |Bnumtype| mathdef:: \xref{binary/types}{binary-numtype}{\B{numtype}} +.. |Breftype| mathdef:: \xref{binary/types}{binary-reftype}{\B{reftype}} .. |Bvaltype| mathdef:: \xref{binary/types}{binary-valtype}{\B{valtype}} .. |Bresulttype| mathdef:: \xref{binary/types}{binary-resulttype}{\B{resulttype}} .. |Bblocktype| mathdef:: \xref{binary/types}{binary-blocktype}{\B{blocktype}} .. |Bfunctype| mathdef:: \xref{binary/types}{binary-functype}{\B{functype}} .. |Bglobaltype| mathdef:: \xref{binary/types}{binary-globaltype}{\B{globaltype}} .. |Btabletype| mathdef:: \xref{binary/types}{binary-tabletype}{\B{tabletype}} -.. |Belemtype| mathdef:: \xref{binary/types}{binary-elemtype}{\B{elemtype}} .. |Bmemtype| mathdef:: \xref{binary/types}{binary-memtype}{\B{memtype}} .. |Blimits| mathdef:: \xref{binary/types}{binary-limits}{\B{limits}} .. |Bmut| mathdef:: \xref{binary/types}{binary-mut}{\B{mut}} @@ -603,13 +615,14 @@ .. Types, non-terminals +.. |Tnumtype| mathdef:: \xref{text/types}{text-numtype}{\T{numtype}} +.. |Treftype| mathdef:: \xref{text/types}{text-reftype}{\T{reftype}} .. |Tvaltype| mathdef:: \xref{text/types}{text-valtype}{\T{valtype}} .. |Tresulttype| mathdef:: \xref{text/types}{text-resulttype}{\T{resulttype}} .. |Tblocktype| mathdef:: \xref{text/types}{text-blocktype}{\T{blocktype}} .. |Tfunctype| mathdef:: \xref{text/types}{text-functype}{\T{functype}} .. |Tglobaltype| mathdef:: \xref{text/types}{text-globaltype}{\T{globaltype}} .. |Ttabletype| mathdef:: \xref{text/types}{text-tabletype}{\T{tabletype}} -.. |Telemtype| mathdef:: \xref{text/types}{text-elemtype}{\T{elemtype}} .. |Tmemtype| mathdef:: \xref{text/types}{text-memtype}{\T{memtype}} .. |Tlimits| mathdef:: \xref{text/types}{text-limits}{\T{limits}} .. |Tparam| mathdef:: \xref{text/types}{text-functype}{\T{param}} @@ -704,6 +717,8 @@ .. |ok| mathdef:: \mathrel{\mbox{ok}} .. |const| mathdef:: \xref{valid/instructions}{valid-constant}{\mathrel{\mbox{const}}} +.. |matchesvaltype| mathdef:: \xref{valid/types}{match-valtype}{\leq} +.. |matchesresulttype| mathdef:: \xref{valid/types}{match-resulttype}{\leq} .. Contexts @@ -726,6 +741,11 @@ .. |vdashmemtype| mathdef:: \xref{valid/types}{valid-memtype}{\vdash} .. |vdashglobaltype| mathdef:: \xref{valid/types}{valid-globaltype}{\vdash} +.. |vdashnumtypematch| mathdef:: \xref{valid/types}{match-numtype}{\vdash} +.. |vdashreftypematch| mathdef:: \xref{valid/types}{match-reftype}{\vdash} +.. |vdashvaltypematch| mathdef:: \xref{valid/types}{match-valtype}{\vdash} +.. |vdashresulttypematch| mathdef:: \xref{valid/types}{match-resulttype}{\vdash} + .. |vdashinstr| mathdef:: \xref{valid/instructions}{valid-instr}{\vdash} .. |vdashinstrseq| mathdef:: \xref{valid/instructions}{valid-instr-seq}{\vdash} .. |vdashexpr| mathdef:: \xref{valid/instructions}{valid-expr}{\vdash} @@ -753,7 +773,8 @@ .. |stepto| mathdef:: \xref{exec/conventions}{formal-notation}{\hookrightarrow} .. |extendsto| mathdef:: \xref{appendix/properties}{extend}{\preceq} -.. |matches| mathdef:: \xref{exec/modules}{match}{\leq} +.. |matchesexterntype| mathdef:: \xref{exec/modules}{match-externtype}{\leq} +.. |matcheslimits| mathdef:: \xref{exec/modules}{match-limits}{\leq} .. Allocation @@ -776,6 +797,7 @@ .. |tableaddr| mathdef:: \xref{exec/runtime}{syntax-tableaddr}{\X{tableaddr}} .. |memaddr| mathdef:: \xref{exec/runtime}{syntax-memaddr}{\X{memaddr}} .. |globaladdr| mathdef:: \xref{exec/runtime}{syntax-globaladdr}{\X{globaladdr}} +.. |hostaddr| mathdef:: \xref{exec/runtime}{syntax-hostaddr}{\X{hostaddr}} .. Instances, terminals @@ -863,6 +885,8 @@ .. Administrative Instructions, terminals +.. |REFFUNC| mathdef:: \xref{exec/runtime}{syntax-ref_func}{\K{ref{.}func}} +.. |REFHOST| mathdef:: \xref{exec/runtime}{syntax-ref_host}{\K{ref{.}host}} .. |TRAP| mathdef:: \xref{exec/runtime}{syntax-trap}{\K{trap}} .. |INVOKE| mathdef:: \xref{exec/runtime}{syntax-invoke}{\K{invoke}} .. |INITELEM| mathdef:: \xref{exec/runtime}{syntax-init_elem}{\K{init\_elem}} @@ -871,10 +895,17 @@ .. Values & Results, non-terminals +.. |num| mathdef:: \xref{exec/runtime}{syntax-num}{\X{num}} +.. |reff| mathdef:: \xref{exec/runtime}{syntax-ref}{\X{ref}} .. |val| mathdef:: \xref{exec/runtime}{syntax-val}{\X{val}} .. |result| mathdef:: \xref{exec/runtime}{syntax-result}{\X{result}} +.. Values, meta-functions + +.. |default| mathdef:: \xref{exec/runtime}{default-val}{\F{default}} + + .. Administrative Instructions, non-terminals .. |XB| mathdef:: \xref{exec/runtime}{syntax-ctxt-block}{B} diff --git a/document/core/valid/instructions.rst b/document/core/valid/instructions.rst index ffc308ff29..1f415d393d 100644 --- a/document/core/valid/instructions.rst +++ b/document/core/valid/instructions.rst @@ -154,6 +154,57 @@ Numeric Instructions } +.. index:: reference instructions, reference type + pair: validation; instruction + single: abstract syntax; instruction +.. _valid-instr-ref: + +Reference Instructions +~~~~~~~~~~~~~~~~~~~~~~ + +.. _valid-ref_null: + +:math:`\REFNULL` +................ + +* The instruction is valid with type :math:`[] \to [\NULLREF]`. + +.. math:: + \frac{ + }{ + C \vdashinstr \REFNULL : [] \to [\NULLREF] + } + + +.. _valid-ref_isnull: + +:math:`\REFISNULL` +.................. + +* The instruction is valid with type :math:`[\ANYREF] \to [\I32]`. + +.. math:: + \frac{ + }{ + C \vdashinstr \REFISNULL : [\ANYREF] \to [\I32] + } + + +.. _valid-ref_eq: + +:math:`\REFEQ` +.............. + +* The instruction is valid with type :math:`[\ANYEQREF~\ANYEQREF] \to [\I32]`. + +.. math:: + \frac{ + }{ + C \vdashinstr \REFEQ : [\ANYEQREF~\ANYEQREF] \to [\I32] + } + + + .. index:: parametric instructions, value type, polymorphism pair: validation; instruction single: abstract syntax; instruction @@ -298,6 +349,54 @@ Variable Instructions } + + +.. index:: table instructions, table index, context + pair: validation; instruction + single: abstract syntax; instruction +.. _valid-instr-table: + +Table Instructions +~~~~~~~~~~~~~~~~~~ + +.. _valid-get_table: + +:math:`\GETTABLE~x` +................... + +* The table :math:`C.\CTABLES[x]` must be defined in the context. + +* Let :math:`\limits~t` be the :ref:`table type ` :math:`C.\CTABLES[x]`. + +* Then the instruction is valid with type :math:`[\I32] \to [t]`. + +.. math:: + \frac{ + C.\CTABLES[x] = \limits~t + }{ + C \vdashinstr \GETTABLE~x : [\I32] \to [t] + } + + +.. _valid-set_table: + +:math:`\SETTABLE~x` +................... + +* The local :math:`C.\CTABLES[x]` must be defined in the context. + +* Let :math:`\limits~t` be the :ref:`table type ` :math:`C.\CTABLES[x]`. + +* Then the instruction is valid with type :math:`[\I32~t] \to []`. + +.. math:: + \frac{ + C.\CTABLES[x] = t + }{ + C \vdashinstr \SETTABLE~x : [\I32~t] \to [] + } + + .. index:: memory instruction, memory index, context pair: validation; instruction single: abstract syntax; instruction @@ -588,21 +687,23 @@ Control Instructions * The label :math:`C.\CLABELS[l_N]` must be defined in the context. -* Let :math:`[t^?]` be the :ref:`result type ` :math:`C.\CLABELS[l_N]`. - * For all :math:`l_i` in :math:`l^\ast`, - the label :math:`C.\CLABELS[l_i]` must be defined in the context. + the label :math:`C.\CLABELS[l_i]` must be defined in the context -* For all :math:`l_i` in :math:`l^\ast`, - :math:`C.\CLABELS[l_i]` must be :math:`t^?`. +* There must be a :ref:`result type ` :math:`[t^?]`, such that: + + * The result type :math:`t^?` :ref:`matches ` :math:`C.\CLABELS[l_i]`. + + * For all :math:`l_i` in :math:`l^\ast`, + the result type :math:`t^?` :ref:`matches ` :math:`C.\CLABELS[l_i]`. * Then the instruction is valid with type :math:`[t_1^\ast~t^?~\I32] \to [t_2^\ast]`, for any sequences of :ref:`value types ` :math:`t_1^\ast` and :math:`t_2^\ast`. .. math:: \frac{ - (C.\CLABELS[l] = [t^?])^\ast + (\vdashresulttypematch [t^?] \matchesresulttype C.\CLABELS[l])^\ast \qquad - C.\CLABELS[l_N] = [t^?] + \vdashresulttypematch [t^?] \matchesresulttype C.\CLABELS[l_N] }{ C \vdashinstr \BRTABLE~l^\ast~l_N : [t_1^\ast~t^?~\I32] \to [t_2^\ast] } @@ -610,6 +711,10 @@ Control Instructions .. note:: The |BRTABLE| instruction is :ref:`stack-polymorphic `. + Furthermore, the :ref:`result type ` :math:`[t^?]` is also chosen non-deterministically in this rule. + In a :ref:`type checking algorithm `, the greatest lower bound of the involved label types can be picked as a principal type, + and it is a type error if that bound does not exist. + .. _valid-return: @@ -656,28 +761,30 @@ Control Instructions .. _valid-call_indirect: -:math:`\CALLINDIRECT~x` -....................... +:math:`\CALLINDIRECT~x~y` +......................... -* The table :math:`C.\CTABLES[0]` must be defined in the context. +* The table :math:`C.\CTABLES[x]` must be defined in the context. -* Let :math:`\limits~\elemtype` be the :ref:`table type ` :math:`C.\CTABLES[0]`. +* Let :math:`\limits~t` be the :ref:`table type ` :math:`C.\CTABLES[x]`. -* The :ref:`element type ` :math:`\elemtype` must be |ANYFUNC|. +* The :ref:`reference type ` :math:`t` must :ref:`match ` type |ANYFUNC|. -* The type :math:`C.\CTYPES[x]` must be defined in the context. +* The type :math:`C.\CTYPES[y]` must be defined in the context. -* Let :math:`[t_1^\ast] \to [t_2^\ast]` be the :ref:`function type ` :math:`C.\CTYPES[x]`. +* Let :math:`[t_1^\ast] \to [t_2^\ast]` be the :ref:`function type ` :math:`C.\CTYPES[y]`. * Then the instruction is valid with type :math:`[t_1^\ast~\I32] \to [t_2^\ast]`. .. math:: \frac{ - C.\CTABLES[0] = \limits~\ANYFUNC + C.\CTABLES[x] = \limits~t + \qquad + \vdashvaltypematch t \leq \ANYFUNC \qquad - C.\CTYPES[x] = [t_1^\ast] \to [t_2^\ast] + C.\CTYPES[y] = [t_1^\ast] \to [t_2^\ast] }{ - C \vdashinstr \CALLINDIRECT~x : [t_1^\ast~\I32] \to [t_2^\ast] + C \vdashinstr \CALLINDIRECT~x~y : [t_1^\ast~\I32] \to [t_2^\ast] } @@ -713,13 +820,17 @@ Non-empty Instruction Sequence: :math:`\instr^\ast~\instr_N` for some sequences of :ref:`value types ` :math:`t^\ast` and :math:`t_3^\ast`. * There must be a sequence of :ref:`value types ` :math:`t_0^\ast`, - such that :math:`t_2^\ast = t_0^\ast~t^\ast`. + such that :math:`t_2^\ast = t_0^\ast~{t'}^\ast` where the type sequence :math:`{t'}^\ast` is as long as :math:`t^\ast`. + +* For each :ref:`value type ` :math:`t'_i` in :math:`{t'}^\ast` and corresponding type :math:`t_i` in :math:`t^\ast`, the type :math:`t'_i` must :ref:`match ` :math:`t_i`. * Then the combined instruction sequence is valid with type :math:`[t_1^\ast] \to [t_0^\ast~t_3^\ast]`. .. math:: \frac{ - C \vdashinstrseq \instr^\ast : [t_1^\ast] \to [t_0^\ast~t^\ast] + C \vdashinstrseq \instr^\ast : [t_1^\ast] \to [t_0^\ast~{t'}^\ast] + \qquad + (\vdashvaltypematch t' \matchesvaltype t)^\ast \qquad C \vdashinstr \instr_N : [t^\ast] \to [t_3^\ast] }{ @@ -782,6 +893,11 @@ Constant Expressions C \vdashinstrconst t.\CONST~c \const } \qquad + \frac{ + }{ + C \vdashinstrconst \REFNULL \const + } + \qquad \frac{ C.\CGLOBALS[x] = \CONST~t }{ diff --git a/document/core/valid/modules.rst b/document/core/valid/modules.rst index 6dc45a687b..bd91d5026b 100644 --- a/document/core/valid/modules.rst +++ b/document/core/valid/modules.rst @@ -152,9 +152,9 @@ Element segments :math:`\elem` are not classified by a type. * The table :math:`C.\CTABLES[x]` must be defined in the context. -* Let :math:`\limits~\elemtype` be the :ref:`table type ` :math:`C.\CTABLES[x]`. +* Let :math:`\limits~t` be the :ref:`table type ` :math:`C.\CTABLES[x]`. -* The :ref:`element type ` :math:`\elemtype` must be |ANYFUNC|. +* The :ref:`reference type ` :math:`t` must be |ANYFUNC|. * The expression :math:`\expr` must be :ref:`valid ` with :ref:`result type ` :math:`[\I32]`. @@ -501,8 +501,6 @@ Instead, the context :math:`C` for validation of the module's content is constru * For each :math:`\export_i` in :math:`\module.\MEXPORTS`, the segment :math:`\import_i` must be :ref:`valid ` with :ref:`external type ` :math:`\externtype'_i`. -* The length of :math:`C.\CTABLES` must not be larger than :math:`1`. - * The length of :math:`C.\CMEMS` must not be larger than :math:`1`. * All export names :math:`\export_i.\ENAME` must be different. @@ -548,8 +546,6 @@ Instead, the context :math:`C` for validation of the module's content is constru \\ C' = \{ \CGLOBALS~\X{igt}^\ast \} \qquad - |C.\CTABLES| \leq 1 - \qquad |C.\CMEMS| \leq 1 \qquad (\export.\ENAME)^\ast ~\F{disjoint} @@ -582,4 +578,4 @@ Instead, the context :math:`C` for validation of the module's content is constru The effect of defining the limited context :math:`C'` for validating the module's globals is that their initialization expressions can only access imported globals and nothing else. .. note:: - The restriction on the number of tables and memories may be lifted in future versions of WebAssembly. + The restriction on the number of memories may be lifted in future versions of WebAssembly. diff --git a/document/core/valid/types.rst b/document/core/valid/types.rst index 76c6c70211..2d3235c265 100644 --- a/document/core/valid/types.rst +++ b/document/core/valid/types.rst @@ -4,6 +4,8 @@ Types Most :ref:`types ` are universally valid. However, restrictions apply to :ref:`function types ` as well as the :ref:`limits ` of :ref:`table types ` and :ref:`memory types `, which must be checked during validation. +On :ref:`value types `, a simple notion of subtyping is defined. + .. index:: limits pair: validation; limits @@ -57,7 +59,7 @@ Function Types This restriction may be removed in future versions of WebAssembly. -.. index:: table type, element type, limits +.. index:: table type, reference type, limits pair: validation; table type single: abstract syntax; table type .. _valid-tabletype: @@ -65,8 +67,8 @@ Function Types Table Types ~~~~~~~~~~~ -:math:`\limits~\elemtype` -......................... +:math:`\limits~\reftype` +........................ * The limits :math:`\limits` must be :ref:`valid `. @@ -76,7 +78,7 @@ Table Types \frac{ \vdashlimits \limits \ok }{ - \vdashtabletype \limits~\elemtype \ok + \vdashtabletype \limits~\reftype \ok } @@ -121,3 +123,95 @@ Global Types }{ \vdashglobaltype \mut~\valtype \ok } + + +.. index:: subtyping + +Value Subtyping +~~~~~~~~~~~~~~~ + +.. index:: number type + +.. _match-numtype: + +Number Types +............ + +A :ref:`number type ` :math:`\numtype_1` matches a :ref:`number type ` :math:`\numtype_2` if and only if: + +* Both :math:`\numtype_1` and :math:`\numtype_2` are the same. + +.. math:: + ~\\[-1ex] + \frac{ + }{ + \vdashnumtypematch \numtype \matchesvaltype \numtype + } + + +.. index:: reference type + +.. _match-reftype: + +Reference Types +............... + +A :ref:`reference type ` :math:`\reftype_1` matches a :ref:`number type ` :math:`\reftype_2` if and only if: + +* Either both :math:`\reftype_1` and :math:`\reftype_2` are the same. + +* Or :math:`\reftype_1` is |NULLREF|. + +* Or :math:`\reftype_2` is |ANYREF|. + +.. math:: + ~\\[-1ex] + \frac{ + }{ + \vdashreftypematch \reftype \matchesvaltype \reftype + } + \qquad + \frac{ + }{ + \vdashreftypematch \NULLREF \matchesvaltype \reftype + } + \qquad + \frac{ + }{ + \vdashreftypematch \reftype \matchesvaltype \ANYREF + } + + +.. index:: value type, number type, reference type + +.. _match-valtype: + +Value Types +........... + +A :ref:`value type ` :math:`\valtype_1` matches a :ref:`value type ` :math:`\valtype_2` if and only if: + +* Either both :math:`\valtype_1` and :math:`\valtype_2` are :ref:`number types ` and :math:`\valtype_1` :ref:`matches ` :math:`\valtype_2`. + +* Or both :math:`\valtype_1` and :math:`\valtype_2` are :ref:`reference types ` and :math:`\valtype_1` :ref:`matches ` :math:`\valtype_2`. + + +.. _match-resulttype: + +Result Types +............ + +Subtyping is lifted to :ref:`result types ` in a pointwise manner. +That is, a :ref:`result type ` :math:`[t_1^?]` matches a :ref:`result type ` :math:`[t_2^?]` if and only if: + +* Either both :math:`t_1^?` and :math:`t_2^?` are empty. + +* Or :ref:`value type ` :math:`t_1` :ref:`matches ` :ref:`value type ` :math:`t_2`. + +.. math:: + ~\\[-1ex] + \frac{ + (\vdashvaltypematch t_1 \matchesvaltype t_2)^? + }{ + \vdashresulttypematch [t_1^?] \matchesresulttype [t_2^?] + } From fec2142c507f5444094de2d4fb800bbdaf4d60e8 Mon Sep 17 00:00:00 2001 From: Andreas Rossberg Date: Thu, 5 Apr 2018 20:09:38 +0200 Subject: [PATCH 015/199] Update overview --- proposals/reference-types/Overview.md | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/proposals/reference-types/Overview.md b/proposals/reference-types/Overview.md index 35859ed249..03504fc638 100644 --- a/proposals/reference-types/Overview.md +++ b/proposals/reference-types/Overview.md @@ -70,8 +70,8 @@ New/extended instructions: - `ref.null : [] -> [nullref]` - allowed in constant expressions -* The new instruction `ref.is_null` checks for null. - - `ref.is_null : [anyref] -> [i32]` +* The new instruction `ref.isnull` checks for null. + - `ref.isnull : [anyref] -> [i32]` * The new instructions `table.get` and `table.set` access tables. - `table.get $x : [i32] -> [t]` iff `t` is the element type of table `$x` @@ -116,17 +116,17 @@ Motivation: Additions: -* Add `eqref` as the type of comparable references - - `reftype ::= ... | eqref` +* Add `anyeqref` as the type of comparable references + - `reftype ::= ... | anyeqref` * It is a subtype of `anyref` - - `eqref < anyref` - - `nullref < eqref` + - `anyeqref < anyref` + - `nullref < anyeqref` * Add `ref.eq` instruction. - - `ref.eq : [eqref eqref] -> [i32]` + - `ref.eq : [anyeqref anyeqref] -> [i32]` API changes: -* Any JS object (non-primitive value) or `null` can be passed as `eqref` to a Wasm function, stored in a global, or in a table. +* Any JS object (non-primitive value) or `null` can be passed as `anyeqref` to a Wasm function, stored in a global, or in a table. Questions: @@ -154,7 +154,7 @@ Additions: * Subtying between concrete and universal reference types - `ref $t < anyref` - `ref < anyfunc` - - Note: reference types are not necessarily subtypes of `eqref`, including functions + - Note: reference types are not necessarily subtypes of `anyeqref`, including functions * Typed function references cannot be null! From a219a033c9f52634be6fc62dee34770f7531b985 Mon Sep 17 00:00:00 2001 From: Andreas Rossberg Date: Thu, 12 Apr 2018 23:16:22 +0200 Subject: [PATCH 016/199] [spec] JS API changes (#8) --- document/js-api/index.bs | 56 ++++++++++++++++++++++++--- proposals/reference-types/Overview.md | 2 +- 2 files changed, 52 insertions(+), 6 deletions(-) diff --git a/document/js-api/index.bs b/document/js-api/index.bs index 19d19808fd..ead9036207 100644 --- a/document/js-api/index.bs +++ b/document/js-api/index.bs @@ -100,6 +100,9 @@ urlPrefix: https://webassembly.github.io/spec/core/; spec: WebAssembly; type: df text: 𝗂𝟥𝟤.𝖼𝗈𝗇𝗌𝗍 text: 𝖿𝟥𝟤.𝖼𝗈𝗇𝗌𝗍 text: 𝖿𝟨𝟦.𝖼𝗈𝗇𝗌𝗍 + text: ref.null + text: ref.func + text: ref.host text: function index; url: syntax/modules.html#syntax-funcidx text: function instance; url: exec/runtime.html#function-instances text: init_store; url: appendix/embedding.html#embed-init-store @@ -132,11 +135,16 @@ urlPrefix: https://webassembly.github.io/spec/core/; spec: WebAssembly; type: df text: table address; url: exec/runtime.html#syntax-tableaddr text: function address; url: exec/runtime.html#syntax-funcaddr text: memory address; url: exec/runtime.html#syntax-memaddr - url: syntax/types.html#syntax-valtype + text: host address; url: exec/runtime.html#syntax-hostaddr + url: syntax/types.html#syntax-numtype text: 𝗂𝟥𝟤 text: 𝗂𝟨𝟦 text: 𝖿𝟥𝟤 text: 𝖿𝟨𝟦 + url: syntax/types.html#syntax-reftype + text: anyref + text: anyeqref + text: anyfunc text: function element; url: exec/runtime.html#syntax-funcelem text: import component; url: syntax/modules.html#imports text: external value; url: exec/runtime.html#syntax-externval @@ -223,6 +231,7 @@ Each [=agent=] is associated with the following [=ordered map=]s: * The Memory object cache, mapping [=memory address=]es to {{Memory}} objects. * The Table object cache, mapping [=table address=]es to {{Table}} objects. * The Exported Function cache, mapping [=function address=]es to [=Exported Function=] objects. + * The Host value cache, mapping [=host address=]es to values.

The WebAssembly Namespace

@@ -326,7 +335,7 @@ A {{Module}} object represents a single WebAssembly module. Each {{Module}} obje 1. [=Append=] |externfunc| to |imports|. 1. If |externtype| is of the form [=𝗀𝗅𝗈𝖻𝖺𝗅=] |globaltype|, 1. If |globaltype| is [=𝗂𝟨𝟦=] or [=Type=](|v|) is not [=Number=], throw a {{LinkError}} exception. - 1. Let |value| be [=ToWebAssemblyValue=](|v|, |globaltype|.[=global type|valtype=]) + 1. Let |value| be [=ToWebAssemblyValue=](|v|, |globaltype|.[=global type|valtype=], {{LinkError}}) 1. Assert: |globaltype|.[=global type|mut=] is [=global type|𝖼𝗈𝗇𝗌𝗍=], as verified by WebAssembly validation. 1. Let |store| be the [=surrounding agent=]'s [=associated store=]. 1. Let (|store|, |globaladdr|) be [=alloc_global=](|store|, |globaltype|, |value|). @@ -590,6 +599,8 @@ which can be simultaneously referenced by multiple {{Instance}} objects. Each
 enum TableKind {
+  "anyref",
+  "anyeqref",
   "anyfunc",
   // Note: More values may be added in future iterations,
   // e.g., typed function references, typed GC references
@@ -742,7 +753,7 @@ This slot holds a [=function address=] relative to the [=surrounding agent=]'s [
     1. For each type |t| of |parameters|,
         1. If the length of |argValues| > |i|, let |arg| be |argValues|[i].
         1. Otherwise, let |arg| be undefined.
-        1. [=Append=] [=ToWebAssemblyValue=](|arg|, |t|) to |args|.
+        1. [=Append=] [=ToWebAssemblyValue=](|arg|, |t|, {{TypeError}}) to |args|.
         1. Set |i| to |i| + 1.
     1. Let (|store|, |ret|) be the result of [=invoke_func=](|store|, |funcaddr|, |args|).
     1. Set the [=surrounding agent=]'s [=associated store=] to |store|.
@@ -767,7 +778,7 @@ Note: Exported Functions do not have a \[[Construct]] method and thus it is not
         1. Let |ret| be ? [=Call=](|func|, undefined, |jsArguments|). If an exception is thrown, trigger a WebAssembly trap, and propagate the exception to the enclosing JavaScript.
         1. Let [|parameters|] → [|results|] be |functype|.
         1. If |results| is empty, return undefined.
-        1. Otherwise, return [=ToWebAssemblyValue=](|ret|, |results|[0]).
+        1. Otherwise, return [=ToWebAssemblyValue=](|ret|, |results|[0], {{TypeError}}).
     1. Let |store| be the [=surrounding agent=]'s [=associated store=].
     1. Let (|store|, |funcaddr|) be [=alloc_func=](|store|, |functype|, |hostfunc|).
     1. Set the [=surrounding agent=]'s [=associated store=] to |store|.
@@ -781,6 +792,9 @@ Assert: |w| is not of the form [=𝗂𝟨𝟦.𝖼𝗈𝗇𝗌𝗍=] |i64|.
 1. If |w| is of the form [=𝗂𝟥𝟤.𝖼𝗈𝗇𝗌𝗍=] |i32|, return [=the Number value=] for [=signed_32=](|i32|).
 1. If |w| is of the form [=𝖿𝟥𝟤.𝖼𝗈𝗇𝗌𝗍=] |f32|, return [=the Number value=] for |f32|.
 1. If |w| is of the form [=𝖿𝟨𝟦.𝖼𝗈𝗇𝗌𝗍=] |f64|, return [=the Number value=] for |f64|.
+1. If |w| is of the form [=ref.null=], return null.
+1. If |w| is of the form [=ref.func=] |funcaddr|, return the result of creating [=a new Exported Function=] from |funcaddr|.
+1. If |w| is of the form [=ref.host=] |hostaddr|, return the result of [=retrieving a host value=] from |hostaddr|.
 
 
 
@@ -788,7 +802,14 @@ Note: Implementations may optionally replace the NaN payload with any other NaN
 
 
 
-The algorithm ToWebAssemblyValue(|v|, |type|) coerce a JavaScript value to a [=WebAssembly value=] performs the following steps: + For retrieving a host value from a [=host address=] |hostaddr|, perform the following steps: + 1. Let |map| be the [=surrounding agent=]'s associated [=host value cache=]. + 1. Assert: |map|[|hostaddr|] [=map/exists=]. + 1. Return |map|[|hostaddr|]. +
+ +
+The algorithm ToWebAssemblyValue(|v|, |type|, |error|) coerces a JavaScript value to a [=WebAssembly value=] performs the following steps: Assert: |type| is not [=𝗂𝟨𝟦=]. @@ -801,9 +822,34 @@ Assert: |type| is not [=𝗂𝟨𝟦=]. 1. If |type| is [=𝖿𝟨𝟦=], 1. Let |f64| be ? [=ToNumber=](|v|). 1. Return [=𝖿𝟨𝟦.𝖼𝗈𝗇𝗌𝗍=] |f64|. +1. If |type| is [=anyref=], + 1. If |v| is a primitive value but not a string, symbol, or null, throw |error|. + 1. Return the result of [=allocating a host address=] for |v|. +1. If |type| is [=anyeqref=], + 1. If |v| is a primitive value but not a symbol or null, throw |error|. + 1. Return the result of [=allocating a host address=] for |v|. +1. If |type| is [=anyfunc=], + 1. If |v| is not an [=Exported function=] or null, throw |error|. + 1. Return the result of [=allocating a host address=] for |v|.
+
+ For allocating a host address for a value |v|, perform the following steps: + 1. If |v| is null, + 1. Return [=ref.null=]. + 1. If |v| is an [=Exported Function=], + 1. Let |funcaddr| be the value of |v|'s \[[FunctionAddress]] internal slot. + 1. Return [=ref.func=] |funcaddr|. + 1. Let |map| be the [=surrounding agent=]'s associated [=host value cache=]. + 1. If a [=host address=] |hostaddr| exists such that |map|[|hostaddr|] is the same as |v|, + 1. Return [=ref.host=] |hostaddr|. + 1. Let [=host address=] |hostaddr| be the smallest address such that |map|[|hostaddr|] [=map/exists=] is false. + 1. [=map/Set=] |map|[|hostaddr|] to |v|. + 1. Return [=ref.host=] |hostaddr|. +
+ +

Error Objects

WebAssembly defines the following Error classes: {{CompileError}}, {{LinkError}}, and {{RuntimeError}}. WebAssembly errors have the following custom bindings: diff --git a/proposals/reference-types/Overview.md b/proposals/reference-types/Overview.md index 1182e5b6c8..3675bd7b36 100644 --- a/proposals/reference-types/Overview.md +++ b/proposals/reference-types/Overview.md @@ -100,7 +100,7 @@ API extensions: * Any JS object (non-primitive value) or string or symbol or `null` can be passed as `anyref` to a Wasm function, stored in a global, or in a table. - It may be possible to allow all other non-primitive values as well, depending on details of existing engines. -* Any JS function object or `null` can be passed as `anyfunc` to a Wasm function, stored in a global, or in a table. +* Any Wasm exported function object or `null` can be passed as `anyfunc` to a Wasm function, stored in a global, or in a table. ## Possible Future Extensions From 4fee761f8fb2998af326e8595c5450eb0e965b03 Mon Sep 17 00:00:00 2001 From: Andreas Rossberg Date: Sun, 15 Apr 2018 20:21:00 +0200 Subject: [PATCH 017/199] Rename to eqref; allow any JS value for anyref (#10) --- document/core/appendix/algorithm.rst | 8 +++--- document/core/appendix/index-instructions.rst | 4 +-- document/core/appendix/index-types.rst | 2 +- document/core/binary/types.rst | 2 +- document/core/syntax/types.rst | 6 ++--- document/core/text/types.rst | 2 +- document/core/util/macros.def | 2 +- document/core/valid/instructions.rst | 4 +-- document/js-api/index.bs | 7 +++-- interpreter/README.md | 2 +- interpreter/binary/decode.ml | 2 +- interpreter/binary/encode.ml | 2 +- interpreter/script/js.ml | 6 ++--- interpreter/script/script.ml | 2 +- interpreter/syntax/types.ml | 4 +-- interpreter/text/lexer.mll | 2 +- interpreter/text/parser.mly | 4 +-- interpreter/valid/valid.ml | 26 ++++++++++++++----- proposals/reference-types/Overview.md | 18 ++++++------- test/core/br_table.wast | 12 ++++----- test/core/globals.wast | 8 +++--- test/core/linking.wast | 4 +-- test/core/select.wast | 8 +++--- 23 files changed, 74 insertions(+), 63 deletions(-) diff --git a/document/core/appendix/algorithm.rst b/document/core/appendix/algorithm.rst index 5253a4a9c7..0afd6e360d 100644 --- a/document/core/appendix/algorithm.rst +++ b/document/core/appendix/algorithm.rst @@ -33,11 +33,11 @@ A type error is encountered if a join or meet is required when it does not exist .. code-block:: pseudo - type val_type = I32 | I64 | F32 | F64 | Anyref | Anyfunc | Anyeqref | Nullref + type val_type = I32 | I64 | F32 | F64 | Anyref | Anyfunc | Eqref | Nullref type opd_type = val_type | Unknown func is_ref(t : opd_type) : bool = - return t = Anyref || t = Anyfunc || t = Anyeqref || t = Nullref + return t = Anyref || t = Anyfunc || t = Eqref || t = Nullref func matches(t1 : opd_type, t2 : opd_type) : bool = return t1 = t2 || t1 = Unknown || @@ -181,8 +181,8 @@ Other instructions are checked in a similar manner. push_opd(I32) case (ref.eq) - pop_opd(Anyeqref) - pop_opd(Anyeqref) + pop_opd(Eqref) + pop_opd(Eqref) push_opd(I32) case (drop) diff --git a/document/core/appendix/index-instructions.rst b/document/core/appendix/index-instructions.rst index d199779185..5122891981 100644 --- a/document/core/appendix/index-instructions.rst +++ b/document/core/appendix/index-instructions.rst @@ -216,7 +216,7 @@ Instruction Binary Opcode Type (reserved) :math:`\hex{CE}` (reserved) :math:`\hex{CF}` :math:`\REFNULL` :math:`\hex{D0}` :math:`[] \to [\NULLREF]` :ref:`validation ` :ref:`execution ` -:math:`\REFISNULL` :math:`\hex{D1}` :math:`[\ANYREF] \to [\I32]` :ref:`validation ` :ref:`execution ` -:math:`\REFEQ` :math:`\hex{D2}` :math:`[\ANYEQREF~\ANYEQREF] \to [\I32]` :ref:`validation ` :ref:`execution ` +:math:`\REFISNULL` :math:`\hex{D1}` :math:`[\ANYREF] \to [\I32]` :ref:`validation ` :ref:`execution ` +:math:`\REFEQ` :math:`\hex{D2}` :math:`[\EQREF~\EQREF] \to [\I32]` :ref:`validation ` :ref:`execution ` =================================== ================ ========================================== ======================================== =============================================================== diff --git a/document/core/appendix/index-types.rst b/document/core/appendix/index-types.rst index 8199229412..bfaccf1645 100644 --- a/document/core/appendix/index-types.rst +++ b/document/core/appendix/index-types.rst @@ -15,7 +15,7 @@ Category Constructor (reserved) :math:`\hex{7B}` .. :math:`\hex{71}` :ref:`Reference type ` |ANYFUNC| :math:`\hex{70}` (-16 as |Bs7|) :ref:`Reference type ` |ANYREF| :math:`\hex{6F}` (-17 as |Bs7|) -:ref:`Reference type ` |ANYEQREF| :math:`\hex{6E}` (-18 as |Bs7|) +:ref:`Reference type ` |EQREF| :math:`\hex{6E}` (-18 as |Bs7|) (reserved) :math:`\hex{6D}` .. :math:`\hex{61}` :ref:`Function type ` :math:`[\valtype^\ast] \to [\valtype^\ast]` :math:`\hex{60}` (-32 as |Bs7|) (reserved) :math:`\hex{5F}` .. :math:`\hex{41}` diff --git a/document/core/binary/types.rst b/document/core/binary/types.rst index 21b4ec1bdc..e5fe814a7a 100644 --- a/document/core/binary/types.rst +++ b/document/core/binary/types.rst @@ -43,7 +43,7 @@ Reference Types \production{reference type} & \Breftype &::=& \hex{70} &\Rightarrow& \ANYFUNC \\ &&|& \hex{6F} &\Rightarrow& \ANYREF \\ &&|& - \hex{6E} &\Rightarrow& \ANYEQREF \\ + \hex{6E} &\Rightarrow& \EQREF \\ \end{array} diff --git a/document/core/syntax/types.rst b/document/core/syntax/types.rst index 9749b97dc6..b44c758d75 100644 --- a/document/core/syntax/types.rst +++ b/document/core/syntax/types.rst @@ -54,15 +54,15 @@ Reference Types .. math:: \begin{array}{llll} \production{reference type} & \reftype &::=& - \ANYREF ~|~ \ANYFUNC ~|~ \ANYEQREF ~|~ \NULLREF \\ + \ANYREF ~|~ \ANYFUNC ~|~ \EQREF ~|~ \NULLREF \\ \end{array} The type |ANYREF| denotes the infinite union of all references, and thereby a :ref:`supertype ` of all other reference types. The type |ANYFUNC| denotes the infinite union of all references to :ref:`functions `, regardless of their :ref:`function types `. -The type |ANYEQREF| denotes the infinite union of all references that can be compared for equality; -in order to avoid exposing implementation details, some reference types, such as |ANYFUNC|, do not admit equality, and therefore are not :ref:`subtypes ` of |ANYEQREF|. +The type |EQREF| denotes the infinite union of all references that can be compared for equality; +in order to avoid exposing implementation details, some reference types, such as |ANYFUNC|, do not admit equality, and therefore are not :ref:`subtypes ` of |EQREF|. The type |NULLREF| only contains a single value: the :ref:`null ` reference. It is a :ref:`subtype ` of all other reference types. diff --git a/document/core/text/types.rst b/document/core/text/types.rst index 1c755abdc7..1e8881aee4 100644 --- a/document/core/text/types.rst +++ b/document/core/text/types.rst @@ -34,7 +34,7 @@ Reference Types \production{reference type} & \Treftype &::=& \text{anyref} &\Rightarrow& \ANYREF \\ &&|& \text{anyfunc} &\Rightarrow& \ANYFUNC \\ &&|& - \text{anyeqref} &\Rightarrow& \ANYEQREF \\ + \text{eqref} &\Rightarrow& \EQREF \\ \end{array} diff --git a/document/core/util/macros.def b/document/core/util/macros.def index 2038b503bf..c9cc2cfb5a 100644 --- a/document/core/util/macros.def +++ b/document/core/util/macros.def @@ -173,7 +173,7 @@ .. |ANYREF| mathdef:: \xref{syntax/types}{syntax-reftype}{\K{anyref}} .. |ANYFUNC| mathdef:: \xref{syntax/types}{syntax-reftype}{\K{anyfunc}} -.. |ANYEQREF| mathdef:: \xref{syntax/types}{syntax-reftype}{\K{anyeqref}} +.. |EQREF| mathdef:: \xref{syntax/types}{syntax-reftype}{\K{eqref}} .. |NULLREF| mathdef:: \xref{syntax/types}{syntax-reftype}{\K{nullref}} .. |MVAR| mathdef:: \xref{syntax/types}{syntax-mut}{\K{var}} diff --git a/document/core/valid/instructions.rst b/document/core/valid/instructions.rst index 1f415d393d..a24719dcac 100644 --- a/document/core/valid/instructions.rst +++ b/document/core/valid/instructions.rst @@ -195,12 +195,12 @@ Reference Instructions :math:`\REFEQ` .............. -* The instruction is valid with type :math:`[\ANYEQREF~\ANYEQREF] \to [\I32]`. +* The instruction is valid with type :math:`[\EQREF~\EQREF] \to [\I32]`. .. math:: \frac{ }{ - C \vdashinstr \REFEQ : [\ANYEQREF~\ANYEQREF] \to [\I32] + C \vdashinstr \REFEQ : [\EQREF~\EQREF] \to [\I32] } diff --git a/document/js-api/index.bs b/document/js-api/index.bs index ead9036207..611e812c5d 100644 --- a/document/js-api/index.bs +++ b/document/js-api/index.bs @@ -143,7 +143,7 @@ urlPrefix: https://webassembly.github.io/spec/core/; spec: WebAssembly; type: df text: 𝖿𝟨𝟦 url: syntax/types.html#syntax-reftype text: anyref - text: anyeqref + text: eqref text: anyfunc text: function element; url: exec/runtime.html#syntax-funcelem text: import component; url: syntax/modules.html#imports @@ -600,7 +600,7 @@ which can be simultaneously referenced by multiple {{Instance}} objects. Each
 enum TableKind {
   "anyref",
-  "anyeqref",
+  "eqref",
   "anyfunc",
   // Note: More values may be added in future iterations,
   // e.g., typed function references, typed GC references
@@ -823,9 +823,8 @@ Assert: |type| is not [=𝗂𝟨𝟦=].
     1. Let |f64| be ? [=ToNumber=](|v|).
     1. Return [=𝖿𝟨𝟦.𝖼𝗈𝗇𝗌𝗍=] |f64|.
 1. If |type| is [=anyref=],
-    1. If |v| is a primitive value but not a string, symbol, or null, throw |error|.
     1. Return the result of [=allocating a host address=] for |v|.
-1. If |type| is [=anyeqref=],
+1. If |type| is [=eqref=],
     1. If |v| is a primitive value but not a symbol or null, throw |error|.
     1. Return the result of [=allocating a host address=] for |v|.
 1. If |type| is [=anyfunc=],
diff --git a/interpreter/README.md b/interpreter/README.md
index c2b656ba22..23f5a3709e 100644
--- a/interpreter/README.md
+++ b/interpreter/README.md
@@ -184,7 +184,7 @@ align: align=(1|2|4|8|...)
 cvtop: trunc_s | trunc_u | extend_s | extend_u | ...
 
 num_type: i32 | i64 | f32 | f64
-ref_type: anyref | anyfunc | anyeqref
+ref_type: anyref | anyfunc | eqref
 val_type: num_type | ref_type
 block_type : ( result * )*
 func_type:   ( type  )? * *
diff --git a/interpreter/binary/decode.ml b/interpreter/binary/decode.ml
index 6648f6735b..84e3d98b4e 100644
--- a/interpreter/binary/decode.ml
+++ b/interpreter/binary/decode.ml
@@ -143,7 +143,7 @@ let ref_type s =
   match vs7 s with
   | -0x10 -> AnyFuncType
   | -0x11 -> AnyRefType
-  | -0x12 -> AnyEqRefType
+  | -0x12 -> EqRefType
   | _ -> error s (pos s - 1) "invalid reference type"
 
 let value_type s =
diff --git a/interpreter/binary/encode.ml b/interpreter/binary/encode.ml
index d074433559..d27b7e3263 100644
--- a/interpreter/binary/encode.ml
+++ b/interpreter/binary/encode.ml
@@ -99,7 +99,7 @@ let encode m =
     let ref_type = function
       | AnyFuncType -> vs7 (-0x10)
       | AnyRefType -> vs7 (-0x11)
-      | AnyEqRefType -> vs7 (-0x12)
+      | EqRefType -> vs7 (-0x12)
       | NullRefType -> assert false
 
     let value_type = function
diff --git a/interpreter/script/js.ml b/interpreter/script/js.ml
index 5739c5614c..4d6ea4d0a4 100644
--- a/interpreter/script/js.ml
+++ b/interpreter/script/js.ml
@@ -329,9 +329,9 @@ let wrap item_name wrap_action wrap_assertion at =
   let item = Lib.List32.length itypes @@ at in
   let types =
     (FuncType ([], []) @@ at) ::
-    (FuncType ([NumType I32Type], [RefType AnyEqRefType]) @@ at) ::
-    (FuncType ([RefType AnyEqRefType], [NumType I32Type]) @@ at) ::
-    (FuncType ([RefType AnyEqRefType], [NumType I32Type]) @@ at) ::
+    (FuncType ([NumType I32Type], [RefType EqRefType]) @@ at) ::
+    (FuncType ([RefType EqRefType], [NumType I32Type]) @@ at) ::
+    (FuncType ([RefType EqRefType], [NumType I32Type]) @@ at) ::
     itypes
   in
   let imports =
diff --git a/interpreter/script/script.ml b/interpreter/script/script.ml
index af96ee0080..02f8b16059 100644
--- a/interpreter/script/script.ml
+++ b/interpreter/script/script.ml
@@ -50,7 +50,7 @@ exception Syntax of Source.region * string
 let () =
   let type_of_ref' = !Values.type_of_ref' in
   Values.type_of_ref' := function
-    | HostRef _ -> Types.AnyEqRefType
+    | HostRef _ -> Types.EqRefType
     | r -> type_of_ref' r
 
 let () =
diff --git a/interpreter/syntax/types.ml b/interpreter/syntax/types.ml
index 39db555bd0..4bd628a66a 100644
--- a/interpreter/syntax/types.ml
+++ b/interpreter/syntax/types.ml
@@ -1,7 +1,7 @@
 (* Types *)
 
 type num_type = I32Type | I64Type | F32Type | F64Type
-type ref_type = NullRefType | AnyEqRefType | AnyRefType | AnyFuncType
+type ref_type = NullRefType | EqRefType | AnyRefType | AnyFuncType
 type value_type = NumType of num_type | RefType of ref_type
 type stack_type = value_type list
 type func_type = FuncType of stack_type * stack_type
@@ -137,7 +137,7 @@ let string_of_num_type = function
 
 let string_of_ref_type = function
   | NullRefType -> "nullref"
-  | AnyEqRefType -> "anyeqref"
+  | EqRefType -> "eqref"
   | AnyRefType -> "anyref"
   | AnyFuncType -> "anyfunc"
 
diff --git a/interpreter/text/lexer.mll b/interpreter/text/lexer.mll
index fefb13eae1..f063c35f3a 100644
--- a/interpreter/text/lexer.mll
+++ b/interpreter/text/lexer.mll
@@ -160,8 +160,8 @@ rule token = parse
   | '"'character*'\\'_
     { error_nest (Lexing.lexeme_end_p lexbuf) lexbuf "illegal escape" }
 
+  | "eqref" { EQREF }
   | "anyref" { ANYREF }
-  | "anyeqref" { ANYEQREF }
   | "anyfunc" { ANYFUNC }
   | (nxx as t) { NUM_TYPE (num_type t) }
   | "mut" { MUT }
diff --git a/interpreter/text/parser.mly b/interpreter/text/parser.mly
index 13e646b1ea..f932c155ca 100644
--- a/interpreter/text/parser.mly
+++ b/interpreter/text/parser.mly
@@ -147,7 +147,7 @@ let inline_type_explicit (c : context) x ft at =
 
 %token LPAR RPAR
 %token NAT INT FLOAT STRING VAR
-%token ANYREF ANYEQREF ANYFUNC NUM_TYPE MUT
+%token EQREF ANYREF ANYFUNC NUM_TYPE MUT
 %token NOP DROP BLOCK END IF THEN ELSE SELECT LOOP BR BR_IF BR_TABLE
 %token CALL CALL_INDIRECT RETURN
 %token GET_LOCAL SET_LOCAL TEE_LOCAL GET_GLOBAL SET_GLOBAL GET_TABLE SET_TABLE
@@ -205,8 +205,8 @@ string_list :
 /* Types */
 
 ref_type :
+  | EQREF { EqRefType }
   | ANYREF { AnyRefType }
-  | ANYEQREF { AnyEqRefType }
   | ANYFUNC { AnyFuncType }
 
 value_type :
diff --git a/interpreter/valid/valid.ml b/interpreter/valid/valid.ml
index e0ff3e888c..85ced4fec5 100644
--- a/interpreter/valid/valid.ml
+++ b/interpreter/valid/valid.ml
@@ -74,11 +74,17 @@ let match_type t1 t2 =
   | Some t1, Some t2 -> match_value_type t1 t2
   | _, _ -> true
 
-let join_type t1 t2 =
+let join_type t1 t2 at =
   match t1, t2 with
   | _, None -> t1
   | None, _ -> t2
-  | Some t1, Some t2 -> join_value_type t1 t2
+  | Some t1', Some t2' ->
+    let t = join_value_type t1' t2' in
+    require (t <> None) at
+      ("type mismatch: operator requires common supertype for " ^
+       string_of_infer_type t1 ^ " and " ^ string_of_infer_type t2 ^
+       " but none exists");
+    t
 
 let check_stack ts1 ts2 at =
   require
@@ -217,7 +223,13 @@ let rec check_instr (c : context) (e : instr) (s : infer_stack_type) : op_type =
 
   | BrTable (xs, x) ->
     let ts =
-      List.fold_left (fun t1 t2 -> Lib.Option.get (meet_stack_type t1 t2) t1)
+      List.fold_left (fun t1 t2 ->
+          let t = meet_stack_type t1 t2 in
+          require (t <> None) e.at
+            ("type mismatch: operator requires common subtype for " ^
+             string_of_stack_type t1 ^ " and " ^ string_of_stack_type t2 ^
+             " but none exists");
+          Lib.Option.force t)
         (label c x) (List.map (label c) xs)
     in
     check_stack (known ts) (known (label c x)) x.at;
@@ -243,9 +255,9 @@ let rec check_instr (c : context) (e : instr) (s : infer_stack_type) : op_type =
     [peek 0 s] -~> []
 
   | Select ->
-    let t1 = peek 1 s in
-    let t2 = peek 0 s in
-    let t = join_type t1 t2 in
+    let t1 = peek 2 s in
+    let t2 = peek 1 s in
+    let t = join_type t1 t2 e.at in
     [t; t; Some (NumType I32Type)] -~> [t]
 
   | GetLocal x ->
@@ -297,7 +309,7 @@ let rec check_instr (c : context) (e : instr) (s : infer_stack_type) : op_type =
     [RefType AnyRefType] --> [NumType I32Type]
 
   | Same ->
-    [RefType AnyEqRefType; RefType AnyEqRefType] --> [NumType I32Type]
+    [RefType EqRefType; RefType EqRefType] --> [NumType I32Type]
 
   | Const v ->
     let t = NumType (type_num v.it) in
diff --git a/proposals/reference-types/Overview.md b/proposals/reference-types/Overview.md
index 3675bd7b36..741f609276 100644
--- a/proposals/reference-types/Overview.md
+++ b/proposals/reference-types/Overview.md
@@ -97,8 +97,8 @@ Table extensions:
 
 API extensions:
 
-* Any JS object (non-primitive value) or string or symbol or `null` can be passed as `anyref` to a Wasm function, stored in a global, or in a table.
-  - It may be possible to allow all other non-primitive values as well, depending on details of existing engines.
+* Any JS value can be passed as `anyref` to a Wasm function, stored in a global, or in a table.
+  - Is it worth considering that restricting this to non-primitive values might allow engines to use techniques like pointer compression.
 
 * Any Wasm exported function object or `null` can be passed as `anyfunc` to a Wasm function, stored in a global, or in a table.
 
@@ -116,17 +116,17 @@ Motivation:
 
 Additions:
 
-* Add `anyeqref` as the type of comparable references
-  - `reftype ::= ... | anyeqref`
+* Add `eqref` as the type of comparable references
+  - `reftype ::= ... | eqref`
 * It is a subtype of `anyref`
-  - `anyeqref < anyref`
-  - `nullref < anyeqref`
+  - `eqref < anyref`
+  - `nullref < eqref`
 * Add `ref.eq` instruction.
-  - `ref.eq : [anyeqref anyeqref] -> [i32]`
+  - `ref.eq : [eqref eqref] -> [i32]`
 
 API changes:
 
-* Any JS object (non-primitive value) or `null` can be passed as `anyeqref` to a Wasm function, stored in a global, or in a table.
+* Any JS object (non-primitive value) or symbol or `null` can be passed as `eqref` to a Wasm function, stored in a global, or in a table.
 
 
 Questions:
@@ -154,7 +154,7 @@ Additions:
 * Subtying between concrete and universal reference types
   - `ref $t < anyref`
   - `ref  < anyfunc`
-  - Note: reference types are not necessarily subtypes of `anyeqref`, including functions
+  - Note: reference types are not necessarily subtypes of `eqref`, including functions
 
 * Typed function references cannot be null!
 
diff --git a/test/core/br_table.wast b/test/core/br_table.wast
index 086c3c32ee..dfb3c77c7c 100644
--- a/test/core/br_table.wast
+++ b/test/core/br_table.wast
@@ -1237,9 +1237,9 @@
     )
   )
 
-  (func (export "meet-anyeqref") (param i32) (param anyeqref) (result anyref)
+  (func (export "meet-eqref") (param i32) (param eqref) (result anyref)
     (block $l1 (result anyref)
-      (block $l2 (result anyeqref)
+      (block $l2 (result eqref)
         (br_table $l1 $l2 $l1 (get_local 1) (get_local 0))
       )
     )
@@ -1255,7 +1255,7 @@
 
   (func (export "meet-nullref") (param i32) (result anyref)
     (block $l1 (result anyref)
-      (block $l2 (result anyeqref)
+      (block $l2 (result eqref)
         (drop
           (block $l3 (result anyfunc)
             (br_table $l1 $l2 $l3 (ref.null) (get_local 0))
@@ -1450,9 +1450,9 @@
 (assert_return (invoke "meet-anyref" (i32.const 1) (ref.host 1)) (ref.host 1))
 (assert_return (invoke "meet-anyref" (i32.const 2) (ref.host 1)) (ref.host 1))
 
-(assert_return (invoke "meet-anyeqref" (i32.const 0) (ref.host 1)) (ref.host 1))
-(assert_return (invoke "meet-anyeqref" (i32.const 1) (ref.host 1)) (ref.host 1))
-(assert_return (invoke "meet-anyeqref" (i32.const 2) (ref.host 1)) (ref.host 1))
+(assert_return (invoke "meet-eqref" (i32.const 0) (ref.host 1)) (ref.host 1))
+(assert_return (invoke "meet-eqref" (i32.const 1) (ref.host 1)) (ref.host 1))
+(assert_return (invoke "meet-eqref" (i32.const 2) (ref.host 1)) (ref.host 1))
 
 (assert_return_func (invoke "meet-anyfunc" (i32.const 0)))
 (assert_return_func (invoke "meet-anyfunc" (i32.const 1)))
diff --git a/test/core/globals.wast b/test/core/globals.wast
index 5ce11544fb..e61f2857e6 100644
--- a/test/core/globals.wast
+++ b/test/core/globals.wast
@@ -13,17 +13,17 @@
 
   (global $r anyref (ref.null))
   (global anyfunc (ref.null))
-  (global $z (mut anyeqref) (ref.null))
+  (global $z (mut eqref) (ref.null))
 
   (func (export "get-a") (result i32) (get_global $a))
   (func (export "get-b") (result i64) (get_global $b))
   (func (export "get-r") (result anyref) (get_global $r))
   (func (export "get-x") (result i32) (get_global $x))
   (func (export "get-y") (result i64) (get_global $y))
-  (func (export "get-z") (result anyeqref) (get_global $z))
+  (func (export "get-z") (result eqref) (get_global $z))
   (func (export "set-x") (param i32) (set_global $x (get_local 0)))
   (func (export "set-y") (param i64) (set_global $y (get_local 0)))
-  (func (export "set-z") (param anyeqref) (set_global $z (get_local 0)))
+  (func (export "set-z") (param eqref) (set_global $z (get_local 0)))
 
   (func (export "get-1") (result f32) (get_global 1))
   (func (export "get-2") (result f64) (get_global 2))
@@ -123,7 +123,7 @@
 )
 
 (assert_invalid
-  (module (global (import "" "") anyref) (global anyeqref (get_global 0)))
+  (module (global (import "" "") anyref) (global eqref (get_global 0)))
   "type mismatch"
 )
 
diff --git a/test/core/linking.wast b/test/core/linking.wast
index 5f47ce677f..20fc94695c 100644
--- a/test/core/linking.wast
+++ b/test/core/linking.wast
@@ -59,9 +59,9 @@
 (assert_return (invoke $Ng "get") (i32.const 43))
 
 (module $Mref-ex
-  (global (export "g-const") anyeqref (ref.null))
+  (global (export "g-const") eqref (ref.null))
   ;; Mutable globals cannot be exported yet
-  ;; (global (export "g-var") (mut anyeqref) (ref.null))
+  ;; (global (export "g-var") (mut eqref) (ref.null))
 )
 (register "Mref-ex" $Mref-ex)
 
diff --git a/test/core/select.wast b/test/core/select.wast
index 7d9a4ac0ec..35553b68f6 100644
--- a/test/core/select.wast
+++ b/test/core/select.wast
@@ -35,7 +35,7 @@
     (select (ref.null) (ref.null) (get_local 0))
   )
 
-  (func (export "join-anyeqref") (param i32) (param anyeqref) (result anyref)
+  (func (export "join-eqref") (param i32) (param eqref) (result anyref)
     (select (get_local 1) (ref.null) (get_local 0))
   )
 
@@ -43,7 +43,7 @@
     (select (get_table $tab (i32.const 0)) (ref.null) (get_local 0))
   )
 
-  (func (export "join-anyref") (param i32) (param anyeqref) (result anyref)
+  (func (export "join-anyref") (param i32) (param eqref) (result anyref)
     (select (get_table $tab (i32.const 0)) (get_local 1) (get_local 0))
   )
 )
@@ -79,8 +79,8 @@
 (assert_return (invoke "join-nullref" (i32.const 1)) (ref.null))
 (assert_return (invoke "join-nullref" (i32.const 0)) (ref.null))
 
-(assert_return (invoke "join-anyeqref" (i32.const 1) (ref.host 1)) (ref.host 1))
-(assert_return (invoke "join-anyeqref" (i32.const 0) (ref.host 1)) (ref.null))
+(assert_return (invoke "join-eqref" (i32.const 1) (ref.host 1)) (ref.host 1))
+(assert_return (invoke "join-eqref" (i32.const 0) (ref.host 1)) (ref.null))
 
 (assert_return_func (invoke "join-anyfunc" (i32.const 1)))
 (assert_return (invoke "join-anyfunc" (i32.const 0)) (ref.null))

From cf1826f831a50e527c0292d70ce767cd6fe663a3 Mon Sep 17 00:00:00 2001
From: Ben Smith 
Date: Tue, 1 May 2018 11:40:03 -0700
Subject: [PATCH 018/199] Add instruction encoding to overview

Also fix some typos I noticed.
---
 proposals/bulk-memory-operations/Overview.md | 16 ++++++++++++++--
 1 file changed, 14 insertions(+), 2 deletions(-)

diff --git a/proposals/bulk-memory-operations/Overview.md b/proposals/bulk-memory-operations/Overview.md
index 9a93c9d905..c1cfd44dac 100644
--- a/proposals/bulk-memory-operations/Overview.md
+++ b/proposals/bulk-memory-operations/Overview.md
@@ -175,9 +175,9 @@ 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
+* `table.init`: copy a region from an element segment
 
-An passive segment has no initializer expression, since it will be specified
+A passive segment has no initializer expression, since it will be specified
 as an operand to `mem.init` or `table.init`.
 
 Passive segments can also be discarded by using the following new instructions:
@@ -282,3 +282,15 @@ implemented as follows:
     (mem.drop 1))
 )
 ```
+
+### Instruction encoding
+
+| Name | Opcode | Immediate | Description |
+| ---- | ---- | ---- | ---- |
+| `mem.init` | `0xfc` | `0x08` | :thinking: copy from a passive data segment to linear memory |
+| `mem.drop` | `0xfc` | `0x09` | :thinking: prevent further use of passive data segment |
+| `mem.copy` | `0xfc` | `0x0a` | :thinking: copy from one region of linear memory to another region |
+| `mem.fill` | `0xfc` | `0x0b` | :thinking: fill a region of linear memory with a given byte value |
+| `table.init` | `0xfc` | `0x0c` | :thinking: copy from a passive element segment to a table |
+| `table.drop` | `0xfc` | `0x0d` | :thinking: prevent further use of a passive element segment |
+| `table.copy` | `0xfc` | `0x0e` | :thinking: copy from one region of a table to another region |

From ab760d0d26bc9bd0f77999ee2f9faa60d879b384 Mon Sep 17 00:00:00 2001
From: Andreas Rossberg 
Date: Fri, 4 May 2018 08:12:19 +0200
Subject: [PATCH 019/199] Remove ref.eq (#12)

---
 document/core/appendix/algorithm.rst          |  9 +---
 document/core/appendix/index-instructions.rst |  1 -
 document/core/appendix/index-types.rst        |  1 -
 document/core/binary/instructions.rst         |  4 +-
 document/core/binary/types.rst                |  3 +-
 document/core/exec/instructions.rst           | 28 -----------
 document/core/syntax/instructions.rst         |  4 +-
 document/core/syntax/types.rst                |  5 +-
 document/core/text/instructions.rst           |  4 +-
 document/core/text/types.rst                  |  3 +-
 document/core/util/macros.def                 |  2 -
 document/core/valid/instructions.rst          | 14 ------
 interpreter/README.md                         |  2 +-
 interpreter/binary/decode.ml                  |  2 -
 interpreter/binary/encode.ml                  |  2 -
 interpreter/exec/eval.ml                      |  6 ---
 interpreter/script/js.ml                      | 19 ++++---
 interpreter/script/script.ml                  |  2 +-
 interpreter/syntax/ast.ml                     |  1 -
 interpreter/syntax/operators.ml               |  2 -
 interpreter/syntax/types.ml                   |  3 +-
 interpreter/text/arrange.ml                   |  1 -
 interpreter/text/lexer.mll                    |  2 -
 interpreter/text/parser.mly                   |  6 +--
 interpreter/valid/valid.ml                    |  3 --
 proposals/reference-types/Overview.md         |  4 +-
 test/core/br_table.wast                       | 29 -----------
 test/core/get_table.wast                      | 12 +----
 test/core/globals.wast                        |  8 +--
 test/core/linking.wast                        |  4 +-
 test/core/ref_eq.wast                         | 50 -------------------
 test/core/ref_isnull.wast                     | 17 +------
 test/core/ref_null.wast                       |  2 -
 test/core/select.wast                         |  9 +---
 test/core/set_table.wast                      | 17 -------
 35 files changed, 32 insertions(+), 249 deletions(-)
 delete mode 100644 test/core/ref_eq.wast

diff --git a/document/core/appendix/algorithm.rst b/document/core/appendix/algorithm.rst
index 0afd6e360d..363656edc5 100644
--- a/document/core/appendix/algorithm.rst
+++ b/document/core/appendix/algorithm.rst
@@ -33,11 +33,11 @@ A type error is encountered if a join or meet is required when it does not exist
 
 .. code-block:: pseudo
 
-   type val_type = I32 | I64 | F32 | F64 | Anyref | Anyfunc | Eqref | Nullref
+   type val_type = I32 | I64 | F32 | F64 | Anyref | Anyfunc | Nullref
    type opd_type = val_type | Unknown
 
    func is_ref(t : opd_type) : bool =
-     return t = Anyref || t = Anyfunc || t = Eqref || t = Nullref
+     return t = Anyref || t = Anyfunc || t = Nullref
 
    func matches(t1 : opd_type, t2 : opd_type) : bool =
      return t1 = t2 || t1 = Unknown ||
@@ -180,11 +180,6 @@ Other instructions are checked in a similar manner.
          pop_opd(I32)
          push_opd(I32)
 
-       case (ref.eq)
-         pop_opd(Eqref)
-         pop_opd(Eqref)
-         push_opd(I32)
-
        case (drop)
          pop_opd()
 
diff --git a/document/core/appendix/index-instructions.rst b/document/core/appendix/index-instructions.rst
index 5122891981..aadaa1664f 100644
--- a/document/core/appendix/index-instructions.rst
+++ b/document/core/appendix/index-instructions.rst
@@ -217,6 +217,5 @@ Instruction                          Binary Opcode     Type
 (reserved)                           :math:`\hex{CF}`                                                  
 :math:`\REFNULL`                     :math:`\hex{D0}`  :math:`[] \to [\NULLREF]`                   :ref:`validation `        :ref:`execution `
 :math:`\REFISNULL`                   :math:`\hex{D1}`  :math:`[\ANYREF] \to [\I32]`                :ref:`validation `      :ref:`execution `
-:math:`\REFEQ`                       :math:`\hex{D2}`  :math:`[\EQREF~\EQREF] \to [\I32]`          :ref:`validation `          :ref:`execution `
 ===================================  ================  ==========================================  ========================================  ===============================================================
 
diff --git a/document/core/appendix/index-types.rst b/document/core/appendix/index-types.rst
index bfaccf1645..049eae4efc 100644
--- a/document/core/appendix/index-types.rst
+++ b/document/core/appendix/index-types.rst
@@ -15,7 +15,6 @@ Category                                  Constructor
 (reserved)                                                                             :math:`\hex{7B}` .. :math:`\hex{71}`
 :ref:`Reference type `    |ANYFUNC|                                    :math:`\hex{70}` (-16 as |Bs7|)
 :ref:`Reference type `    |ANYREF|                                     :math:`\hex{6F}` (-17 as |Bs7|)
-:ref:`Reference type `    |EQREF|                                      :math:`\hex{6E}` (-18 as |Bs7|)
 (reserved)                                                                             :math:`\hex{6D}` .. :math:`\hex{61}`
 :ref:`Function type `    :math:`[\valtype^\ast] \to [\valtype^\ast]`  :math:`\hex{60}` (-32 as |Bs7|)
 (reserved)                                                                             :math:`\hex{5F}` .. :math:`\hex{41}`
diff --git a/document/core/binary/instructions.rst b/document/core/binary/instructions.rst
index e83c57ac17..542ab305ce 100644
--- a/document/core/binary/instructions.rst
+++ b/document/core/binary/instructions.rst
@@ -72,14 +72,12 @@ Reference Instructions
 
 .. _binary-ref_null:
 .. _binary-ref_isnull:
-.. _binary-ref_eq:
 
 .. math::
    \begin{array}{llclll}
    \production{instruction} & \Binstr &::=& \dots \\ &&|&
      \hex{D0} &\Rightarrow& \REFNULL \\ &&|&
-     \hex{D1} &\Rightarrow& \REFISNULL \\ &&|&
-     \hex{D2} &\Rightarrow& \REFEQ \\
+     \hex{D1} &\Rightarrow& \REFISNULL \\
    \end{array}
 
 .. note::
diff --git a/document/core/binary/types.rst b/document/core/binary/types.rst
index e5fe814a7a..7784e9830d 100644
--- a/document/core/binary/types.rst
+++ b/document/core/binary/types.rst
@@ -42,8 +42,7 @@ Reference Types
    \begin{array}{llclll@{\qquad\qquad}l}
    \production{reference type} & \Breftype &::=&
      \hex{70} &\Rightarrow& \ANYFUNC \\ &&|&
-     \hex{6F} &\Rightarrow& \ANYREF \\ &&|&
-     \hex{6E} &\Rightarrow& \EQREF \\
+     \hex{6F} &\Rightarrow& \ANYREF \\
    \end{array}
 
 
diff --git a/document/core/exec/instructions.rst b/document/core/exec/instructions.rst
index 41620bd08e..91da2290db 100644
--- a/document/core/exec/instructions.rst
+++ b/document/core/exec/instructions.rst
@@ -219,34 +219,6 @@ Reference Instructions
    \end{array}
 
 
-.. _exec-ref_eq:
-
-:math:`\REFEQ`
-..............
-
-1. Assert: due to :ref:`validation `, two :ref:`reference values ` are on the top of the stack.
-
-2. Pop the value :math:`\val_2` from the stack.
-
-3. Pop the value :math:`\val_1` from the stack.
-
-3. If :math:`\val_1` is the same as :math:`\val_2`, then:
-
-   a. Push the value :math:`\I32.\CONST~1` to the stack.
-
-4. Else:
-
-   a. Push the value :math:`\I32.\CONST~0` to the stack.
-
-.. math::
-   \begin{array}{lcl@{\qquad}l}
-   \val_1~\val_2~\REFEQ &\stepto& \I32.\CONST~1
-     & (\iff \val_1 = \val_2) \\
-   \val_1~\val_2~\REFEQ &\stepto& \I32.\CONST~0
-     & (\iff \val_1 \neq \val_2) \\
-   \end{array}
-
-
 .. index:: parametric instructions, value
    pair: execution; instruction
    single: abstract syntax; instruction
diff --git a/document/core/syntax/instructions.rst b/document/core/syntax/instructions.rst
index 3fc2996eaa..44a4778a14 100644
--- a/document/core/syntax/instructions.rst
+++ b/document/core/syntax/instructions.rst
@@ -170,7 +170,6 @@ Occasionally, it is convenient to group operators together according to the foll
    pair: abstract syntax; instruction
 .. _syntax-ref_null:
 .. _syntax-ref_isnull:
-.. _syntax-ref_eq:
 .. _syntax-instr-ref:
 
 Reference Instructions
@@ -183,8 +182,7 @@ Instructions in this group are concerned with accessing :ref:`references ` of all other reference types.
 
 The type |ANYFUNC| denotes the infinite union of all references to :ref:`functions `, regardless of their :ref:`function types `.
 
-The type |EQREF| denotes the infinite union of all references that can be compared for equality;
-in order to avoid exposing implementation details, some reference types, such as |ANYFUNC|, do not admit equality, and therefore are not :ref:`subtypes ` of |EQREF|.
-
 The type |NULLREF| only contains a single value: the :ref:`null ` reference.
 It is a :ref:`subtype ` of all other reference types.
 By virtue of not being representable in either the :ref:`binary format ` nor the :ref:`text format `, the |NULLREF| type cannot be used in a program;
diff --git a/document/core/text/instructions.rst b/document/core/text/instructions.rst
index ddf773a070..973ca78449 100644
--- a/document/core/text/instructions.rst
+++ b/document/core/text/instructions.rst
@@ -138,14 +138,12 @@ Reference Instructions
 
 .. _text-ref_null:
 .. _text-ref_isnull:
-.. _text-ref_eq:
 
 .. math::
    \begin{array}{llclll}
    \production{instruction} & \Tplaininstr_I &::=& \dots \\ &&|&
      \text{ref.null} &\Rightarrow& \REFNULL \\ &&|&
-     \text{ref.isnull} &\Rightarrow& \REFISNULL \\ &&|&
-     \text{ref.eq} &\Rightarrow& \REFEQ \\
+     \text{ref.isnull} &\Rightarrow& \REFISNULL \\
    \end{array}
 
 
diff --git a/document/core/text/types.rst b/document/core/text/types.rst
index 1e8881aee4..0f0cb600ea 100644
--- a/document/core/text/types.rst
+++ b/document/core/text/types.rst
@@ -33,8 +33,7 @@ Reference Types
    \begin{array}{llcll@{\qquad\qquad}l}
    \production{reference type} & \Treftype &::=&
      \text{anyref} &\Rightarrow& \ANYREF \\ &&|&
-     \text{anyfunc} &\Rightarrow& \ANYFUNC \\ &&|&
-     \text{eqref} &\Rightarrow& \EQREF \\
+     \text{anyfunc} &\Rightarrow& \ANYFUNC \\
    \end{array}
 
 
diff --git a/document/core/util/macros.def b/document/core/util/macros.def
index c9cc2cfb5a..9a7ea35234 100644
--- a/document/core/util/macros.def
+++ b/document/core/util/macros.def
@@ -173,7 +173,6 @@
 
 .. |ANYREF| mathdef:: \xref{syntax/types}{syntax-reftype}{\K{anyref}}
 .. |ANYFUNC| mathdef:: \xref{syntax/types}{syntax-reftype}{\K{anyfunc}}
-.. |EQREF| mathdef:: \xref{syntax/types}{syntax-reftype}{\K{eqref}}
 .. |NULLREF| mathdef:: \xref{syntax/types}{syntax-reftype}{\K{nullref}}
 
 .. |MVAR| mathdef:: \xref{syntax/types}{syntax-mut}{\K{var}}
@@ -337,7 +336,6 @@
 
 .. |REFNULL| mathdef:: \xref{syntax/instructions}{syntax-instr-ref}{\K{ref{.}null}}
 .. |REFISNULL| mathdef:: \xref{syntax/instructions}{syntax-instr-ref}{\K{ref{.}isnull}}
-.. |REFEQ| mathdef:: \xref{syntax/instructions}{syntax-instr-ref}{\K{ref{.}eq}}
 
 .. |CONST| mathdef:: \xref{syntax/instructions}{syntax-instr-numeric}{\K{const}}
 .. |EQZ| mathdef:: \xref{syntax/instructions}{syntax-instr-numeric}{\K{eqz}}
diff --git a/document/core/valid/instructions.rst b/document/core/valid/instructions.rst
index a24719dcac..3cb54a5f37 100644
--- a/document/core/valid/instructions.rst
+++ b/document/core/valid/instructions.rst
@@ -190,20 +190,6 @@ Reference Instructions
    }
 
 
-.. _valid-ref_eq:
-
-:math:`\REFEQ`
-..............
-
-* The instruction is valid with type :math:`[\EQREF~\EQREF] \to [\I32]`.
-
-.. math::
-   \frac{
-   }{
-     C \vdashinstr \REFEQ : [\EQREF~\EQREF] \to [\I32]
-   }
-
-
 
 .. index:: parametric instructions, value type, polymorphism
    pair: validation; instruction
diff --git a/interpreter/README.md b/interpreter/README.md
index 23f5a3709e..c2eef28fa1 100644
--- a/interpreter/README.md
+++ b/interpreter/README.md
@@ -184,7 +184,7 @@ align: align=(1|2|4|8|...)
 cvtop: trunc_s | trunc_u | extend_s | extend_u | ...
 
 num_type: i32 | i64 | f32 | f64
-ref_type: anyref | anyfunc | eqref
+ref_type: anyref | anyfunc
 val_type: num_type | ref_type
 block_type : ( result * )*
 func_type:   ( type  )? * *
diff --git a/interpreter/binary/decode.ml b/interpreter/binary/decode.ml
index 84e3d98b4e..9d3fe80238 100644
--- a/interpreter/binary/decode.ml
+++ b/interpreter/binary/decode.ml
@@ -143,7 +143,6 @@ let ref_type s =
   match vs7 s with
   | -0x10 -> AnyFuncType
   | -0x11 -> AnyRefType
-  | -0x12 -> EqRefType
   | _ -> error s (pos s - 1) "invalid reference type"
 
 let value_type s =
@@ -447,7 +446,6 @@ let rec instr s =
   (* TODO: Allocate more adequate opcodes *)
   | 0xd0 -> ref_null
   | 0xd1 -> ref_isnull
-  | 0xd2 -> ref_eq
 
   | b -> illegal s pos b
 
diff --git a/interpreter/binary/encode.ml b/interpreter/binary/encode.ml
index d27b7e3263..496a0aab7e 100644
--- a/interpreter/binary/encode.ml
+++ b/interpreter/binary/encode.ml
@@ -99,7 +99,6 @@ let encode m =
     let ref_type = function
       | AnyFuncType -> vs7 (-0x10)
       | AnyRefType -> vs7 (-0x11)
-      | EqRefType -> vs7 (-0x12)
       | NullRefType -> assert false
 
     let value_type = function
@@ -376,7 +375,6 @@ let encode m =
       (* TODO: Allocate more adequate opcodes *)
       | Null -> op 0xd0
       | IsNull -> op 0xd1
-      | Same -> op 0xd2
 
     let const c =
       list instr c.it; end_ ()
diff --git a/interpreter/exec/eval.ml b/interpreter/exec/eval.ml
index b601d80494..f0c300aa08 100644
--- a/interpreter/exec/eval.ml
+++ b/interpreter/exec/eval.ml
@@ -248,12 +248,6 @@ let rec step (c : config) : config =
       | IsNull, v :: vs' ->
         Num (I32 0l) :: vs', []
 
-      | Same, Ref r2 :: Ref r1 :: vs' when r1 = r2 ->
-        Num (I32 1l) :: vs', []
-
-      | Same, Ref r2 :: Ref r1 :: vs' ->
-        Num (I32 0l) :: vs', []
-
       | Const n, vs ->
         Num n.it :: vs, []
 
diff --git a/interpreter/script/js.ml b/interpreter/script/js.ml
index 4d6ea4d0a4..2aed6cae46 100644
--- a/interpreter/script/js.ml
+++ b/interpreter/script/js.ml
@@ -220,7 +220,8 @@ let subject_idx = 0l
 let hostref_idx = 1l
 let _is_hostref_idx = 2l
 let is_funcref_idx = 3l
-let subject_type_idx = 4l
+let eq_ref_idx = 4l
+let subject_type_idx = 5l
 
 let eq_of = function
   | I32Type -> Values.I32 I32Op.Eq
@@ -282,7 +283,7 @@ let assert_return vs ts at =
     | Values.Ref (HostRef n) ->
       [ Const (Values.I32 n @@ at) @@ at;
         Call (hostref_idx @@ at) @@ at;
-        Same @@ at;
+        Call (eq_ref_idx @@ at)  @@ at;
         Test (Values.I32 I32Op.Eqz) @@ at;
         BrIf (0l @@ at) @@ at ]
     | _ -> assert false
@@ -309,8 +310,7 @@ let assert_return_ref ts at =
   let test = function
     | NumType _ -> [Br (0l @@ at) @@ at]
     | RefType _ ->
-      [ Null @@ at;
-        Same @@ at;
+      [ IsNull @@ at;
         BrIf (0l @@ at) @@ at ]
   in [], List.flatten (List.rev_map test ts)
 
@@ -329,9 +329,10 @@ let wrap item_name wrap_action wrap_assertion at =
   let item = Lib.List32.length itypes @@ at in
   let types =
     (FuncType ([], []) @@ at) ::
-    (FuncType ([NumType I32Type], [RefType EqRefType]) @@ at) ::
-    (FuncType ([RefType EqRefType], [NumType I32Type]) @@ at) ::
-    (FuncType ([RefType EqRefType], [NumType I32Type]) @@ at) ::
+    (FuncType ([NumType I32Type], [RefType AnyRefType]) @@ at) ::
+    (FuncType ([RefType AnyRefType], [NumType I32Type]) @@ at) ::
+    (FuncType ([RefType AnyRefType], [NumType I32Type]) @@ at) ::
+    (FuncType ([RefType AnyRefType; RefType AnyRefType], [NumType I32Type]) @@ at) ::
     itypes
   in
   let imports =
@@ -341,7 +342,9 @@ let wrap item_name wrap_action wrap_assertion at =
       {module_name = Utf8.decode "spectest"; item_name = Utf8.decode "is_hostref";
        idesc = FuncImport (2l @@ at) @@ at} @@ at;
       {module_name = Utf8.decode "spectest"; item_name = Utf8.decode "is_funcref";
-       idesc = FuncImport (3l @@ at) @@ at} @@ at ]
+       idesc = FuncImport (3l @@ at) @@ at} @@ at;
+      {module_name = Utf8.decode "spectest"; item_name = Utf8.decode "eq_ref";
+       idesc = FuncImport (4l @@ at) @@ at} @@ at ]
   in
   let edesc = FuncExport item @@ at in
   let exports = [{name = Utf8.decode "run"; edesc} @@ at] in
diff --git a/interpreter/script/script.ml b/interpreter/script/script.ml
index 02f8b16059..1739360368 100644
--- a/interpreter/script/script.ml
+++ b/interpreter/script/script.ml
@@ -50,7 +50,7 @@ exception Syntax of Source.region * string
 let () =
   let type_of_ref' = !Values.type_of_ref' in
   Values.type_of_ref' := function
-    | HostRef _ -> Types.EqRefType
+    | HostRef _ -> Types.AnyRefType
     | r -> type_of_ref' r
 
 let () =
diff --git a/interpreter/syntax/ast.ml b/interpreter/syntax/ast.ml
index 7b7837420c..7cc8bb34de 100644
--- a/interpreter/syntax/ast.ml
+++ b/interpreter/syntax/ast.ml
@@ -95,7 +95,6 @@ and instr' =
   | GrowMemory                        (* grow linear memory *)
   | Null                              (* null reference *)
   | IsNull                            (* null test *)
-  | Same                              (* reference equality *)
   | Const of literal                  (* constant *)
   | Test of testop                    (* numeric test *)
   | Compare of relop                  (* numeric comparison *)
diff --git a/interpreter/syntax/operators.ml b/interpreter/syntax/operators.ml
index 05253bb19d..5b7f4cd14a 100644
--- a/interpreter/syntax/operators.ml
+++ b/interpreter/syntax/operators.ml
@@ -10,9 +10,7 @@ let i64_const n = Const (I64 n.it @@ n.at)
 let f32_const n = Const (F32 n.it @@ n.at)
 let f64_const n = Const (F64 n.it @@ n.at)
 let ref_null = Null
-
 let ref_isnull = IsNull
-let ref_eq = Same
 
 let unreachable = Unreachable
 let nop = Nop
diff --git a/interpreter/syntax/types.ml b/interpreter/syntax/types.ml
index 4bd628a66a..679223d9b8 100644
--- a/interpreter/syntax/types.ml
+++ b/interpreter/syntax/types.ml
@@ -1,7 +1,7 @@
 (* Types *)
 
 type num_type = I32Type | I64Type | F32Type | F64Type
-type ref_type = NullRefType | EqRefType | AnyRefType | AnyFuncType
+type ref_type = NullRefType | AnyRefType | AnyFuncType
 type value_type = NumType of num_type | RefType of ref_type
 type stack_type = value_type list
 type func_type = FuncType of stack_type * stack_type
@@ -137,7 +137,6 @@ let string_of_num_type = function
 
 let string_of_ref_type = function
   | NullRefType -> "nullref"
-  | EqRefType -> "eqref"
   | AnyRefType -> "anyref"
   | AnyFuncType -> "anyfunc"
 
diff --git a/interpreter/text/arrange.ml b/interpreter/text/arrange.ml
index bd67ea0a3a..1179be1c34 100644
--- a/interpreter/text/arrange.ml
+++ b/interpreter/text/arrange.ml
@@ -251,7 +251,6 @@ let rec instr e =
     | GrowMemory -> "grow_memory", []
     | Null -> "ref.null", []
     | IsNull -> "ref.isnull", []
-    | Same -> "ref.eq", []
     | Const lit -> constop lit ^ " " ^ num lit, []
     | Test op -> testop op, []
     | Compare op -> relop op, []
diff --git a/interpreter/text/lexer.mll b/interpreter/text/lexer.mll
index f063c35f3a..01ebab60af 100644
--- a/interpreter/text/lexer.mll
+++ b/interpreter/text/lexer.mll
@@ -160,7 +160,6 @@ rule token = parse
   | '"'character*'\\'_
     { error_nest (Lexing.lexeme_end_p lexbuf) lexbuf "illegal escape" }
 
-  | "eqref" { EQREF }
   | "anyref" { ANYREF }
   | "anyfunc" { ANYFUNC }
   | (nxx as t) { NUM_TYPE (num_type t) }
@@ -181,7 +180,6 @@ rule token = parse
   | "ref.null" { REF_NULL }
   | "ref.host" { REF_HOST }
   | "ref.isnull" { REF_ISNULL }
-  | "ref.eq" { REF_EQ }
 
   | "nop" { NOP }
   | "unreachable" { UNREACHABLE }
diff --git a/interpreter/text/parser.mly b/interpreter/text/parser.mly
index f932c155ca..28d76b7ebc 100644
--- a/interpreter/text/parser.mly
+++ b/interpreter/text/parser.mly
@@ -147,12 +147,12 @@ let inline_type_explicit (c : context) x ft at =
 
 %token LPAR RPAR
 %token NAT INT FLOAT STRING VAR
-%token EQREF ANYREF ANYFUNC NUM_TYPE MUT
+%token ANYREF ANYFUNC NUM_TYPE MUT
 %token NOP DROP BLOCK END IF THEN ELSE SELECT LOOP BR BR_IF BR_TABLE
 %token CALL CALL_INDIRECT RETURN
 %token GET_LOCAL SET_LOCAL TEE_LOCAL GET_GLOBAL SET_GLOBAL GET_TABLE SET_TABLE
 %token LOAD STORE OFFSET_EQ_NAT ALIGN_EQ_NAT
-%token REF_NULL REF_HOST REF_ISNULL REF_EQ
+%token REF_NULL REF_HOST REF_ISNULL
 %token CONST UNARY BINARY TEST COMPARE CONVERT
 %token UNREACHABLE CURRENT_MEMORY GROW_MEMORY
 %token FUNC START TYPE PARAM RESULT LOCAL GLOBAL
@@ -205,7 +205,6 @@ string_list :
 /* Types */
 
 ref_type :
-  | EQREF { EqRefType }
   | ANYREF { AnyRefType }
   | ANYFUNC { AnyFuncType }
 
@@ -333,7 +332,6 @@ plain_instr :
   | GROW_MEMORY { fun c -> grow_memory }
   | REF_NULL { fun c -> ref_null }
   | REF_ISNULL { fun c -> ref_isnull }
-  | REF_EQ { fun c -> ref_eq }
   | CONST literal { fun c -> fst (literal $1 $2) }
   | TEST { fun c -> $1 }
   | COMPARE { fun c -> $1 }
diff --git a/interpreter/valid/valid.ml b/interpreter/valid/valid.ml
index 85ced4fec5..da56cd8bbb 100644
--- a/interpreter/valid/valid.ml
+++ b/interpreter/valid/valid.ml
@@ -308,9 +308,6 @@ let rec check_instr (c : context) (e : instr) (s : infer_stack_type) : op_type =
   | IsNull ->
     [RefType AnyRefType] --> [NumType I32Type]
 
-  | Same ->
-    [RefType EqRefType; RefType EqRefType] --> [NumType I32Type]
-
   | Const v ->
     let t = NumType (type_num v.it) in
     [] --> [t]
diff --git a/proposals/reference-types/Overview.md b/proposals/reference-types/Overview.md
index 741f609276..c666029619 100644
--- a/proposals/reference-types/Overview.md
+++ b/proposals/reference-types/Overview.md
@@ -97,8 +97,8 @@ Table extensions:
 
 API extensions:
 
-* Any JS value can be passed as `anyref` to a Wasm function, stored in a global, or in a table.
-  - Is it worth considering that restricting this to non-primitive values might allow engines to use techniques like pointer compression.
+* Any JS object (non-primitive value) or string or symbol or `null` can be passed as `anyref` to a Wasm function, stored in a global, or in a table.
+  - It may be possible to allow all JS values into `anyref`, but or some engines that would imply possible boxing at the boundary.
 
 * Any Wasm exported function object or `null` can be passed as `anyfunc` to a Wasm function, stored in a global, or in a table.
 
diff --git a/test/core/br_table.wast b/test/core/br_table.wast
index dfb3c77c7c..a24d1283da 100644
--- a/test/core/br_table.wast
+++ b/test/core/br_table.wast
@@ -1237,14 +1237,6 @@
     )
   )
 
-  (func (export "meet-eqref") (param i32) (param eqref) (result anyref)
-    (block $l1 (result anyref)
-      (block $l2 (result eqref)
-        (br_table $l1 $l2 $l1 (get_local 1) (get_local 0))
-      )
-    )
-  )
-
   (func (export "meet-anyfunc") (param i32) (result anyref)
     (block $l1 (result anyref)
       (block $l2 (result anyfunc)
@@ -1252,19 +1244,6 @@
       )
     )
   )
-
-  (func (export "meet-nullref") (param i32) (result anyref)
-    (block $l1 (result anyref)
-      (block $l2 (result eqref)
-        (drop
-          (block $l3 (result anyfunc)
-            (br_table $l1 $l2 $l3 (ref.null) (get_local 0))
-          )
-        )
-        (ref.null)
-      )
-    )
-  )
 )
 
 (assert_return (invoke "type-i32"))
@@ -1450,18 +1429,10 @@
 (assert_return (invoke "meet-anyref" (i32.const 1) (ref.host 1)) (ref.host 1))
 (assert_return (invoke "meet-anyref" (i32.const 2) (ref.host 1)) (ref.host 1))
 
-(assert_return (invoke "meet-eqref" (i32.const 0) (ref.host 1)) (ref.host 1))
-(assert_return (invoke "meet-eqref" (i32.const 1) (ref.host 1)) (ref.host 1))
-(assert_return (invoke "meet-eqref" (i32.const 2) (ref.host 1)) (ref.host 1))
-
 (assert_return_func (invoke "meet-anyfunc" (i32.const 0)))
 (assert_return_func (invoke "meet-anyfunc" (i32.const 1)))
 (assert_return_func (invoke "meet-anyfunc" (i32.const 2)))
 
-(assert_return (invoke "meet-nullref" (i32.const 0)) (ref.null))
-(assert_return (invoke "meet-nullref" (i32.const 1)) (ref.null))
-(assert_return (invoke "meet-nullref" (i32.const 2)) (ref.null))
-
 (assert_invalid
   (module (func $type-arg-void-vs-num (result i32)
     (block (br_table 0 (i32.const 1)) (i32.const 1))
diff --git a/test/core/get_table.wast b/test/core/get_table.wast
index 6b7e6750c7..63443b5f8e 100644
--- a/test/core/get_table.wast
+++ b/test/core/get_table.wast
@@ -1,18 +1,13 @@
 (module
-  (table $t1 2 eqref)
   (table $t2 2 anyref)
   (table $t3 3 anyfunc) (elem $t3 (i32.const 1) $dummy)
   (func $dummy)
 
-  (func (export "init") (param $r eqref)
-    (set_table $t1 (i32.const 1) (get_local $r))
+  (func (export "init") (param $r anyref)
     (set_table $t2 (i32.const 1) (get_local $r))
     (set_table $t3 (i32.const 2) (get_table $t3 (i32.const 1)))
   )
 
-  (func (export "get-eqref") (param $i i32) (result eqref)
-    (get_table $t1 (get_local $i))
-  )
   (func (export "get-anyref") (param $i i32) (result anyref)
     (get_table $t2 (get_local $i))
   )
@@ -27,9 +22,6 @@
 
 (invoke "init" (ref.host 1))
 
-(assert_return (invoke "get-eqref" (i32.const 0)) (ref.null))
-(assert_return (invoke "get-eqref" (i32.const 1)) (ref.host 1))
-
 (assert_return (invoke "get-anyref" (i32.const 0)) (ref.null))
 (assert_return (invoke "get-anyref" (i32.const 1)) (ref.host 1))
 
@@ -37,9 +29,7 @@
 (assert_return (invoke "isnull-anyfunc" (i32.const 1)) (i32.const 0))
 (assert_return (invoke "isnull-anyfunc" (i32.const 2)) (i32.const 0))
 
-(assert_trap (invoke "get-eqref" (i32.const 2)) "out of bounds")
 (assert_trap (invoke "get-anyref" (i32.const 2)) "out of bounds")
 (assert_trap (invoke "get-anyfunc" (i32.const 3)) "out of bounds")
-(assert_trap (invoke "get-eqref" (i32.const -1)) "out of bounds")
 (assert_trap (invoke "get-anyref" (i32.const -1)) "out of bounds")
 (assert_trap (invoke "get-anyfunc" (i32.const -1)) "out of bounds")
diff --git a/test/core/globals.wast b/test/core/globals.wast
index e61f2857e6..736c74cf30 100644
--- a/test/core/globals.wast
+++ b/test/core/globals.wast
@@ -13,17 +13,14 @@
 
   (global $r anyref (ref.null))
   (global anyfunc (ref.null))
-  (global $z (mut eqref) (ref.null))
 
   (func (export "get-a") (result i32) (get_global $a))
   (func (export "get-b") (result i64) (get_global $b))
   (func (export "get-r") (result anyref) (get_global $r))
   (func (export "get-x") (result i32) (get_global $x))
   (func (export "get-y") (result i64) (get_global $y))
-  (func (export "get-z") (result eqref) (get_global $z))
   (func (export "set-x") (param i32) (set_global $x (get_local 0)))
   (func (export "set-y") (param i64) (set_global $y (get_local 0)))
-  (func (export "set-z") (param eqref) (set_global $z (get_local 0)))
 
   (func (export "get-1") (result f32) (get_global 1))
   (func (export "get-2") (result f64) (get_global 2))
@@ -38,7 +35,6 @@
 (assert_return (invoke "get-r") (ref.null))
 (assert_return (invoke "get-x") (i32.const -12))
 (assert_return (invoke "get-y") (i64.const -15))
-(assert_return (invoke "get-z") (ref.null))
 
 (assert_return (invoke "get-1") (f32.const -3))
 (assert_return (invoke "get-2") (f64.const -4))
@@ -47,13 +43,11 @@
 
 (assert_return (invoke "set-x" (i32.const 6)))
 (assert_return (invoke "set-y" (i64.const 7)))
-(assert_return (invoke "set-z" (ref.host 33)))
 (assert_return (invoke "set-5" (f32.const 8)))
 (assert_return (invoke "set-6" (f64.const 9)))
 
 (assert_return (invoke "get-x") (i32.const 6))
 (assert_return (invoke "get-y") (i64.const 7))
-(assert_return (invoke "get-z") (ref.host 33))
 (assert_return (invoke "get-5") (f32.const 8))
 (assert_return (invoke "get-6") (f64.const 9))
 
@@ -123,7 +117,7 @@
 )
 
 (assert_invalid
-  (module (global (import "" "") anyref) (global eqref (get_global 0)))
+  (module (global (import "" "") anyref) (global anyfunc (get_global 0)))
   "type mismatch"
 )
 
diff --git a/test/core/linking.wast b/test/core/linking.wast
index 20fc94695c..c44da62800 100644
--- a/test/core/linking.wast
+++ b/test/core/linking.wast
@@ -59,9 +59,9 @@
 (assert_return (invoke $Ng "get") (i32.const 43))
 
 (module $Mref-ex
-  (global (export "g-const") eqref (ref.null))
+  (global (export "g-const") anyfunc (ref.null))
   ;; Mutable globals cannot be exported yet
-  ;; (global (export "g-var") (mut eqref) (ref.null))
+  ;; (global (export "g-var") (mut anyfunc) (ref.null))
 )
 (register "Mref-ex" $Mref-ex)
 
diff --git a/test/core/ref_eq.wast b/test/core/ref_eq.wast
deleted file mode 100644
index c17458b29e..0000000000
--- a/test/core/ref_eq.wast
+++ /dev/null
@@ -1,50 +0,0 @@
-(module
-  (func $eq (export "eq") (param $x eqref) (param $y eqref) (result i32)
-    (ref.eq (get_local $x) (get_local $y))
-  )
-
-  (table $t 2 eqref)
-
-  (func (export "init") (param $r eqref)
-    (set_table $t (i32.const 1) (get_local $r))
-  )
-
-  (func (export "eq-elem") (param $i i32) (param $x eqref) (result i32)
-    (call $eq (get_table $t (get_local $i)) (get_local $x))
-  )
-)
-
-(assert_return (invoke "eq" (ref.null) (ref.null)) (i32.const 1))
-(assert_return (invoke "eq" (ref.host 1) (ref.host 1)) (i32.const 1))
-
-(assert_return (invoke "eq" (ref.null) (ref.host 0)) (i32.const 0))
-(assert_return (invoke "eq" (ref.host 0) (ref.null)) (i32.const 0))
-(assert_return (invoke "eq" (ref.host 1) (ref.host 2)) (i32.const 0))
-
-(invoke "init" (ref.host 0))
-
-(assert_return (invoke "eq-elem" (i32.const 0) (ref.null)) (i32.const 1))
-(assert_return (invoke "eq-elem" (i32.const 1) (ref.host 0)) (i32.const 1))
-
-(assert_return (invoke "eq-elem" (i32.const 0) (ref.host 0)) (i32.const 0))
-(assert_return (invoke "eq-elem" (i32.const 1) (ref.null)) (i32.const 0))
-(assert_return (invoke "eq-elem" (i32.const 1) (ref.host 1)) (i32.const 0))
-
-
-(assert_invalid
-  (module
-    (func (param $x anyref) (param $y eqref) (result i32)
-      (ref.eq (get_local $x) (get_local $y))
-    )
-  )
-  "type mismatch"
-)
-
-(assert_invalid
-  (module
-    (func (param $x anyfunc) (param $y eqref) (result i32)
-      (ref.eq (get_local $x) (get_local $y))
-    )
-  )
-  "type mismatch"
-)
diff --git a/test/core/ref_isnull.wast b/test/core/ref_isnull.wast
index 89b840983e..7bd0164c29 100644
--- a/test/core/ref_isnull.wast
+++ b/test/core/ref_isnull.wast
@@ -1,7 +1,4 @@
 (module
-  (func $f1 (export "eqref") (param $x eqref) (result i32)
-    (ref.isnull (get_local $x))
-  )
   (func $f2 (export "anyref") (param $x anyref) (result i32)
     (ref.isnull (get_local $x))
   )
@@ -9,24 +6,18 @@
     (ref.isnull (get_local $x))
   )
 
-  (table $t1 2 eqref)
   (table $t2 2 anyref)
   (table $t3 2 anyfunc) (elem $t3 (i32.const 1) $dummy)
   (func $dummy)
 
-  (func (export "init") (param $r eqref)
-    (set_table $t1 (i32.const 1) (get_local $r))
+  (func (export "init") (param $r anyref)
     (set_table $t2 (i32.const 1) (get_local $r))
   )
   (func (export "deinit")
-    (set_table $t1 (i32.const 1) (ref.null))
     (set_table $t2 (i32.const 1) (ref.null))
     (set_table $t3 (i32.const 1) (ref.null))
   )
 
-  (func (export "eqref-elem") (param $x i32) (result i32)
-    (call $f1 (get_table $t1 (get_local $x)))
-  )
   (func (export "anyref-elem") (param $x i32) (result i32)
     (call $f2 (get_table $t2 (get_local $x)))
   )
@@ -35,30 +26,24 @@
   )
 )
 
-(assert_return (invoke "eqref" (ref.null)) (i32.const 1))
 (assert_return (invoke "anyref" (ref.null)) (i32.const 1))
 (assert_return (invoke "anyfunc" (ref.null)) (i32.const 1))
 
-(assert_return (invoke "eqref" (ref.host 1)) (i32.const 0))
 (assert_return (invoke "anyref" (ref.host 1)) (i32.const 0))
 (assert_return (invoke "anyfunc" (ref.host 1)) (i32.const 0))
 
 (invoke "init" (ref.host 0))
 
-(assert_return (invoke "eqref-elem" (i32.const 0)) (i32.const 1))
 (assert_return (invoke "anyref-elem" (i32.const 0)) (i32.const 1))
 (assert_return (invoke "anyfunc-elem" (i32.const 0)) (i32.const 1))
 
-(assert_return (invoke "eqref-elem" (i32.const 1)) (i32.const 0))
 (assert_return (invoke "anyref-elem" (i32.const 1)) (i32.const 0))
 (assert_return (invoke "anyfunc-elem" (i32.const 1)) (i32.const 0))
 
 (invoke "deinit")
 
-(assert_return (invoke "eqref-elem" (i32.const 0)) (i32.const 1))
 (assert_return (invoke "anyref-elem" (i32.const 0)) (i32.const 1))
 (assert_return (invoke "anyfunc-elem" (i32.const 0)) (i32.const 1))
 
-(assert_return (invoke "eqref-elem" (i32.const 1)) (i32.const 1))
 (assert_return (invoke "anyref-elem" (i32.const 1)) (i32.const 1))
 (assert_return (invoke "anyfunc-elem" (i32.const 1)) (i32.const 1))
diff --git a/test/core/ref_null.wast b/test/core/ref_null.wast
index a627b31ed4..ba95b40a31 100644
--- a/test/core/ref_null.wast
+++ b/test/core/ref_null.wast
@@ -1,9 +1,7 @@
 (module
-  (func (export "eqref") (result eqref) (ref.null))
   (func (export "anyref") (result anyref) (ref.null))
   (func (export "anyfunc") (result anyfunc) (ref.null))
 )
 
-(assert_return (invoke "eqref") (ref.null))
 (assert_return (invoke "anyref") (ref.null))
 (assert_return (invoke "anyfunc") (ref.null))
diff --git a/test/core/select.wast b/test/core/select.wast
index 35553b68f6..0aa5e202bd 100644
--- a/test/core/select.wast
+++ b/test/core/select.wast
@@ -35,15 +35,11 @@
     (select (ref.null) (ref.null) (get_local 0))
   )
 
-  (func (export "join-eqref") (param i32) (param eqref) (result anyref)
-    (select (get_local 1) (ref.null) (get_local 0))
-  )
-
   (func (export "join-anyfunc") (param i32) (result anyref)
     (select (get_table $tab (i32.const 0)) (ref.null) (get_local 0))
   )
 
-  (func (export "join-anyref") (param i32) (param eqref) (result anyref)
+  (func (export "join-anyref") (param i32) (param anyref) (result anyref)
     (select (get_table $tab (i32.const 0)) (get_local 1) (get_local 0))
   )
 )
@@ -79,9 +75,6 @@
 (assert_return (invoke "join-nullref" (i32.const 1)) (ref.null))
 (assert_return (invoke "join-nullref" (i32.const 0)) (ref.null))
 
-(assert_return (invoke "join-eqref" (i32.const 1) (ref.host 1)) (ref.host 1))
-(assert_return (invoke "join-eqref" (i32.const 0) (ref.host 1)) (ref.null))
-
 (assert_return_func (invoke "join-anyfunc" (i32.const 1)))
 (assert_return (invoke "join-anyfunc" (i32.const 0)) (ref.null))
 
diff --git a/test/core/set_table.wast b/test/core/set_table.wast
index 0a6747bc05..241331d65f 100644
--- a/test/core/set_table.wast
+++ b/test/core/set_table.wast
@@ -1,12 +1,8 @@
 (module
-  (table $t1 1 eqref)
   (table $t2 1 anyref)
   (table $t3 2 anyfunc) (elem $t3 (i32.const 1) $dummy)
   (func $dummy)
 
-  (func (export "get-eqref") (param $i i32) (result eqref)
-    (get_table $t1 (get_local $i))
-  )
   (func (export "get-anyref") (param $i i32) (result anyref)
     (get_table $t2 (get_local $i))
   )
@@ -14,9 +10,6 @@
     (get_table $t3 (get_local $i))
   )
 
-  (func (export "set-eqref") (param $i i32) (param $r eqref)
-    (set_table $t1 (get_local $i) (get_local $r))
-  )
   (func (export "set-anyref") (param $i i32) (param $r anyref)
     (set_table $t2 (get_local $i) (get_local $r))
   )
@@ -32,12 +25,6 @@
   )
 )
 
-(assert_return (invoke "get-eqref" (i32.const 0)) (ref.null))
-(assert_return (invoke "set-eqref" (i32.const 0) (ref.host 1)))
-(assert_return (invoke "get-eqref" (i32.const 0)) (ref.host 1))
-(assert_return (invoke "set-eqref" (i32.const 0) (ref.null)))
-(assert_return (invoke "get-eqref" (i32.const 0)) (ref.null))
-
 (assert_return (invoke "get-anyref" (i32.const 0)) (ref.null))
 (assert_return (invoke "set-anyref" (i32.const 0) (ref.host 1)))
 (assert_return (invoke "get-anyref" (i32.const 0)) (ref.host 1))
@@ -50,16 +37,12 @@
 (assert_return (invoke "set-anyfunc" (i32.const 0) (ref.null)))
 (assert_return (invoke "get-anyfunc" (i32.const 0)) (ref.null))
 
-(assert_trap (invoke "set-eqref" (i32.const 2) (ref.null)) "out of bounds")
 (assert_trap (invoke "set-anyref" (i32.const 2) (ref.null)) "out of bounds")
 (assert_trap (invoke "set-anyfunc" (i32.const 3) (ref.null)) "out of bounds")
-(assert_trap (invoke "set-eqref" (i32.const -1) (ref.null)) "out of bounds")
 (assert_trap (invoke "set-anyref" (i32.const -1) (ref.null)) "out of bounds")
 (assert_trap (invoke "set-anyfunc" (i32.const -1) (ref.null)) "out of bounds")
 
-(assert_trap (invoke "set-eqref" (i32.const 2) (ref.host 0)) "out of bounds")
 (assert_trap (invoke "set-anyref" (i32.const 2) (ref.host 0)) "out of bounds")
 (assert_trap (invoke "set-anyfunc-from" (i32.const 3) (i32.const 1)) "out of bounds")
-(assert_trap (invoke "set-eqref" (i32.const -1) (ref.host 0)) "out of bounds")
 (assert_trap (invoke "set-anyref" (i32.const -1) (ref.host 0)) "out of bounds")
 (assert_trap (invoke "set-anyfunc-from" (i32.const -1) (i32.const 1)) "out of bounds")

From ba2a5f8fa3752ecf6611e17dbcec8ca44c6c954c Mon Sep 17 00:00:00 2001
From: Ben Smith 
Date: Mon, 7 May 2018 12:31:35 -0700
Subject: [PATCH 020/199] Rename `mem.*` -> `memory.*`

This follows the naming discussed in issue
https://github.com/WebAssembly/spec/issues/627.
---
 proposals/bulk-memory-operations/Overview.md | 60 ++++++++++----------
 1 file changed, 30 insertions(+), 30 deletions(-)

diff --git a/proposals/bulk-memory-operations/Overview.md b/proposals/bulk-memory-operations/Overview.md
index c1cfd44dac..824ce13318 100644
--- a/proposals/bulk-memory-operations/Overview.md
+++ b/proposals/bulk-memory-operations/Overview.md
@@ -19,7 +19,7 @@ when profiling some WebAssembly benchmarks. Some examples:
 
 ### Bulk Memory Operations Prototype
 
-I implemented a prototype implementation of a `mem.copy` instruction in v8 which just calls out
+I implemented a prototype implementation of a `memory.copy` instruction in v8 which just calls out
 to v8's [`MemMove` function](https://cs.chromium.org/chromium/src/v8/src/utils.h?l=446). I compared
 this to an implementation [generated by emscripten](https://gist.github.com/binji/c57dc945bba60985439ef8e5b574eee0) and currently used in the Unity demo. This implementation aligns then performs copies using `i32.load` and `i32.store`. I've also included performance achieved by unrolling this loop manually and increasing the size to `i64`.
 
@@ -39,7 +39,7 @@ This is the core loop:
 ```
 
 The code for the benchmark can be found [here](https://gist.github.com/binji/b8e8bc0c0121235d9f1668bc447c7f8c).
-Note that this will not run properly without a WebAssembly implementation of `mem.copy`. For my tests, I
+Note that this will not run properly without a WebAssembly implementation of `memory.copy`. For my tests, I
 hacked a version of v8 to replace any exported function called `memcpy` or `memmove` with a new function with
 the following contents:
 
@@ -48,7 +48,7 @@ the following contents:
   get_local $dst
   get_local $src
   get_local $size
-  mem.copy
+  memory.copy
   get_local $dst)
 ```
 
@@ -144,8 +144,8 @@ requires two modules where one should be enough.
 
 When [discussing the design of Conditional Segment Initialization](https://github.com/WebAssembly/threads/issues/62),
 we found that programmatic memory initialization from a read-only data segment
-(via the `mem.init` instruction, described below) has similar behavior to the
-proposed instruction to copy memory regions from linear memory (`mem.copy`,
+(via the `memory.init` instruction, described below) has similar behavior to the
+proposed instruction to copy memory regions from linear memory (`memory.copy`,
 also described below.)
 
 ## Design
@@ -153,14 +153,14 @@ also described below.)
 Copying between regions in linear memory or a table is accomplished with the
 new `*.copy` instructions:
 
-* `mem.copy`: copy from one region of linear memory to another
+* `memory.copy`: copy from one region of linear memory to another
 * `table.copy`: copy from one region of a table to another
 
-Filling a memory region can be accomplished with `mem.fill`:
+Filling a memory region can be accomplished with `memory.fill`:
 
-* `mem.fill`: fill a region of linear memory with a given byte value
+* `memory.fill`: fill a region of linear memory with a given byte value
 
-TODO: should we provide `mem.clear` and `table.clear` instead?
+TODO: should we provide `memory.clear` and `table.clear` instead?
 
 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
@@ -174,15 +174,15 @@ _passive_. A passive 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
+* `memory.init`: copy a region from a data segment
 * `table.init`: copy a region from an element segment
 
 A passive segment has no initializer expression, since it will be specified
-as an operand to `mem.init` or `table.init`.
+as an operand to `memory.init` or `table.init`.
 
 Passive segments can also be discarded by using the following new instructions:
 
-* `mem.drop`: prevent further use of a data segment
+* `memory.drop`: prevent further use of a data segment
 * `table.drop`: prevent further use of an element segment
 
 Attempting to drop an active segment is a validation error.
@@ -197,36 +197,36 @@ data    ::= 0x01 b*:vec(byte)            => {data 0, offset empty, init b*, acti
 
 The element section is encoded similarly.
 
-### `mem.init` instruction
+### `memory.init` instruction
 
-The `mem.init` instruction copies data from a given passive segment into a target
+The `memory.init` instruction copies data from a given passive 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 `mem.init` is executed, its behavior matches the steps described in
+When `memory.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 `mem.init` operands.
+target offset, and length as given by the `memory.init` operands.
 
 A trap occurs if:
 * the segment is passive
-* the segment is used after it has been dropped via `mem.drop`
+* the segment is used after it has been dropped via `memory.drop`
 * any of the accessed bytes lies outside the source data segment or the target memory
 
-Note that it is allowed to use `mem.init` on the same data segment more than
+Note that it is allowed to use `memory.init` on the same data segment more than
 once.
 
-### `mem.drop` instruction
+### `memory.drop` instruction
 
-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`
+The `memory.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 `memory.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.
 
-### `mem.copy` instruction
+### `memory.copy` instruction
 
 Copy data from a source memory region to destination region; these regions may
 overlap: the copy is performed as if the source region was first copied to a
@@ -239,7 +239,7 @@ The instruction has the signature `[i32 i32 i32] -> []`. The parameters are, in
 - top-1: source address
 - top-0: size of memory region in bytes
 
-### `mem.fill` instruction
+### `memory.fill` instruction
 
 Set all bytes in a memory region to a given byte.
 
@@ -251,7 +251,7 @@ The instruction has the signature `[i32 i32 i32] -> []`. The parameters are, in
 
 ### `table.init`, `table.drop`, and `table.copy` instructions
 
-The `table.*` instructions behave similary to the `mem.*` instructions, with
+The `table.*` instructions behave similary to the `memory.*` 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` and
 `table.copy` have element units instead of bytes as well.
@@ -272,14 +272,14 @@ implemented as follows:
   (if (get_global 0)
 
     ;; copy data segment 1 into memory
-    (mem.init 1
+    (memory.init 1
       (i32.const 0)     ;; source offset
       (i32.const 16)    ;; target offset
       (i32.const 7))    ;; length
 
     ;; The memory used by this segment is no longer needed, so this segment can
     ;; be dropped.
-    (mem.drop 1))
+    (memory.drop 1))
 )
 ```
 
@@ -287,10 +287,10 @@ implemented as follows:
 
 | Name | Opcode | Immediate | Description |
 | ---- | ---- | ---- | ---- |
-| `mem.init` | `0xfc` | `0x08` | :thinking: copy from a passive data segment to linear memory |
-| `mem.drop` | `0xfc` | `0x09` | :thinking: prevent further use of passive data segment |
-| `mem.copy` | `0xfc` | `0x0a` | :thinking: copy from one region of linear memory to another region |
-| `mem.fill` | `0xfc` | `0x0b` | :thinking: fill a region of linear memory with a given byte value |
+| `memory.init` | `0xfc` | `0x08` | :thinking: copy from a passive data segment to linear memory |
+| `memory.drop` | `0xfc` | `0x09` | :thinking: prevent further use of passive data segment |
+| `memory.copy` | `0xfc` | `0x0a` | :thinking: copy from one region of linear memory to another region |
+| `memory.fill` | `0xfc` | `0x0b` | :thinking: fill a region of linear memory with a given byte value |
 | `table.init` | `0xfc` | `0x0c` | :thinking: copy from a passive element segment to a table |
 | `table.drop` | `0xfc` | `0x0d` | :thinking: prevent further use of a passive element segment |
 | `table.copy` | `0xfc` | `0x0e` | :thinking: copy from one region of a table to another region |

From c86bece05ef8c3dcf85755e1ada8fa7463ac8ca5 Mon Sep 17 00:00:00 2001
From: Ben Smith 
Date: Thu, 10 May 2018 10:38:04 -0700
Subject: [PATCH 021/199] [spec] Initial documentation of syntax (#12)

* [spec] Initial documentation of syntax

Includes the basic structure needed for the proposal, but no validation,
binary, text or execution.
---
 document/core/syntax/instructions.rst | 39 +++++++++++++++++++++++-
 document/core/syntax/modules.rst      | 44 +++++++++++++++++++++------
 document/core/util/macros.def         | 10 ++++++
 3 files changed, 82 insertions(+), 11 deletions(-)

diff --git a/document/core/syntax/instructions.rst b/document/core/syntax/instructions.rst
index 1b8e195db2..96667f4137 100644
--- a/document/core/syntax/instructions.rst
+++ b/document/core/syntax/instructions.rst
@@ -241,7 +241,11 @@ Instructions in this group are concerned with linear :ref:`memory `.
      \K{i}\X{nn}\K{.}\STORE\K{16}~\memarg ~|~
      \K{i64.}\STORE\K{32}~\memarg \\&&|&
      \MEMORYSIZE \\&&|&
-     \MEMORYGROW \\
+     \MEMORYGROW \\&&|&
+     \MEMORYINIT~\dataidx \\&&|&
+     \MEMORYDROP~\dataidx \\&&|&
+     \MEMORYCOPY \\&&|&
+     \MEMORYFILL \\
    \end{array}
 
 Memory is accessed with |LOAD| and |STORE| instructions for the different :ref:`value types `.
@@ -260,12 +264,45 @@ The |MEMORYSIZE| instruction returns the current size of a memory.
 The |MEMORYGROW| instruction grows memory by a given delta and returns the previous size, or :math:`-1` if enough memory cannot be allocated.
 Both instructions operate in units of :ref:`page size `.
 
+The |MEMORYINIT| instruction copies data from a :ref:`passive data segment ` into a memory.
+The |MEMORYDROP| instruction prevents further use of a passive data segment. This instruction is intended to be used as an optimization hint. After a data segment is dropped its data can no longer be retrieved, so the memory used by this segment may be freed.
+The |MEMORYCOPY| instruction copies data from a source memory region to a possibly overlapping destination region.
+The |MEMORYFILL| instruction sets all values in a region to a given byte.
+
 .. note::
    In the current version of WebAssembly,
    all memory instructions implicitly operate on :ref:`memory ` :ref:`index ` :math:`0`.
    This restriction may be lifted in future versions.
 
 
+.. index:: ! table instruction, table, table index
+   pair: abstract syntax; instruction
+.. _syntax-instr-table:
+
+Table Instructions
+~~~~~~~~~~~~~~~~~~
+
+Instructions in this group are concerned with tables :ref:`table `.
+
+.. math::
+   \begin{array}{llcl}
+   \production{instruction} & \instr &::=&
+     \dots \\&&|&
+     \TABLEINIT~\elemidx \\&&|&
+     \TABLEDROP~\elemidx \\&&|&
+     \TABLECOPY \\
+   \end{array}
+
+The |TABLEINIT| instruction copies elements from a :ref:`passive element segment ` into a table.
+The |TABLEDROP| instruction prevents further use of a passive element segment. This instruction is intended to be used as an optimization hint. After an element segment is dropped its elements can no longer be retrieved, so the memory used by this segment may be freed.
+The |TABLECOPY| instruction copies elements from a source table region to a possibly overlapping destination region.
+
+.. note::
+   In the current version of WebAssembly,
+   all table instructions implicitly operate on :ref:`table ` :ref:`index ` :math:`0`.
+   This restriction may be lifted in future versions.
+
+
 .. index:: ! control instruction, ! structured control, ! label, ! block, ! branch, ! unwinding, result type, label index, function index, type index, vector, trap, function, table, function type
    pair: abstract syntax; instruction
 .. _syntax-nop:
diff --git a/document/core/syntax/modules.rst b/document/core/syntax/modules.rst
index fe2b3cd7a1..30453e2a12 100644
--- a/document/core/syntax/modules.rst
+++ b/document/core/syntax/modules.rst
@@ -9,7 +9,7 @@ WebAssembly programs are organized into *modules*,
 which are the unit of deployment, loading, and compilation.
 A module collects definitions for :ref:`types `, :ref:`functions `, :ref:`tables `, :ref:`memories `, and :ref:`globals `.
 In addition, it can declare :ref:`imports ` and :ref:`exports `
-and provide initialization logic in the form of :ref:`data ` and :ref:`element ` segments or a :ref:`start function `.
+and provide initialization logic in the form of active and passive :ref:`data ` and :ref:`element ` segments, or a :ref:`start function `.
 
 .. math::
    \begin{array}{lllll}
@@ -29,12 +29,14 @@ and provide initialization logic in the form of :ref:`data ` and :r
 Each of the vectors -- and thus the entire module -- may be empty.
 
 
-.. index:: ! index, ! index space, ! type index, ! function index, ! table index, ! memory index, ! global index, ! local index, ! label index, function, global, table, memory, local, parameter, import
+.. index:: ! index, ! index space, ! type index, ! function index, ! table index, ! memory index, ! global index, ! local index, ! label index, ! element index, ! data index, function, global, table, memory, element, data, local, parameter, import
    pair: abstract syntax; type index
    pair: abstract syntax; function index
    pair: abstract syntax; table index
    pair: abstract syntax; memory index
    pair: abstract syntax; global index
+   pair: abstract syntax; element index
+   pair: abstract syntax; data index
    pair: abstract syntax; local index
    pair: abstract syntax; label index
    pair: type; index
@@ -42,6 +44,8 @@ Each of the vectors -- and thus the entire module -- may be empty.
    pair: table; index
    pair: memory; index
    pair: global; index
+   pair: element; index
+   pair: data; index
    pair: local; index
    pair: label; index
 .. _syntax-typeidx:
@@ -49,6 +53,8 @@ Each of the vectors -- and thus the entire module -- may be empty.
 .. _syntax-tableidx:
 .. _syntax-memidx:
 .. _syntax-globalidx:
+.. _syntax-elemidx:
+.. _syntax-dataidx:
 .. _syntax-localidx:
 .. _syntax-labelidx:
 .. _syntax-index:
@@ -66,6 +72,8 @@ Each class of definition has its own *index space*, as distinguished by the foll
    \production{table index} & \tableidx &::=& \u32 \\
    \production{memory index} & \memidx &::=& \u32 \\
    \production{global index} & \globalidx &::=& \u32 \\
+   \production{element index} & \elemidx &::=& \u32 \\
+   \production{data index} & \dataidx &::=& \u32 \\
    \production{local index} & \localidx &::=& \u32 \\
    \production{label index} & \labelidx &::=& \u32 \\
    \end{array}
@@ -73,6 +81,10 @@ Each class of definition has its own *index space*, as distinguished by the foll
 The index space for :ref:`functions `, :ref:`tables `, :ref:`memories ` and :ref:`globals ` includes respective :ref:`imports ` declared in the same module.
 The indices of these imports precede the indices of other definitions in the same index space.
 
+Element indices reference :ref:`element segments `.
+
+Data indices reference :ref:`data segments `.
+
 The index space for :ref:`locals ` is only accessible inside a :ref:`function ` and includes the parameters and local variables of that function, which precede the other locals.
 
 Label indices reference :ref:`structured control instructions ` inside an instruction sequence.
@@ -216,7 +228,7 @@ Globals are referenced through :ref:`global indices `,
 starting with the smallest index not referencing a global :ref:`import `.
 
 
-.. index:: ! element, table, table index, expression, constant, function index, vector
+.. index:: ! element, ! active, ! passive, element index, table, table index, expression, constant, function index, vector
    pair: abstract syntax; element
    single: table; element
    single: element; segment
@@ -225,23 +237,29 @@ starting with the smallest index not referencing a global :ref:`import ` of elements.
+The initial contents of a table is uninitialized. *Element segments* can be used to initialize a subrange of a table from a static :ref:`vector ` of elements.
+
+Element segments can be *active* or *passive*. An active element segment copies its elements into a table during :ref:`instantiation `. A passive element segment's elements can be copied using the |TABLEINIT| instruction.
+
+The |MELEM| component of a module defines a vector of element segments. Each active element segment defines the |ETABLE| and the starting |EOFFSET| in that table to initialize. Each passive element segment only defines its contents.
 
 .. math::
    \begin{array}{llll}
    \production{element segment} & \elem &::=&
-     \{ \ETABLE~\tableidx, \EOFFSET~\expr, \EINIT~\vec(\funcidx) \} \\
+     \{ \ETABLE~\tableidx, \EOFFSET~\expr, \EINIT~\vec(\funcidx) \} \\&&|&
+     \{ \EINIT~\vec(\funcidx) \} \\
    \end{array}
 
 The |EOFFSET| is given by a :ref:`constant ` :ref:`expression `.
 
+Element segments are referenced through :ref:`element indices `.
+
 .. note::
    In the current version of WebAssembly, at most one table is allowed in a module.
    Consequently, the only valid |tableidx| is :math:`0`.
 
 
-.. index:: ! data, memory, memory index, expression, constant, byte, vector
+.. index:: ! data, active, passive, data index, memory, memory index, expression, constant, byte, vector
    pair: abstract syntax; data
    single: memory; data
    single: data; segment
@@ -250,17 +268,23 @@ The |EOFFSET| is given by a :ref:`constant ` :ref:`expression ` are zero bytes.
-The |MDATA| component of a module defines a vector of *data segments* that initialize a range of memory at a given offset with a static :ref:`vector ` of :ref:`bytes `.
+The initial contents of a :ref:`memory ` are zero bytes. *Data segments* can be used to initialize a range of memory from a static :ref:`vector ` of :ref:`bytes `.
+
+Like element segments, data segments can be active or passive. An active data segment copies its contents into a table during :ref:`instantiation `. A passive data segment's contents can be copied using the |MEMORYINIT| instruction.
+
+The |MDATA| component of a module defines a vector of data segments. Each active data segment defines the memory to initialize, and the starting |DOFFSET| in that memory to initialize. Each passive data segment only defines its contents.
 
 .. math::
    \begin{array}{llll}
    \production{data segment} & \data &::=&
-     \{ \DMEM~\memidx, \DOFFSET~\expr, \DINIT~\vec(\byte) \} \\
+     \{ \DMEM~\memidx, \DOFFSET~\expr, \DINIT~\vec(\byte) \} \\&&|&
+     \{ \DINIT~\vec(\byte) \} \\
    \end{array}
 
 The |DOFFSET| is given by a :ref:`constant ` :ref:`expression `.
 
+Data segments are referenced through :ref:`data indices `.
+
 .. note::
    In the current version of WebAssembly, at most one memory is allowed in a module.
    Consequently, the only valid |memidx| is :math:`0`.
diff --git a/document/core/util/macros.def b/document/core/util/macros.def
index ea5be82d8c..60babcb9e3 100644
--- a/document/core/util/macros.def
+++ b/document/core/util/macros.def
@@ -216,6 +216,8 @@
 .. |tableidx| mathdef:: \xref{syntax/modules}{syntax-tableidx}{\X{tableidx}}
 .. |memidx| mathdef:: \xref{syntax/modules}{syntax-memidx}{\X{memidx}}
 .. |globalidx| mathdef:: \xref{syntax/modules}{syntax-globalidx}{\X{globalidx}}
+.. |elemidx| mathdef:: \xref{syntax/modules}{syntax-elemidx}{\X{elemidx}}
+.. |dataidx| mathdef:: \xref{syntax/modules}{syntax-dataidx}{\X{dataidx}}
 .. |localidx| mathdef:: \xref{syntax/modules}{syntax-localidx}{\X{localidx}}
 .. |labelidx| mathdef:: \xref{syntax/modules}{syntax-labelidx}{\X{labelidx}}
 
@@ -327,6 +329,14 @@
 .. |STORE| mathdef:: \xref{syntax/instructions}{syntax-instr-memory}{\K{store}}
 .. |MEMORYSIZE| mathdef:: \xref{syntax/instructions}{syntax-instr-memory}{\K{memory.size}}
 .. |MEMORYGROW| mathdef:: \xref{syntax/instructions}{syntax-instr-memory}{\K{memory.grow}}
+.. |MEMORYINIT| mathdef:: \xref{syntax/instructions}{syntax-instr-memory}{\K{memory.init}}
+.. |MEMORYDROP| mathdef:: \xref{syntax/instructions}{syntax-instr-memory}{\K{memory.drop}}
+.. |MEMORYCOPY| mathdef:: \xref{syntax/instructions}{syntax-instr-memory}{\K{memory.copy}}
+.. |MEMORYFILL| mathdef:: \xref{syntax/instructions}{syntax-instr-memory}{\K{memory.fill}}
+
+.. |TABLEINIT| mathdef:: \xref{syntax/instructions}{syntax-instr-table}{\K{table.init}}
+.. |TABLEDROP| mathdef:: \xref{syntax/instructions}{syntax-instr-table}{\K{table.drop}}
+.. |TABLECOPY| mathdef:: \xref{syntax/instructions}{syntax-instr-table}{\K{table.copy}}
 
 .. |CONST| mathdef:: \xref{syntax/instructions}{syntax-instr-numeric}{\K{const}}
 .. |EQZ| mathdef:: \xref{syntax/instructions}{syntax-instr-numeric}{\K{eqz}}

From 9319fa707d4fa705287576a3b4805ff433dddb90 Mon Sep 17 00:00:00 2001
From: Ben Smith 
Date: Thu, 10 May 2018 11:44:56 -0700
Subject: [PATCH 022/199] Fix memory.{init,drop} mistakes in overview (#14)

Using `memory.init` or `memory.drop` on an active segment is a validation error, not a trap.
---
 proposals/bulk-memory-operations/Overview.md | 5 ++++-
 1 file changed, 4 insertions(+), 1 deletion(-)

diff --git a/proposals/bulk-memory-operations/Overview.md b/proposals/bulk-memory-operations/Overview.md
index 824ce13318..de5e7b11b6 100644
--- a/proposals/bulk-memory-operations/Overview.md
+++ b/proposals/bulk-memory-operations/Overview.md
@@ -210,8 +210,9 @@ step 11 of
 but it behaves as though the segment were specified with the source offset,
 target offset, and length as given by the `memory.init` operands.
 
+It is a validation error to use `memory.init` with an active segment.
+
 A trap occurs if:
-* the segment is passive
 * the segment is used after it has been dropped via `memory.drop`
 * any of the accessed bytes lies outside the source data segment or the target memory
 
@@ -226,6 +227,8 @@ 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.
 
+It is a validation error to use `memory.drop` with an active segment.
+
 ### `memory.copy` instruction
 
 Copy data from a source memory region to destination region; these regions may

From 863d96338401c481f90f33495b35c9a93aa9be23 Mon Sep 17 00:00:00 2001
From: Ben Smith 
Date: Fri, 11 May 2018 12:22:22 -0700
Subject: [PATCH 023/199] [spec] Document validation (#16)

---
 document/core/syntax/instructions.rst |   4 +-
 document/core/syntax/modules.rst      |   8 +-
 document/core/syntax/types.rst        |  19 ++++
 document/core/util/macros.def         |   6 ++
 document/core/valid/conventions.rst   |   4 +
 document/core/valid/instructions.rst  | 143 ++++++++++++++++++++++++++
 document/core/valid/modules.rst       |  60 +++++++++--
 7 files changed, 227 insertions(+), 17 deletions(-)

diff --git a/document/core/syntax/instructions.rst b/document/core/syntax/instructions.rst
index 1e34f189d9..d9b44c594a 100644
--- a/document/core/syntax/instructions.rst
+++ b/document/core/syntax/instructions.rst
@@ -265,7 +265,7 @@ The |MEMORYSIZE| instruction returns the current size of a memory.
 The |MEMORYGROW| instruction grows memory by a given delta and returns the previous size, or :math:`-1` if enough memory cannot be allocated.
 Both instructions operate in units of :ref:`page size `.
 
-The |MEMORYINIT| instruction copies data from a :ref:`passive data segment ` into a memory.
+The |MEMORYINIT| instruction copies data from a :ref:`passive data segment ` into a memory.
 The |MEMORYDROP| instruction prevents further use of a passive data segment. This instruction is intended to be used as an optimization hint. After a data segment is dropped its data can no longer be retrieved, so the memory used by this segment may be freed.
 The |MEMORYCOPY| instruction copies data from a source memory region to a possibly overlapping destination region.
 The |MEMORYFILL| instruction sets all values in a region to a given byte.
@@ -294,7 +294,7 @@ Instructions in this group are concerned with tables :ref:`table `
      \TABLECOPY \\
    \end{array}
 
-The |TABLEINIT| instruction copies elements from a :ref:`passive element segment ` into a table.
+The |TABLEINIT| instruction copies elements from a :ref:`passive element segment ` into a table.
 The |TABLEDROP| instruction prevents further use of a passive element segment. This instruction is intended to be used as an optimization hint. After an element segment is dropped its elements can no longer be retrieved, so the memory used by this segment may be freed.
 The |TABLECOPY| instruction copies elements from a source table region to a possibly overlapping destination region.
 
diff --git a/document/core/syntax/modules.rst b/document/core/syntax/modules.rst
index 9ac4aed87c..fad2796044 100644
--- a/document/core/syntax/modules.rst
+++ b/document/core/syntax/modules.rst
@@ -9,7 +9,7 @@ WebAssembly programs are organized into *modules*,
 which are the unit of deployment, loading, and compilation.
 A module collects definitions for :ref:`types `, :ref:`functions `, :ref:`tables `, :ref:`memories `, and :ref:`globals `.
 In addition, it can declare :ref:`imports ` and :ref:`exports `
-and provide initialization logic in the form of active and passive :ref:`data ` and :ref:`element ` segments, or a :ref:`start function `.
+and provide initialization in the form of :ref:`active ` and :ref:`passive ` :ref:`data ` and :ref:`element ` segments, or a :ref:`start function `.
 
 .. math::
    \begin{array}{lllll}
@@ -228,7 +228,7 @@ Globals are referenced through :ref:`global indices `,
 starting with the smallest index not referencing a global :ref:`import `.
 
 
-.. index:: ! element, ! active, ! passive, element index, table, table index, expression, constant, function index, vector
+.. index:: ! element, active, passive, element index, table, table index, expression, constant, function index, vector
    pair: abstract syntax; element
    single: table; element
    single: element; segment
@@ -239,7 +239,7 @@ Element Segments
 
 The initial contents of a table is uninitialized. *Element segments* can be used to initialize a subrange of a table from a static :ref:`vector ` of elements.
 
-Element segments can be *active* or *passive*. An active element segment copies its elements into a table during :ref:`instantiation `. A passive element segment's elements can be copied using the |TABLEINIT| instruction.
+Element segments can be :ref:`active ` or :ref:`passive `. An active element segment copies its elements into a table during :ref:`instantiation `. A passive element segment's elements can be copied using the |TABLEINIT| instruction.
 
 The |MELEM| component of a module defines a vector of element segments. Each active element segment defines the |ETABLE| and the starting |EOFFSET| in that table to initialize. Each passive element segment only defines its contents.
 
@@ -270,7 +270,7 @@ Data Segments
 
 The initial contents of a :ref:`memory ` are zero bytes. *Data segments* can be used to initialize a range of memory from a static :ref:`vector ` of :ref:`bytes `.
 
-Like element segments, data segments can be active or passive. An active data segment copies its contents into a table during :ref:`instantiation `. A passive data segment's contents can be copied using the |MEMORYINIT| instruction.
+Like element segments, data segments can be :ref:`active ` or :ref:`passive `. An active data segment copies its contents into a table during :ref:`instantiation `. A passive data segment's contents can be copied using the |MEMORYINIT| instruction.
 
 The |MDATA| component of a module defines a vector of data segments. Each active data segment defines the memory to initialize, and the starting |DOFFSET| in that memory to initialize. Each passive data segment only defines its contents.
 
diff --git a/document/core/syntax/types.rst b/document/core/syntax/types.rst
index 012eff4c33..abe0289cc5 100644
--- a/document/core/syntax/types.rst
+++ b/document/core/syntax/types.rst
@@ -181,6 +181,25 @@ Global Types
    \end{array}
 
 
+.. index:: ! segtype, ! active, ! passive
+   pair: abstract syntax; segtype
+.. _syntax-segtype:
+.. _syntax-active:
+.. _syntax-passive:
+
+Segment Types
+~~~~~~~~~~~~~
+
+*Segment types* classify :ref:`data segments ` and :ref:`element segments `, which can either be *active* or *passive*.
+
+.. math::
+   \begin{array}{llll}
+   \production{segment type} & \segtype &::=&
+     \SACTIVE ~|~
+     \SPASSIVE \\
+   \end{array}
+
+
 .. index:: ! external type, function type, table type, memory type, global type, import, external value
    pair: abstract syntax; external type
    pair: external; type
diff --git a/document/core/util/macros.def b/document/core/util/macros.def
index e9cec168d5..ff4491e955 100644
--- a/document/core/util/macros.def
+++ b/document/core/util/macros.def
@@ -179,6 +179,9 @@
 .. |LMIN| mathdef:: \xref{syntax/types}{syntax-limits}{\K{min}}
 .. |LMAX| mathdef:: \xref{syntax/types}{syntax-limits}{\K{max}}
 
+.. |SACTIVE| mathdef:: \xref{syntax/types}{syntax-segtype}{\K{active}}
+.. |SPASSIVE| mathdef:: \xref{syntax/types}{syntax-segtype}{\K{passive}}
+
 .. |ETFUNC| mathdef:: \xref{syntax/types}{syntax-externtype}{\K{func}}
 .. |ETTABLE| mathdef:: \xref{syntax/types}{syntax-externtype}{\K{table}}
 .. |ETMEM| mathdef:: \xref{syntax/types}{syntax-externtype}{\K{mem}}
@@ -194,6 +197,7 @@
 .. |tabletype| mathdef:: \xref{syntax/types}{syntax-tabletype}{\X{tabletype}}
 .. |elemtype| mathdef:: \xref{syntax/types}{syntax-elemtype}{\X{elemtype}}
 .. |memtype| mathdef:: \xref{syntax/types}{syntax-memtype}{\X{memtype}}
+.. |segtype| mathdef:: \xref{syntax/types}{syntax-segtype}{\X{segtype}}
 
 .. |limits| mathdef:: \xref{syntax/types}{syntax-limits}{\X{limits}}
 .. |mut| mathdef:: \xref{syntax/types}{syntax-mut}{\X{mut}}
@@ -723,6 +727,8 @@
 .. |CTABLES| mathdef:: \xref{valid/conventions}{context}{\K{tables}}
 .. |CMEMS| mathdef:: \xref{valid/conventions}{context}{\K{mems}}
 .. |CGLOBALS| mathdef:: \xref{valid/conventions}{context}{\K{globals}}
+.. |CELEM| mathdef:: \xref{valid/conventions}{context}{\K{elem}}
+.. |CDATA| mathdef:: \xref{valid/conventions}{context}{\K{data}}
 .. |CLOCALS| mathdef:: \xref{valid/conventions}{context}{\K{locals}}
 .. |CLABELS| mathdef:: \xref{valid/conventions}{context}{\K{labels}}
 .. |CRETURN| mathdef:: \xref{valid/conventions}{context}{\K{return}}
diff --git a/document/core/valid/conventions.rst b/document/core/valid/conventions.rst
index 9e5f6f182b..3260818fb4 100644
--- a/document/core/valid/conventions.rst
+++ b/document/core/valid/conventions.rst
@@ -38,6 +38,8 @@ which collects relevant information about the surrounding :ref:`module ` :math:
         & \CTABLES & \tabletype^\ast, \\
         & \CMEMS & \memtype^\ast, \\
         & \CGLOBALS & \globaltype^\ast, \\
+        & \CELEM & \segtype^\ast, \\
+        & \CDATA & \segtype^\ast, \\
         & \CLOCALS & \valtype^\ast, \\
         & \CLABELS & \resulttype^\ast, \\
         & \CRETURN & \resulttype^? ~\} \\
diff --git a/document/core/valid/instructions.rst b/document/core/valid/instructions.rst
index dfb14ea893..a9fb729cd2 100644
--- a/document/core/valid/instructions.rst
+++ b/document/core/valid/instructions.rst
@@ -423,6 +423,149 @@ Memory Instructions
    }
 
 
+.. _valid-memory.init:
+
+:math:`\MEMORYINIT~x`
+.....................
+
+* The memory :math:`C.\CMEMS[0]` must be defined in the context.
+
+* The data segment :math:`C.\CDATA[x]` must be defined in the context.
+
+* The :ref:`segment type ` :math:`C.\CDATA[x]` must be |SPASSIVE|.
+
+* Then the instruction is valid with type :math:`[\I32~\I32~\I32] \to []`.
+
+.. math::
+   \frac{
+     C.\CMEMS[0] = \memtype
+     \qquad
+     C.\CDATA[x] = \SPASSIVE
+   }{
+     C \vdashinstr \MEMORYINIT~x : [\I32~\I32~\I32] \to []
+   }
+
+
+.. _valid-memory.drop:
+
+:math:`\MEMORYDROP~x`
+.....................
+
+* The data segment :math:`C.\CDATA[x]` must be defined in the context.
+
+* The :ref:`segment type ` :math:`C.\CDATA[x]` must be |SPASSIVE|.
+
+* Then the instruction is valid with type :math:`[] \to []`.
+
+.. math::
+   \frac{
+     C.\CDATA[x] = \SPASSIVE
+   }{
+     C \vdashinstr \MEMORYDROP~x : [] \to []
+   }
+
+
+.. _valid-memory.copy:
+
+:math:`\MEMORYCOPY`
+.....................
+
+* The memory :math:`C.\CMEMS[0]` must be defined in the context.
+
+* Then the instruction is valid with type :math:`[\I32~\I32~\I32] \to []`.
+
+.. math::
+   \frac{
+     C.\CMEMS[0] = \memtype
+   }{
+     C \vdashinstr \MEMORYCOPY : [\I32~\I32~\I32] \to []
+   }
+
+
+.. _valid-memory.fill:
+
+:math:`\MEMORYFILL`
+.....................
+
+* The memory :math:`C.\CMEMS[0]` must be defined in the context.
+
+* Then the instruction is valid with type :math:`[\I32~\I32~\I32] \to []`.
+
+.. math::
+   \frac{
+     C.\CMEMS[0] = \memtype
+   }{
+     C \vdashinstr \MEMORYFILL : [\I32~\I32~\I32] \to []
+   }
+
+
+.. index:: table instruction, table index, context
+   pair: validation; instruction
+   single: abstract syntax; instruction
+.. _valid-instr-table:
+
+Table Instructions
+~~~~~~~~~~~~~~~~~~
+
+.. _valid-table.init:
+
+:math:`\TABLEINIT~x`
+.....................
+
+* The table :math:`C.\CTABLES[0]` must be defined in the context.
+
+* The element segment :math:`C.\CELEM[x]` must be defined in the context.
+
+* The :ref:`segment type ` :math:`C.\CELEM[x]` must be |SPASSIVE|.
+
+* Then the instruction is valid with type :math:`[\I32~\I32~\I32] \to []`.
+
+.. math::
+   \frac{
+     C.\CTABLES[0] = \tabletype
+     \qquad
+     C.\CELEM[x] = \SPASSIVE
+   }{
+     C \vdashinstr \TABLEINIT~x : [\I32~\I32~\I32] \to []
+   }
+
+
+.. _valid-table.drop:
+
+:math:`\TABLEDROP~x`
+.....................
+
+* The element segment :math:`C.\CELEM[x]` must be defined in the context.
+
+* The :ref:`segment type ` :math:`C.\CELEM[x]` must be |SPASSIVE|.
+
+* Then the instruction is valid with type :math:`[] \to []`.
+
+.. math::
+   \frac{
+     C.\CELEM[x] = \SPASSIVE
+   }{
+     C \vdashinstr \TABLEDROP~x : [] \to []
+   }
+
+
+.. _valid-table.copy:
+
+:math:`\TABLECOPY`
+.....................
+
+* The table :math:`C.\CTABLES[0]` must be defined in the context.
+
+* Then the instruction is valid with type :math:`[\I32~\I32~\I32] \to []`.
+
+.. math::
+   \frac{
+     C.\CTABLES[0] = \tabletype
+   }{
+     C \vdashinstr \TABLECOPY : [\I32~\I32~\I32] \to []
+   }
+
+
 .. index:: control instructions, structured control, label, block, branch, result type, label index, function index, type index, vector, polymorphism, context
    pair: validation; instruction
    single: abstract syntax; instruction
diff --git a/document/core/valid/modules.rst b/document/core/valid/modules.rst
index 752500e520..46f316209c 100644
--- a/document/core/valid/modules.rst
+++ b/document/core/valid/modules.rst
@@ -145,7 +145,7 @@ Globals :math:`\global` are classified by :ref:`global types 
 Element Segments
 ~~~~~~~~~~~~~~~~
 
-Element segments :math:`\elem` are not classified by a type.
+Element segments :math:`\elem` are classified by :ref:`segment types `.
 
 :math:`\{ \ETABLE~x, \EOFFSET~\expr, \EINIT~y^\ast \}`
 ......................................................
@@ -163,7 +163,7 @@ Element segments :math:`\elem` are not classified by a type.
 * For each :math:`y_i` in :math:`y^\ast`,
   the function :math:`C.\CFUNCS[y]` must be defined in the context.
 
-* Then the element segment is valid.
+* Then the element segment is valid with type |SACTIVE|.
 
 
 .. math::
@@ -176,7 +176,24 @@ Element segments :math:`\elem` are not classified by a type.
      \qquad
      (C.\CFUNCS[y] = \functype)^\ast
    }{
-     C \vdashelem \{ \ETABLE~x, \EOFFSET~\expr, \EINIT~y^\ast \} \ok
+     C \vdashelem \{ \ETABLE~x, \EOFFSET~\expr, \EINIT~y^\ast \} : \SACTIVE
+   }
+
+
+:math:`\{ \EINIT~y^\ast \}`
+......................................................
+
+* For each :math:`y_i` in :math:`y^\ast`,
+  the function :math:`C.\CFUNCS[y]` must be defined in the context.
+
+* Then the element segment is valid with type |SPASSIVE|.
+
+
+.. math::
+   \frac{
+     (C.\CFUNCS[y] = \functype)^\ast
+   }{
+     C \vdashelem \{ \EINIT~y^\ast \} : \SPASSIVE
    }
 
 
@@ -190,7 +207,7 @@ Element segments :math:`\elem` are not classified by a type.
 Data Segments
 ~~~~~~~~~~~~~
 
-Data segments :math:`\data` are not classified by any type.
+Data segments :math:`\data` are classified by :ref:`segment types `.
 
 :math:`\{ \DMEM~x, \DOFFSET~\expr, \DINIT~b^\ast \}`
 ....................................................
@@ -201,7 +218,7 @@ Data segments :math:`\data` are not classified by any type.
 
 * The expression :math:`\expr` must be :ref:`constant `.
 
-* Then the data segment is valid.
+* Then the data segment is valid with type |SACTIVE|.
 
 
 .. math::
@@ -212,7 +229,20 @@ Data segments :math:`\data` are not classified by any type.
      \qquad
      C \vdashexprconst \expr \const
    }{
-     C \vdashdata \{ \DMEM~x, \DOFFSET~\expr, \DINIT~b^\ast \} \ok
+     C \vdashdata \{ \DMEM~x, \DOFFSET~\expr, \DINIT~b^\ast \} : \SACTIVE
+   }
+
+
+:math:`\{ \DINIT~b^\ast \}`
+....................................................
+
+* The data segment is valid.
+
+
+.. math::
+   \frac{
+   }{
+     C \vdashdata \{ \DINIT~b^\ast \} : \SPASSIVE
    }
 
 
@@ -465,6 +495,10 @@ Instead, the context :math:`C` for validation of the module's content is constru
   * :math:`C.\CGLOBALS` is :math:`\etglobals(\X{it}^\ast)` concatenated with :math:`\X{gt}^\ast`,
     with the import's :ref:`external types ` :math:`\X{it}^\ast` and the internal :ref:`global types ` :math:`\X{gt}^\ast` as determined below,
 
+  * :math:`C.\CELEM` is :math:`\X{est}^\ast`, with :ref:`segment types ` :math:`\X{est}^\ast` as determined below,
+
+  * :math:`C.\CDATA` is :math:`\X{dst}^\ast`, with :ref:`segment types ` :math:`\X{dst}^\ast` as determined below,
+
   * :math:`C.\CLOCALS` is empty,
 
   * :math:`C.\CLABELS` is empty,
@@ -493,10 +527,10 @@ Instead, the context :math:`C` for validation of the module's content is constru
       the definition :math:`\global_i` must be :ref:`valid ` with a :ref:`global type ` :math:`\X{gt}_i`.
 
   * For each :math:`\elem_i` in :math:`\module.\MELEM`,
-    the segment :math:`\elem_i` must be :ref:`valid `.
+    the segment :math:`\elem_i` must be :ref:`valid ` with a :ref:`segment type ` :math:`\X{est}_i`.
 
   * For each :math:`\data_i` in :math:`\module.\MDATA`,
-    the segment :math:`\data_i` must be :ref:`valid `.
+    the segment :math:`\data_i` must be :ref:`valid ` with a :ref:`segment type ` :math:`\X{dst}_i`.
 
   * If :math:`\module.\MSTART` is non-empty,
     then :math:`\module.\MSTART` must be :ref:`valid `.
@@ -521,6 +555,10 @@ Instead, the context :math:`C` for validation of the module's content is constru
 
 * Let :math:`\X{gt}^\ast` be the concatenation of the internal :ref:`global types ` :math:`\X{gt}_i`, in index order.
 
+* Let :math:`\X{est}^\ast` be the concatenation of the :ref:`segment types ` :math:`\X{est}_i`, in index order.
+
+* Let :math:`\X{dst}^\ast` be the concatenation of the :ref:`segment types ` :math:`\X{dst}_i`, in index order.
+
 * Let :math:`\X{it}^\ast` be the concatenation of :ref:`external types ` :math:`\X{it}_i` of the imports, in index order.
 
 * Let :math:`\X{et}^\ast` be the concatenation of :ref:`external types ` :math:`\X{et}_i` of the exports, in index order.
@@ -540,9 +578,9 @@ Instead, the context :math:`C` for validation of the module's content is constru
      \quad
      (C' \vdashglobal \global : \X{gt})^\ast
      \\
-     (C \vdashelem \elem \ok)^\ast
+     (C \vdashelem \elem : \X{est})^\ast
      \quad
-     (C \vdashdata \data \ok)^\ast
+     (C \vdashdata \data : \X{dst})^\ast
      \quad
      (C \vdashstart \start \ok)^?
      \quad
@@ -558,7 +596,7 @@ Instead, the context :math:`C` for validation of the module's content is constru
      \qquad
      \X{igt}^\ast = \etglobals(\X{it}^\ast)
      \\
-     C = \{ \CTYPES~\functype^\ast, \CFUNCS~\X{ift}^\ast~\X{ft}^\ast, \CTABLES~\X{itt}^\ast~\X{tt}^\ast, \CMEMS~\X{imt}^\ast~\X{mt}^\ast, \CGLOBALS~\X{igt}^\ast~\X{gt}^\ast \}
+     C = \{ \CTYPES~\functype^\ast, \CFUNCS~\X{ift}^\ast~\X{ft}^\ast, \CTABLES~\X{itt}^\ast~\X{tt}^\ast, \CMEMS~\X{imt}^\ast~\X{mt}^\ast, \CGLOBALS~\X{igt}^\ast~\X{gt}^\ast, \CELEM~\X{est}^\ast, \CDATA~\X{dst}^\ast \}
      \\
      C' = \{ \CGLOBALS~\X{igt}^\ast \}
      \qquad

From eeec7403cccd67300162e217c883102f0f872408 Mon Sep 17 00:00:00 2001
From: Andreas Rossberg 
Date: Sat, 12 May 2018 08:08:05 +0200
Subject: [PATCH 024/199] Link spec in README

---
 README.md               | 4 +++-
 document/core/index.rst | 2 +-
 2 files changed, 4 insertions(+), 2 deletions(-)

diff --git a/README.md b/README.md
index c202ce633e..ec165c54eb 100644
--- a/README.md
+++ b/README.md
@@ -5,7 +5,9 @@
 This repository is a clone of [github.com/WebAssembly/spec/](https://github.com/WebAssembly/spec/).
 It is meant for discussion, prototype specification and implementation of a proposal to add support for basic reference types to WebAssembly.
 
-See the [overview](proposals/reference-types/Overview.md) for a summary of the proposal.
+* See the [overview](proposals/reference-types/Overview.md) for a summary of the proposal.
+
+* See the [modified spec](https://webassembly.github.io/reference-types/core/) for details.
 
 Original `README` from upstream repository follows...
 
diff --git a/document/core/index.rst b/document/core/index.rst
index f6dca0a227..57d2972d65 100644
--- a/document/core/index.rst
+++ b/document/core/index.rst
@@ -3,7 +3,7 @@ WebAssembly Specification
 
 .. only:: html
 
-   Release |release| (Draft, last updated |today|)
+   Release |release| + reference types (Draft, last updated |today|)
 
 .. toctree::
    :maxdepth: 3

From 506907b64bac75bf7bc375f2867bcdc869cb1059 Mon Sep 17 00:00:00 2001
From: Ben Smith 
Date: Tue, 15 May 2018 08:54:31 -0700
Subject: [PATCH 025/199] [spec] Documentation of binary format (#17)

---
 document/core/binary/instructions.rst | 33 +++++++++++++++++++++++++--
 document/core/binary/modules.rst      | 32 ++++++++++++++++++++++----
 document/core/util/macros.def         |  2 ++
 3 files changed, 60 insertions(+), 7 deletions(-)

diff --git a/document/core/binary/instructions.rst b/document/core/binary/instructions.rst
index 7e4fbbb325..7f8a4764b1 100644
--- a/document/core/binary/instructions.rst
+++ b/document/core/binary/instructions.rst
@@ -126,6 +126,10 @@ Each variant of :ref:`memory instruction ` is encoded with
 .. _binary-storen:
 .. _binary-memory.size:
 .. _binary-memory.grow:
+.. _binary-memory.init:
+.. _binary-memory.drop:
+.. _binary-memory.copy:
+.. _binary-memory.fill:
 
 .. math::
    \begin{array}{llclll}
@@ -156,11 +160,36 @@ Each variant of :ref:`memory instruction ` is encoded with
      \hex{3D}~~m{:}\Bmemarg &\Rightarrow& \I64.\STORE\K{16}~m \\ &&|&
      \hex{3E}~~m{:}\Bmemarg &\Rightarrow& \I64.\STORE\K{32}~m \\ &&|&
      \hex{3F}~~\hex{00} &\Rightarrow& \MEMORYSIZE \\ &&|&
-     \hex{40}~~\hex{00} &\Rightarrow& \MEMORYGROW \\
+     \hex{40}~~\hex{00} &\Rightarrow& \MEMORYGROW \\ &&|&
+     \hex{FC}~\hex{08}~~x{:}\Bdataidx &\Rightarrow& \MEMORYINIT~x \\ &&|&
+     \hex{FC}~\hex{09}~~x{:}\Bdataidx &\Rightarrow& \MEMORYDROP~x \\ &&|&
+     \hex{FC}~\hex{0A}~~\hex{00} &\Rightarrow& \MEMORYCOPY \\ &&|&
+     \hex{FC}~\hex{0B}~~\hex{00} &\Rightarrow& \MEMORYFILL \\
    \end{array}
 
 .. note::
-   In future versions of WebAssembly, the additional zero bytes occurring in the encoding of the |MEMORYSIZE| and |MEMORYGROW| instructions may be used to index additional memories.
+   In future versions of WebAssembly, the additional zero bytes occurring in the encoding of the |MEMORYSIZE|, |MEMORYGROW|, |MEMORYCOPY|, and |MEMORYFILL| instructions may be used to index additional memories.
+
+
+Table Instructions
+~~~~~~~~~~~~~~~~~~
+
+Each variant of :ref:`table instruction ` is encoded with a different byte code.
+
+.. _binary-table.init:
+.. _binary-table.drop:
+.. _binary-table.copy:
+
+.. math::
+   \begin{array}{llclll}
+   \production{instruction} & \Binstr &::=& \dots \\ &&|&
+     \hex{FC}~\hex{0C}~~x{:}\Belemidx &\Rightarrow& \TABLEINIT~x \\ &&|&
+     \hex{FC}~\hex{0D}~~x{:}\Belemidx &\Rightarrow& \TABLEDROP~x \\ &&|&
+     \hex{FC}~\hex{0E}~~\hex{00} &\Rightarrow& \TABLECOPY \\
+   \end{array}
+
+.. note::
+   In future versions of WebAssembly, the additional zero byte occurring in the encoding of the |TABLECOPY| instruction may be used to index an additional table.
 
 
 .. index:: numeric instruction
diff --git a/document/core/binary/modules.rst b/document/core/binary/modules.rst
index b667314984..cee7749515 100644
--- a/document/core/binary/modules.rst
+++ b/document/core/binary/modules.rst
@@ -9,12 +9,14 @@ except that :ref:`function definitions ` are split into two section
    This separation enables *parallel* and *streaming* compilation of the functions in a module.
 
 
-.. index:: index, type index, function index, table index, memory index, global index, local index, label index
+.. index:: index, type index, function index, table index, memory index, global index, element index, data index, local index, label index
    pair: binary format; type index
    pair: binary format; function index
    pair: binary format; table index
    pair: binary format; memory index
    pair: binary format; global index
+   pair: binary format; element index
+   pair: binary format; data index
    pair: binary format; local index
    pair: binary format; label index
 .. _binary-typeidx:
@@ -22,6 +24,8 @@ except that :ref:`function definitions ` are split into two section
 .. _binary-tableidx:
 .. _binary-memidx:
 .. _binary-globalidx:
+.. _binary-elemidx:
+.. _binary-dataidx:
 .. _binary-localidx:
 .. _binary-labelidx:
 .. _binary-index:
@@ -38,6 +42,8 @@ All :ref:`indices ` are encoded with their respective value.
    \production{table index} & \Btableidx &::=& x{:}\Bu32 &\Rightarrow& x \\
    \production{memory index} & \Bmemidx &::=& x{:}\Bu32 &\Rightarrow& x \\
    \production{global index} & \Bglobalidx &::=& x{:}\Bu32 &\Rightarrow& x \\
+   \production{element index} & \Belemidx &::=& x{:}\Bu32 &\Rightarrow& x \\
+   \production{data index} & \Bdataidx &::=& x{:}\Bu32 &\Rightarrow& x \\
    \production{local index} & \Blocalidx &::=& x{:}\Bu32 &\Rightarrow& x \\
    \production{label index} & \Blabelidx &::=& l{:}\Bu32 &\Rightarrow& l \\
    \end{array}
@@ -319,10 +325,18 @@ It decodes into a vector of :ref:`element segments ` that represent
    \production{element section} & \Belemsec &::=&
      \X{seg}^\ast{:}\Bsection_9(\Bvec(\Belem)) &\Rightarrow& \X{seg} \\
    \production{element segment} & \Belem &::=&
-     x{:}\Btableidx~~e{:}\Bexpr~~y^\ast{:}\Bvec(\Bfuncidx)
-       &\Rightarrow& \{ \ETABLE~x, \EOFFSET~e, \EINIT~y^\ast \} \\
+     \hex{00}~~e{:}\Bexpr~~y^\ast{:}\Bvec(\Bfuncidx)
+       &\Rightarrow& \{ \ETABLE~0, \EOFFSET~e, \EINIT~y^\ast \} \\
+   \production{element segment} & \Belem &::=&
+     \hex{01}~~y^\ast{:}\Bvec(\Bfuncidx)
+       &\Rightarrow& \{ \EINIT~y^\ast \} \\
    \end{array}
 
+.. note::
+   In the current version of WebAssembly, at most one table may be defined or
+   imported in a single module, so all valid :ref:`active `
+   element segments have a |ETABLE| value of :math:`0`.
+
 
 .. index:: ! code section, function, local, type index, function type
    pair: binary format; function
@@ -400,10 +414,18 @@ It decodes into a vector of :ref:`data segments ` that represent th
    \production{data section} & \Bdatasec &::=&
      \X{seg}^\ast{:}\Bsection_{11}(\Bvec(\Bdata)) &\Rightarrow& \X{seg} \\
    \production{data segment} & \Bdata &::=&
-     x{:}\Bmemidx~~e{:}\Bexpr~~b^\ast{:}\Bvec(\Bbyte)
-       &\Rightarrow& \{ \DMEM~x, \DOFFSET~e, \DINIT~b^\ast \} \\
+     \hex{00}~~e{:}\Bexpr~~b^\ast{:}\Bvec(\Bbyte)
+       &\Rightarrow& \{ \DMEM~0, \DOFFSET~e, \DINIT~b^\ast \} \\
+   \production{data segment} & \Bdata &::=&
+     \hex{01}~~b^\ast{:}\Bvec(\Bbyte)
+       &\Rightarrow& \{ \DINIT~b^\ast \} \\
    \end{array}
 
+.. note::
+   In the current version of WebAssembly, at most one memory may be defined or
+   imported in a single module, so all valid :ref:`active ` data
+   segments have a |DMEM| value of :math:`0`.
+
 
 .. index:: module, section, type definition, function type, function, table, memory, global, element, data, start function, import, export, context, version
    pair: binary format; module
diff --git a/document/core/util/macros.def b/document/core/util/macros.def
index ff4491e955..657ec4ce92 100644
--- a/document/core/util/macros.def
+++ b/document/core/util/macros.def
@@ -478,6 +478,8 @@
 .. |Btableidx| mathdef:: \xref{binary/modules}{binary-tableidx}{\B{tableidx}}
 .. |Bmemidx| mathdef:: \xref{binary/modules}{binary-memidx}{\B{memidx}}
 .. |Bglobalidx| mathdef:: \xref{binary/modules}{binary-globalidx}{\B{globalidx}}
+.. |Belemidx| mathdef:: \xref{binary/modules}{binary-elemidx}{\B{elemidx}}
+.. |Bdataidx| mathdef:: \xref{binary/modules}{binary-dataidx}{\B{dataidx}}
 .. |Blocalidx| mathdef:: \xref{binary/modules}{binary-localidx}{\B{localidx}}
 .. |Blabelidx| mathdef:: \xref{binary/modules}{binary-labelidx}{\B{labelidx}}
 

From 008e5522b213632432f53a28b5ee79f542407696 Mon Sep 17 00:00:00 2001
From: Ben Smith 
Date: Thu, 31 May 2018 14:33:45 -0700
Subject: [PATCH 026/199] [spec] Documentation of text format (#18)

---
 document/core/text/conventions.rst  |  2 ++
 document/core/text/instructions.rst | 26 +++++++++++++++++++++++++-
 document/core/text/modules.rst      | 26 +++++++++++++++++++++-----
 document/core/util/macros.def       |  4 ++++
 4 files changed, 52 insertions(+), 6 deletions(-)

diff --git a/document/core/text/conventions.rst b/document/core/text/conventions.rst
index 1d87c8ce79..ad9e29d4ab 100644
--- a/document/core/text/conventions.rst
+++ b/document/core/text/conventions.rst
@@ -122,6 +122,8 @@ It is convenient to define identifier contexts as :ref:`records ` to ide
 .. math::
    \begin{array}{llclll}
    \production{element segment} & \Telem_I &::=&
-     \text{(}~\text{elem}~~x{:}\Ttableidx_I~~\text{(}~\text{offset}~~e{:}\Texpr_I~\text{)}~~y^\ast{:}\Tvec(\Tfuncidx_I)~\text{)} \\ &&& \qquad
-       \Rightarrow\quad \{ \ETABLE~x, \EOFFSET~e, \EINIT~y^\ast \} \\
+     \text{(}~\text{elem}~~\Tid^?~~x{:}\Ttableidx_I~~\text{(}~\text{offset}~~e{:}\Texpr_I~\text{)}~~y^\ast{:}\Tvec(\Tfuncidx_I)~\text{)} \\ &&& \qquad
+       \Rightarrow\quad \{ \ETABLE~x, \EOFFSET~e, \EINIT~y^\ast \} \\ &&|&
+     \text{(}~\text{elem}~~\Tid^?~~\text{passive}~~y^\ast{:}\Tvec(\Tfuncidx_I)~\text{)} \\ &&& \qquad
+       \Rightarrow\quad \{ \EINIT~y^\ast \} \\
    \end{array}
 
 .. note::
@@ -525,8 +535,10 @@ The data is written as a :ref:`string `, which may be split up into
 .. math::
    \begin{array}{llclll}
    \production{data segment} & \Tdata_I &::=&
-     \text{(}~\text{data}~~x{:}\Tmemidx_I~~\text{(}~\text{offset}~~e{:}\Texpr_I~\text{)}~~b^\ast{:}\Tdatastring~\text{)} \\ &&& \qquad
-       \Rightarrow\quad \{ \DMEM~x', \DOFFSET~e, \DINIT~b^\ast \} \\[1ex]
+     \text{(}~\text{data}~~\Tid^?~~x{:}\Tmemidx_I~~\text{(}~\text{offset}~~e{:}\Texpr_I~\text{)}~~b^\ast{:}\Tdatastring~\text{)} \\ &&& \qquad
+       \Rightarrow\quad \{ \DMEM~x', \DOFFSET~e, \DINIT~b^\ast \} \\ &&|&
+     \text{(}~\text{data}~~\Tid^?~~\text{passive}~~b^\ast{:}\Tdatastring~\text{)} \\ &&& \qquad
+       \Rightarrow\quad \{ \DINIT~b^\ast \} \\
    \production{data string} & \Tdatastring &::=&
      (b^\ast{:}\Tstring)^\ast \quad\Rightarrow\quad \concat((b^\ast)^\ast) \\
    \end{array}
@@ -631,6 +643,10 @@ The definition of the initial :ref:`identifier context ` :math:`I`
      \{\IMEMS~(\Tid^?)\} \\
    \F{idc}(\text{(}~\text{global}~\Tid^?~\dots~\text{)}) &=&
      \{\IGLOBALS~(\Tid^?)\} \\
+   \F{idc}(\text{(}~\text{elem}~\Tid^?~\dots~\text{)}) &=&
+     \{\IELEM~(\Tid^?)\} \\
+   \F{idc}(\text{(}~\text{data}~\Tid^?~\dots~\text{)}) &=&
+     \{\IDATA~(\Tid^?)\} \\
    \F{idc}(\text{(}~\text{import}~\dots~\text{(}~\text{func}~\Tid^?~\dots~\text{)}~\text{)}) &=&
      \{\IFUNCS~(\Tid^?)\} \\
    \F{idc}(\text{(}~\text{import}~\dots~\text{(}~\text{table}~\Tid^?~\dots~\text{)}~\text{)}) &=&
diff --git a/document/core/util/macros.def b/document/core/util/macros.def
index 657ec4ce92..ce5596a1fc 100644
--- a/document/core/util/macros.def
+++ b/document/core/util/macros.def
@@ -639,6 +639,8 @@
 .. |Ttableidx| mathdef:: \xref{text/modules}{text-tableidx}{\T{tableidx}}
 .. |Tmemidx| mathdef:: \xref{text/modules}{text-memidx}{\T{memidx}}
 .. |Tglobalidx| mathdef:: \xref{text/modules}{text-globalidx}{\T{globalidx}}
+.. |Telemidx| mathdef:: \xref{text/modules}{text-elemidx}{\T{elemidx}}
+.. |Tdataidx| mathdef:: \xref{text/modules}{text-dataidx}{\T{dataidx}}
 .. |Tlocalidx| mathdef:: \xref{text/modules}{text-localidx}{\T{localidx}}
 .. |Tlabelidx| mathdef:: \xref{text/modules}{text-labelidx}{\T{labelidx}}
 
@@ -701,6 +703,8 @@
 .. |ITABLES| mathdef:: \xref{text/conventions}{text-context}{\K{tables}}
 .. |IMEMS| mathdef:: \xref{text/conventions}{text-context}{\K{mems}}
 .. |IGLOBALS| mathdef:: \xref{text/conventions}{text-context}{\K{globals}}
+.. |IELEM| mathdef:: \xref{text/conventions}{text-context}{\K{elem}}
+.. |IDATA| mathdef:: \xref{text/conventions}{text-context}{\K{data}}
 .. |ILOCALS| mathdef:: \xref{text/conventions}{text-context}{\K{locals}}
 .. |ILABELS| mathdef:: \xref{text/conventions}{text-context}{\K{labels}}
 

From d50d7e5080f681342a00b7fbc1cbbe43b377ccec Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Istv=C3=A1n=20Szmozs=C3=A1nszky?= 
Date: Sat, 9 Jun 2018 13:34:31 +0200
Subject: [PATCH 027/199] Fix links to broken/obsolete proposals (#15)

---
 proposals/reference-types/Overview.md | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/proposals/reference-types/Overview.md b/proposals/reference-types/Overview.md
index c666029619..8f2d8576dc 100644
--- a/proposals/reference-types/Overview.md
+++ b/proposals/reference-types/Overview.md
@@ -18,8 +18,8 @@ by repurposing tables as a general memory for opaque data types
 * Set the stage for later additions:
 
   - Typed function references (see [below](#typed-function-references))
-  - Exception references (see the [exception handling proposal](https://github.com/WebAssembly/exception-handling/blob/master/proposals/Exceptions.md) and [here](https://github.com/WebAssembly/host-bindings/issues/10))
-  - A smoother transition path to GC (see the [GC proposal](https://github.com/WebAssembly/gc/blob/master/proposals/GC.md))
+  - Exception references (see the [exception handling proposal](https://github.com/WebAssembly/exception-handling/blob/master/proposals/Level-1.md) and [here](https://github.com/WebAssembly/host-bindings/issues/10))
+  - A smoother transition path to GC (see the [GC proposal](https://github.com/WebAssembly/gc/blob/master/proposals/gc/Overview.md))
 
 Get the most important parts soon!
 

From f4bdb3a9663710880475098f3cd1e66eda995815 Mon Sep 17 00:00:00 2001
From: Andreas Rossberg 
Date: Sun, 15 Jul 2018 12:15:09 +0200
Subject: [PATCH 028/199] Remove eqref remainders

---
 document/js-api/index.bs | 5 -----
 1 file changed, 5 deletions(-)

diff --git a/document/js-api/index.bs b/document/js-api/index.bs
index 611e812c5d..23ef2586e7 100644
--- a/document/js-api/index.bs
+++ b/document/js-api/index.bs
@@ -143,7 +143,6 @@ urlPrefix: https://webassembly.github.io/spec/core/; spec: WebAssembly; type: df
         text: 𝖿𝟨𝟦
     url: syntax/types.html#syntax-reftype
         text: anyref
-        text: eqref
         text: anyfunc
     text: function element; url: exec/runtime.html#syntax-funcelem
     text: import component; url: syntax/modules.html#imports
@@ -600,7 +599,6 @@ which can be simultaneously referenced by multiple {{Instance}} objects. Each
 
 enum TableKind {
   "anyref",
-  "eqref",
   "anyfunc",
   // Note: More values may be added in future iterations,
   // e.g., typed function references, typed GC references
@@ -824,9 +822,6 @@ Assert: |type| is not [=𝗂𝟨𝟦=].
     1. Return [=𝖿𝟨𝟦.𝖼𝗈𝗇𝗌𝗍=] |f64|.
 1. If |type| is [=anyref=],
     1. Return the result of [=allocating a host address=] for |v|.
-1. If |type| is [=eqref=],
-    1. If |v| is a primitive value but not a symbol or null, throw |error|.
-    1. Return the result of [=allocating a host address=] for |v|.
 1. If |type| is [=anyfunc=],
     1. If |v| is not an [=Exported function=] or null, throw |error|.
     1. Return the result of [=allocating a host address=] for |v|.

From bf6e067ccf30de288fc6c6d9a0ae5094838f17ce Mon Sep 17 00:00:00 2001
From: Andreas Rossberg 
Date: Sun, 15 Jul 2018 12:16:56 +0200
Subject: [PATCH 029/199] Update overview

---
 proposals/reference-types/Overview.md | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/proposals/reference-types/Overview.md b/proposals/reference-types/Overview.md
index 8f2d8576dc..a570a04ca8 100644
--- a/proposals/reference-types/Overview.md
+++ b/proposals/reference-types/Overview.md
@@ -97,8 +97,7 @@ Table extensions:
 
 API extensions:
 
-* Any JS object (non-primitive value) or string or symbol or `null` can be passed as `anyref` to a Wasm function, stored in a global, or in a table.
-  - It may be possible to allow all JS values into `anyref`, but or some engines that would imply possible boxing at the boundary.
+* Any JS value can be passed as `anyref` to a Wasm function, stored in a global, or in a table.
 
 * Any Wasm exported function object or `null` can be passed as `anyfunc` to a Wasm function, stored in a global, or in a table.
 

From b022826e5cdda3c72b3b14e05203f5552e929ac0 Mon Sep 17 00:00:00 2001
From: Sergey Rubanov 
Date: Wed, 29 Aug 2018 08:55:58 +0300
Subject: [PATCH 030/199] Update link to GC proposal overview (#16)

---
 proposals/reference-types/Overview.md | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/proposals/reference-types/Overview.md b/proposals/reference-types/Overview.md
index a570a04ca8..9b19db1256 100644
--- a/proposals/reference-types/Overview.md
+++ b/proposals/reference-types/Overview.md
@@ -229,7 +229,7 @@ Note:
 
 ### GC Types
 
-See [GC proposal](https://github.com/WebAssembly/gc/blob/master/proposals/GC.md).
+See [GC proposal](https://github.com/WebAssembly/gc/blob/master/proposals/gc/Overview.md).
 
 
 ### Further possible generalisations

From 872fcfa4d89b54839b1b8ff852f787b636c071bd Mon Sep 17 00:00:00 2001
From: Andrew Scheidecker 
Date: Tue, 11 Sep 2018 11:07:38 -0700
Subject: [PATCH 031/199] Tweak segment encoding to keep memory/table index
 encoding (#28)

The current state seems to remove the placeholder table/memory index from the encoding to use it as an active flag.
---
 document/core/binary/modules.rst             | 6 ++++++
 proposals/bulk-memory-operations/Overview.md | 7 ++++---
 2 files changed, 10 insertions(+), 3 deletions(-)

diff --git a/document/core/binary/modules.rst b/document/core/binary/modules.rst
index cee7749515..d0309d6bd8 100644
--- a/document/core/binary/modules.rst
+++ b/document/core/binary/modules.rst
@@ -330,6 +330,9 @@ It decodes into a vector of :ref:`element segments ` that represent
    \production{element segment} & \Belem &::=&
      \hex{01}~~y^\ast{:}\Bvec(\Bfuncidx)
        &\Rightarrow& \{ \EINIT~y^\ast \} \\
+   \production{element segment} & \Belem &::=&
+     \hex{02}~~x{:}\Btableidx~~e{:}\Bexpr~~y^\ast{:}\Bvec(\Bfuncidx)
+       &\Rightarrow& \{ \ETABLE~x, \EOFFSET~e, \EINIT~y^\ast \} \\
    \end{array}
 
 .. note::
@@ -419,6 +422,9 @@ It decodes into a vector of :ref:`data segments ` that represent th
    \production{data segment} & \Bdata &::=&
      \hex{01}~~b^\ast{:}\Bvec(\Bbyte)
        &\Rightarrow& \{ \DINIT~b^\ast \} \\
+   \production{data segment} & \Bdata &::=&
+     \hex{02}~~x{:}\Bmemidx~~e{:}\Bexpr~~b^\ast{:}\Bvec(\Bbyte)
+       &\Rightarrow& \{ \DMEM~x, \DOFFSET~e, \DINIT~b^\ast \} \\
    \end{array}
 
 .. note::
diff --git a/proposals/bulk-memory-operations/Overview.md b/proposals/bulk-memory-operations/Overview.md
index de5e7b11b6..43d7067671 100644
--- a/proposals/bulk-memory-operations/Overview.md
+++ b/proposals/bulk-memory-operations/Overview.md
@@ -190,9 +190,10 @@ Attempting to drop an active segment is a validation error.
 The data section is encoded as follows:
 
 ```
-datasec ::= seg*:section_11(vec(data))   => seg
-data    ::= 0x00 e:expr b*:vec(byte)     => {data 0, offset e, init b*, active true}
-data    ::= 0x01 b*:vec(byte)            => {data 0, offset empty, init b*, active false}
+datasec ::= seg*:section_11(vec(data))        => seg
+data    ::= 0x00 e:expr b*:vec(byte)          => {data 0, offset e,     init b*, active true }
+data    ::= 0x01 b*:vec(byte)                 => {data 0, offset empty, init b*, active false}
+data    ::= 0x02 x:memidx e:expr b*:vec(byte) => {data x, offset e,     init b*, active true }
 ```
 
 The element section is encoded similarly.

From 4123d1e7a37e66a3dbf91b57d6776648a3f05566 Mon Sep 17 00:00:00 2001
From: Andrew Scheidecker 
Date: Wed, 19 Sep 2018 23:04:44 -0400
Subject: [PATCH 032/199] Don't statically validate whether the segment index
 immediates of `memory.init`, `memory.drop`, `table.init`, and `table.drop`
 identify passive segments; only that they index a valid segment. (#31)

---
 document/core/valid/instructions.rst         | 14 ++++---------
 proposals/bulk-memory-operations/Overview.md | 21 +++++++++++++-------
 2 files changed, 18 insertions(+), 17 deletions(-)

diff --git a/document/core/valid/instructions.rst b/document/core/valid/instructions.rst
index a9fb729cd2..988faf2600 100644
--- a/document/core/valid/instructions.rst
+++ b/document/core/valid/instructions.rst
@@ -432,15 +432,13 @@ Memory Instructions
 
 * The data segment :math:`C.\CDATA[x]` must be defined in the context.
 
-* The :ref:`segment type ` :math:`C.\CDATA[x]` must be |SPASSIVE|.
-
 * Then the instruction is valid with type :math:`[\I32~\I32~\I32] \to []`.
 
 .. math::
    \frac{
      C.\CMEMS[0] = \memtype
      \qquad
-     C.\CDATA[x] = \SPASSIVE
+     C.\CDATA[x] = \segtype
    }{
      C \vdashinstr \MEMORYINIT~x : [\I32~\I32~\I32] \to []
    }
@@ -459,7 +457,7 @@ Memory Instructions
 
 .. math::
    \frac{
-     C.\CDATA[x] = \SPASSIVE
+     C.\CDATA[x] = \segtype
    }{
      C \vdashinstr \MEMORYDROP~x : [] \to []
    }
@@ -516,15 +514,13 @@ Table Instructions
 
 * The element segment :math:`C.\CELEM[x]` must be defined in the context.
 
-* The :ref:`segment type ` :math:`C.\CELEM[x]` must be |SPASSIVE|.
-
 * Then the instruction is valid with type :math:`[\I32~\I32~\I32] \to []`.
 
 .. math::
    \frac{
      C.\CTABLES[0] = \tabletype
      \qquad
-     C.\CELEM[x] = \SPASSIVE
+     C.\CELEM[x] = \segtype
    }{
      C \vdashinstr \TABLEINIT~x : [\I32~\I32~\I32] \to []
    }
@@ -537,13 +533,11 @@ Table Instructions
 
 * The element segment :math:`C.\CELEM[x]` must be defined in the context.
 
-* The :ref:`segment type ` :math:`C.\CELEM[x]` must be |SPASSIVE|.
-
 * Then the instruction is valid with type :math:`[] \to []`.
 
 .. math::
    \frac{
-     C.\CELEM[x] = \SPASSIVE
+     C.\CELEM[x] = \segtype
    }{
      C \vdashinstr \TABLEDROP~x : [] \to []
    }
diff --git a/proposals/bulk-memory-operations/Overview.md b/proposals/bulk-memory-operations/Overview.md
index 43d7067671..73e8635084 100644
--- a/proposals/bulk-memory-operations/Overview.md
+++ b/proposals/bulk-memory-operations/Overview.md
@@ -180,12 +180,14 @@ the following new instructions:
 A passive segment has no initializer expression, since it will be specified
 as an operand to `memory.init` or `table.init`.
 
-Passive segments can also be discarded by using the following new instructions:
+Segments can also be discarded by using the following new instructions:
 
 * `memory.drop`: prevent further use of a data segment
 * `table.drop`: prevent further use of an element segment
 
-Attempting to drop an active segment is a validation error.
+An active segment is equivalent to a passive segment, but with an implicit
+`memory.init` followed by a `memory.drop` (or `table.init` followed by a
+`table.drop`) that is prepended to the module's start function.
 
 The data section is encoded as follows:
 
@@ -200,7 +202,7 @@ The element section is encoded similarly.
 
 ### `memory.init` instruction
 
-The `memory.init` instruction copies data from a given passive segment into a target
+The `memory.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.
@@ -211,10 +213,12 @@ step 11 of
 but it behaves as though the segment were specified with the source offset,
 target offset, and length as given by the `memory.init` operands.
 
-It is a validation error to use `memory.init` with an active segment.
+It is a validation error to use `memory.init` with an out-of-bounds segment index.
 
 A trap occurs if:
-* the segment is used after it has been dropped via `memory.drop`
+* the segment is used after it has been dropped via `memory.drop`. This includes
+  active segments that were dropped after being copied into memory during module
+  instantiation.
 * any of the accessed bytes lies outside the source data segment or the target memory
 
 Note that it is allowed to use `memory.init` on the same data segment more than
@@ -228,7 +232,10 @@ 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.
 
-It is a validation error to use `memory.drop` with an active segment.
+It is a validation error to use `memory.drop` with an out-of-bounds segment index.
+
+A trap occurs if the segment was already dropped. This includes active segments
+that were dropped after being copied into memory during module instantiation.
 
 ### `memory.copy` instruction
 
@@ -260,7 +267,7 @@ the difference that they operate on element segments and tables, instead of
 data segments and memories. The offset and length operands of `table.init` and
 `table.copy` have element units instead of bytes as well.
 
-## Conditional Segment Initialization Example
+## Passive Segment Initialization Example
 
 Consider if there are two data sections, the first is always active and the
 second is conditionally active if global 0 has a non-zero value. This could be

From 7ea73f793209b29f3dde28e2a63a9a7268cb33dd Mon Sep 17 00:00:00 2001
From: Ben Smith 
Date: Fri, 5 Oct 2018 12:51:05 -0700
Subject: [PATCH 033/199] Add memory index for {memory,table}.init (#33)

---
 document/core/binary/instructions.rst | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/document/core/binary/instructions.rst b/document/core/binary/instructions.rst
index 7f8a4764b1..bc583f63cf 100644
--- a/document/core/binary/instructions.rst
+++ b/document/core/binary/instructions.rst
@@ -161,7 +161,7 @@ Each variant of :ref:`memory instruction ` is encoded with
      \hex{3E}~~m{:}\Bmemarg &\Rightarrow& \I64.\STORE\K{32}~m \\ &&|&
      \hex{3F}~~\hex{00} &\Rightarrow& \MEMORYSIZE \\ &&|&
      \hex{40}~~\hex{00} &\Rightarrow& \MEMORYGROW \\ &&|&
-     \hex{FC}~\hex{08}~~x{:}\Bdataidx &\Rightarrow& \MEMORYINIT~x \\ &&|&
+     \hex{FC}~\hex{08}~~\hex{00}~x{:}\Bdataidx &\Rightarrow& \MEMORYINIT~x \\ &&|&
      \hex{FC}~\hex{09}~~x{:}\Bdataidx &\Rightarrow& \MEMORYDROP~x \\ &&|&
      \hex{FC}~\hex{0A}~~\hex{00} &\Rightarrow& \MEMORYCOPY \\ &&|&
      \hex{FC}~\hex{0B}~~\hex{00} &\Rightarrow& \MEMORYFILL \\
@@ -183,7 +183,7 @@ Each variant of :ref:`table instruction ` is encoded with a
 .. math::
    \begin{array}{llclll}
    \production{instruction} & \Binstr &::=& \dots \\ &&|&
-     \hex{FC}~\hex{0C}~~x{:}\Belemidx &\Rightarrow& \TABLEINIT~x \\ &&|&
+     \hex{FC}~\hex{0C}~~\hex{00}~x{:}\Belemidx &\Rightarrow& \TABLEINIT~x \\ &&|&
      \hex{FC}~\hex{0D}~~x{:}\Belemidx &\Rightarrow& \TABLEDROP~x \\ &&|&
      \hex{FC}~\hex{0E}~~\hex{00} &\Rightarrow& \TABLECOPY \\
    \end{array}

From b73c0797ee2a5ee36f406a27560c2de31ed91293 Mon Sep 17 00:00:00 2001
From: Alex Crichton 
Date: Fri, 5 Oct 2018 13:57:12 -0700
Subject: [PATCH 034/199] Clarify some encoding/semantics (#32)

I recently looked into adding support for bulk memory operations into
some Rust tooling in preparation for an overall threading story, and on
reading the overview here I was slightly confused about a few encodings
and some semantics. In the end I'm hopeful that these updates can help
clarify these for future readers! No major functional change is intended
here, only tweaks to wording and clarification of what I believe the
original intent of the instructions were.

Changes made were:

* Fixed a broken `modules.html` link
* Clarified some wording about how the new encoding of data segments
  with a flags field up front is backwards compatible.
* Lifted the style of specifying encodings in `BinaryEncoding.md` to
  replace the current table for the new encoding of a data section. (I
  found this to be a bit more readable, but it should be functionally
  the same!)
* Update `memory.*` instructions (and transitively `table.*`) to all be
  succeeded by an immediate index of which memory/table to operate over.
  This should, in the future, allow initializing/dropping data segments
  with multiple memories in play.
* Updated the chart of instruction binary encodings to explicitly
  specify the following immediates of segments and tables.
---
 proposals/bulk-memory-operations/Overview.md | 70 ++++++++++++--------
 1 file changed, 44 insertions(+), 26 deletions(-)

diff --git a/proposals/bulk-memory-operations/Overview.md b/proposals/bulk-memory-operations/Overview.md
index 73e8635084..01ed57174d 100644
--- a/proposals/bulk-memory-operations/Overview.md
+++ b/proposals/bulk-memory-operations/Overview.md
@@ -162,14 +162,16 @@ Filling a memory region can be accomplished with `memory.fill`:
 
 TODO: should we provide `memory.clear` and `table.clear` instead?
 
-The [binary format for the data section](https://webassembly.github.io/spec/binary/modules.html#data-section)
+The [binary format for the data
+section](https://webassembly.github.io/spec/core/binary/modules.html#binary-datasec)
 currently has a collection of segments, each of which has a memory index, an
 initializer expression for its offset, and its raw data.
 
 Since WebAssembly currently does not allow for multiple memories, the memory
-index must be zero. We can repurpose this field as a flags field.
+index of each segment must be zero, which when represented as a `varuint32` is
+a single zero byte. We can repurpose this byte as a flags field.
 
-When the least-significant bit of the flags field is `1`, this segment is
+When the least-significant bit of this new flags field is `1`, this segment is
 _passive_. A passive segment will not be automatically copied into the
 memory or table on instantiation, and must instead be applied manually using
 the following new instructions:
@@ -189,23 +191,29 @@ An active segment is equivalent to a passive segment, but with an implicit
 `memory.init` followed by a `memory.drop` (or `table.init` followed by a
 `table.drop`) that is prepended to the module's start function.
 
-The data section is encoded as follows:
+The new encoding of a data segment is now:
 
-```
-datasec ::= seg*:section_11(vec(data))        => seg
-data    ::= 0x00 e:expr b*:vec(byte)          => {data 0, offset e,     init b*, active true }
-data    ::= 0x01 b*:vec(byte)                 => {data 0, offset empty, init b*, active false}
-data    ::= 0x02 x:memidx e:expr b*:vec(byte) => {data x, offset e,     init b*, active true }
-```
+| Field | Type | Description |
+|------|-------|-------------|
+| flags | `uint8` | Flags for passive and presence of fields below, only values of 0, 1, and 2 are valid |
+| index | `varuint32`? | Memory index this segment is for, only present if `flags` is 2, otherwise the index is implicitly 0 |
+| offset | `init_expr`? | an `i32` initializer expression for offset, not present if `flags & 0x1` is set |
+| size | `varuint32` | size of `data` (in bytes) |
+| data | `bytes` | sequence of `size` bytes |
 
-The element section is encoded similarly.
+An element segment (for tables) is encoded similarly by repurposing its table
+index (which is required to be zero) as a flags field.
 
 ### `memory.init` instruction
 
-The `memory.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.
+The `memory.init` instruction copies data from a given passive segment into a target
+memory. The target memory and source segment are given as immediates.
+
+The instruction has the signature `[i32 i32 i32] -> []`. The parameters are, in order:
+
+- top-2: destination address
+- top-1: offset into the source segment
+- top-0: size of memory region in bytes
 
 When `memory.init` is executed, its behavior matches the steps described in
 step 11 of
@@ -242,7 +250,8 @@ that were dropped after being copied into memory during module instantiation.
 Copy data from a source memory region to destination region; these regions may
 overlap: the copy is performed as if the source region was first copied to a
 temporary buffer, then the temporary buffer is copied to the destination
-region.
+region. This instruction has an immediate argument of which memory to operate
+on, and it must be zero for now.
 
 The instruction has the signature `[i32 i32 i32] -> []`. The parameters are, in order:
 
@@ -252,7 +261,8 @@ The instruction has the signature `[i32 i32 i32] -> []`. The parameters are, in
 
 ### `memory.fill` instruction
 
-Set all bytes in a memory region to a given byte.
+Set all bytes in a memory region to a given byte. This instruction has an
+immediate argument of which memory to operate on, and it must be zero for now.
 
 The instruction has the signature `[i32 i32 i32] -> []`. The parameters are, in order:
 
@@ -282,10 +292,10 @@ implemented as follows:
 (func $start
   (if (get_global 0)
 
-    ;; copy data segment 1 into memory
+    ;; copy data segment 1 into memory 0 (the 0 is implicit)
     (memory.init 1
-      (i32.const 0)     ;; source offset
       (i32.const 16)    ;; target offset
+      (i32.const 0)     ;; source offset
       (i32.const 7))    ;; length
 
     ;; The memory used by this segment is no longer needed, so this segment can
@@ -296,12 +306,20 @@ implemented as follows:
 
 ### Instruction encoding
 
+All bulk memory instructions are encoded as a 0xfc prefix byte, followed by
+another opcode, optionally followed by more immediates:
+
+```
+instr ::= ...
+        | 0xfc operation:uint8 ...
+```
+
 | Name | Opcode | Immediate | Description |
 | ---- | ---- | ---- | ---- |
-| `memory.init` | `0xfc` | `0x08` | :thinking: copy from a passive data segment to linear memory |
-| `memory.drop` | `0xfc` | `0x09` | :thinking: prevent further use of passive data segment |
-| `memory.copy` | `0xfc` | `0x0a` | :thinking: copy from one region of linear memory to another region |
-| `memory.fill` | `0xfc` | `0x0b` | :thinking: fill a region of linear memory with a given byte value |
-| `table.init` | `0xfc` | `0x0c` | :thinking: copy from a passive element segment to a table |
-| `table.drop` | `0xfc` | `0x0d` | :thinking: prevent further use of a passive element segment |
-| `table.copy` | `0xfc` | `0x0e` | :thinking: copy from one region of a table to another region |
+| `memory.init` | `0xfc 0x08` | `memory:0x00`, `segment:varuint32` | :thinking: copy from a passive data segment to linear memory |
+| `memory.drop` | `0xfc 0x09` | `segment:varuint32` | :thinking: prevent further use of passive data segment |
+| `memory.copy` | `0xfc 0x0a` | `memory:0x00` | :thinking: copy from one region of linear memory to another region |
+| `memory.fill` | `0xfc 0x0b` | `memory:0x00` | :thinking: fill a region of linear memory with a given byte value |
+| `table.init` | `0xfc 0x0c` | `memory:0x00`, `segment:varuint32` | :thinking: copy from a passive element segment to a table |
+| `table.drop` | `0xfc 0x0d` | `segment:varuint32` | :thinking: prevent further use of a passive element segment |
+| `table.copy` | `0xfc 0x0e` | `memory:0x00` | :thinking: copy from one region of a table to another region |

From 30092f19832756cdd3a8b3de98fc66a9ec1dfe8c Mon Sep 17 00:00:00 2001
From: Alex Crichton 
Date: Mon, 15 Oct 2018 15:59:22 -0500
Subject: [PATCH 035/199] Update binary encoding to use varuint32 for flags
 (#35)

This commit fixes #34 by specifying that the flags field (which
indicates if a segment is passive) is a `varuint32` instead of a
`uint8`. It was discovered in #34 that the memory index located at that
position today is a `varuint32`, which can be validly encoded as `0x80
0x00` in addition to `0x00` (in addition to a number of other
encodings). This means that if the first field were repurposed as a
single byte of flags, it would break these existing modules that work
today.

It's not currently known how many modules in the wild actually take
advantage of such an encoding, but it's probably better to be safe than
sorry!

Closes #34
---
 proposals/bulk-memory-operations/Overview.md | 13 ++++++-------
 1 file changed, 6 insertions(+), 7 deletions(-)

diff --git a/proposals/bulk-memory-operations/Overview.md b/proposals/bulk-memory-operations/Overview.md
index 01ed57174d..10f36c8e14 100644
--- a/proposals/bulk-memory-operations/Overview.md
+++ b/proposals/bulk-memory-operations/Overview.md
@@ -168,13 +168,12 @@ currently has a collection of segments, each of which has a memory index, an
 initializer expression for its offset, and its raw data.
 
 Since WebAssembly currently does not allow for multiple memories, the memory
-index of each segment must be zero, which when represented as a `varuint32` is
-a single zero byte. We can repurpose this byte as a flags field.
+index of each segment must be zero. We can repurpose this 32-bit integer as a
+flags field where new meaning is attached to nonzero values.
 
-When the least-significant bit of this new flags field is `1`, this segment is
-_passive_. A passive segment will not be automatically copied into the
-memory or table on instantiation, and must instead be applied manually using
-the following new instructions:
+When the new flags field is `1`, this segment is _passive_. A passive segment
+will not be automatically copied into the memory or table on instantiation, and
+must instead be applied manually using the following new instructions:
 
 * `memory.init`: copy a region from a data segment
 * `table.init`: copy a region from an element segment
@@ -195,7 +194,7 @@ The new encoding of a data segment is now:
 
 | Field | Type | Description |
 |------|-------|-------------|
-| flags | `uint8` | Flags for passive and presence of fields below, only values of 0, 1, and 2 are valid |
+| flags | `varuint32` | Flags for passive and presence of fields below, only values of 0, 1, and 2 are valid |
 | index | `varuint32`? | Memory index this segment is for, only present if `flags` is 2, otherwise the index is implicitly 0 |
 | offset | `init_expr`? | an `i32` initializer expression for offset, not present if `flags & 0x1` is set |
 | size | `varuint32` | size of `data` (in bytes) |

From 61018e89bf9f1bf2c54e9055f0b797c65cf21886 Mon Sep 17 00:00:00 2001
From: Ben Smith 
Date: Wed, 31 Oct 2018 12:43:15 -0700
Subject: [PATCH 036/199] Fix typo in overview: memory->table

---
 proposals/bulk-memory-operations/Overview.md | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/proposals/bulk-memory-operations/Overview.md b/proposals/bulk-memory-operations/Overview.md
index 10f36c8e14..d1442fafdb 100644
--- a/proposals/bulk-memory-operations/Overview.md
+++ b/proposals/bulk-memory-operations/Overview.md
@@ -319,6 +319,6 @@ instr ::= ...
 | `memory.drop` | `0xfc 0x09` | `segment:varuint32` | :thinking: prevent further use of passive data segment |
 | `memory.copy` | `0xfc 0x0a` | `memory:0x00` | :thinking: copy from one region of linear memory to another region |
 | `memory.fill` | `0xfc 0x0b` | `memory:0x00` | :thinking: fill a region of linear memory with a given byte value |
-| `table.init` | `0xfc 0x0c` | `memory:0x00`, `segment:varuint32` | :thinking: copy from a passive element segment to a table |
+| `table.init` | `0xfc 0x0c` | `table:0x00`, `segment:varuint32` | :thinking: copy from a passive element segment to a table |
 | `table.drop` | `0xfc 0x0d` | `segment:varuint32` | :thinking: prevent further use of a passive element segment |
-| `table.copy` | `0xfc 0x0e` | `memory:0x00` | :thinking: copy from one region of a table to another region |
+| `table.copy` | `0xfc 0x0e` | `table:0x00` | :thinking: copy from one region of a table to another region |

From 1276e58b702b73235473f3de254ca670e8aa4bde Mon Sep 17 00:00:00 2001
From: Ben Smith 
Date: Mon, 26 Nov 2018 13:54:27 -0800
Subject: [PATCH 037/199]  Update Overview.md for element segments (#41)

* Update Overview.md for element segments

Passive element segments now include an element type, and have a sequence of expressions instead of function indices.
---
 proposals/bulk-memory-operations/Overview.md | 58 ++++++++++++++++----
 1 file changed, 48 insertions(+), 10 deletions(-)

diff --git a/proposals/bulk-memory-operations/Overview.md b/proposals/bulk-memory-operations/Overview.md
index d1442fafdb..ded652ccb5 100644
--- a/proposals/bulk-memory-operations/Overview.md
+++ b/proposals/bulk-memory-operations/Overview.md
@@ -192,16 +192,54 @@ An active segment is equivalent to a passive segment, but with an implicit
 
 The new encoding of a data segment is now:
 
-| Field | Type | Description |
-|------|-------|-------------|
-| flags | `varuint32` | Flags for passive and presence of fields below, only values of 0, 1, and 2 are valid |
-| index | `varuint32`? | Memory index this segment is for, only present if `flags` is 2, otherwise the index is implicitly 0 |
-| offset | `init_expr`? | an `i32` initializer expression for offset, not present if `flags & 0x1` is set |
-| size | `varuint32` | size of `data` (in bytes) |
-| data | `bytes` | sequence of `size` bytes |
-
-An element segment (for tables) is encoded similarly by repurposing its table
-index (which is required to be zero) as a flags field.
+| Field | Type | Present? | Description |
+| - | - | - | - |
+| flags | `varuint32` | always | Flags for passive and presence of fields below, only values of 0, 1, and 2 are valid |
+| index | `varuint32`? | flags = 2 | Memory index; 0 if the field is not present |
+| offset | `init_expr`? | flags != 1 | an `i32` initializer expression for offset |
+| size | `varuint32` | always | size of `data` (in bytes) |
+| data | `bytes` | always | sequence of `size` bytes |
+
+Another way of looking at it:
+
+| Flags | Active? | index | offset |
+| - | - | - | - |
+| 0 | Active | Always 0 | Present |
+| 1 | Passive | - | -  |
+| 2 | Active | Present | Present |
+
+### Element segments
+
+The new binary format for element segments is similar to the new format for data segments, but
+also includes an element type when the segment is passive. A passive segment also has a sequence
+of `expr`s instead of function indices.
+
+| Field | Type | Present? | Description |
+| - | - | - | - |
+| flags | `varuint32` | always | Flags for passive and presence of fields below, only values of 0, 1, and 2 are valid |
+| index | `varuint32`? | flags = 2 |  Table index; 0 if the field is not present  |
+| element_type | `elem_type`? | flags = 1 | element type of this segment; `anyfunc` if not present |
+| offset | `init_expr`? | flags != 1 | an `i32` initializer expression for offset |
+| count | `varuint32` | always | number of elements |
+| elems | `varuint32*` | flags != 1 | sequence of function indices |
+| elems | `elem_expr*` | flags = 1 | sequence of element expressions |
+
+Another way of looking at it:
+
+| Flags | Active? | index | element_type | offset |
+| - | - | - | - | - |
+| 0 | Active | Always 0 | Always `anyfunc` | Present |
+| 1 | Passive | - | Present | - |
+| 2 | Active | Present | Always `anyfunc` | Present |
+
+An `elem_expr` is like an `init_expr`, but can only contain expressions of the following sequences:
+
+| Binary | Text | Description |
+| - | - | - |
+| `0xd0 0x0b` | `ref.null end` | Returns a null reference |
+| `0xd2 varuint32 0x0b` | `ref.func $funcidx end` | Returns a reference to function `$funcidx` |
+
+TODO: coordinate with other proposals to determine the binary encoding for `ref.null` and `ref.func`.
 
 ### `memory.init` instruction
 

From d6d2c1f7149dd3ecd40b0eb1705c2977d69ef1ab Mon Sep 17 00:00:00 2001
From: Ben Smith 
Date: Thu, 29 Nov 2018 11:29:18 -0800
Subject: [PATCH 038/199] Add new `DataCount` section (#42)

---
 proposals/bulk-memory-operations/Overview.md | 44 ++++++++++++++++++++
 1 file changed, 44 insertions(+)

diff --git a/proposals/bulk-memory-operations/Overview.md b/proposals/bulk-memory-operations/Overview.md
index ded652ccb5..46f280ce23 100644
--- a/proposals/bulk-memory-operations/Overview.md
+++ b/proposals/bulk-memory-operations/Overview.md
@@ -360,3 +360,47 @@ instr ::= ...
 | `table.init` | `0xfc 0x0c` | `table:0x00`, `segment:varuint32` | :thinking: copy from a passive element segment to a table |
 | `table.drop` | `0xfc 0x0d` | `segment:varuint32` | :thinking: prevent further use of a passive element segment |
 | `table.copy` | `0xfc 0x0e` | `table:0x00` | :thinking: copy from one region of a table to another region |
+
+### `DataCount` section
+
+The WebAssembly binary format is designed to be validated in a single pass. If
+a section requires information to validate, it is guaranteed that this
+information will be present in a previous section.
+
+The `memory.{init,drop}` instructions break this guarantee. Both of these
+instructions are used in the `Code` section. They each have a data segment
+index immediate, but the vector of data segments is not available until the
+`Data` section is parsed, which occurs after the `Code` section.
+
+To keep single-pass validation, the number of data segments defined in the
+`Data` section must be available before the `Code` section. This information is
+provided in a new `DataCount` section with the code `12`.
+
+Like all sections, the `DataCount` section is optional. If present, it must
+appear in the following order:
+
+| Section Name | Code | Description |
+| ------------ | ---- | ----------- |
+| Type | `1` | Function signature declarations |
+| Import | `2` | Import declarations |
+| Function | `3` | Function declarations |
+| Table | `4` | Indirect function table and other tables |
+| Memory | `5` | Memory attributes |
+| Global | `6` | Global declarations |
+| Export | `7` | Exports |
+| Start | `8` | Start function declaration |
+| Element | `9` | Elements section |
+| DataCount | `13` | Data segment count |
+| Code | `10` | Function bodies (code) |
+| Data | `11` | Data segments |
+
+The `DataCount` section has just one field that specifies the number of data
+segments in the `Data` section:
+
+| Field | Type | Description |
+| ----- | ---- | ----------- |
+| count | `varuint32` | count of data segments in `Data` section |
+
+It is a validation error if `count` is not equal to the number of data segments
+in the `Data` section. It is also a validation error if the `DataCount` section
+is omitted and a `memory.init` or `memory.drop` instruction is used.

From b19cbf3b367b2a96bacfa7a9d5f370ee3f74fcf7 Mon Sep 17 00:00:00 2001
From: Andrew Scheidecker 
Date: Thu, 29 Nov 2018 14:15:47 -0600
Subject: [PATCH 039/199] Add a second placeholder zero to the encoding of
 `memory.copy` and `table.copy`. (#29)

This would make it simpler to extend those instructions to support multiple memories/tables, and copying between different memories/tables.

The current encoding has a single placeholder zero byte for those instructions, which allows extension to multiple memories/tables, but would require a more complicated encoding to add two immediate indices.
---
 document/core/binary/instructions.rst | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/document/core/binary/instructions.rst b/document/core/binary/instructions.rst
index bc583f63cf..1bd9ab75ae 100644
--- a/document/core/binary/instructions.rst
+++ b/document/core/binary/instructions.rst
@@ -163,7 +163,7 @@ Each variant of :ref:`memory instruction ` is encoded with
      \hex{40}~~\hex{00} &\Rightarrow& \MEMORYGROW \\ &&|&
      \hex{FC}~\hex{08}~~\hex{00}~x{:}\Bdataidx &\Rightarrow& \MEMORYINIT~x \\ &&|&
      \hex{FC}~\hex{09}~~x{:}\Bdataidx &\Rightarrow& \MEMORYDROP~x \\ &&|&
-     \hex{FC}~\hex{0A}~~\hex{00} &\Rightarrow& \MEMORYCOPY \\ &&|&
+     \hex{FC}~\hex{0A}~~\hex{00}~~\hex{00} &\Rightarrow& \MEMORYCOPY \\ &&|&
      \hex{FC}~\hex{0B}~~\hex{00} &\Rightarrow& \MEMORYFILL \\
    \end{array}
 
@@ -185,11 +185,11 @@ Each variant of :ref:`table instruction ` is encoded with a
    \production{instruction} & \Binstr &::=& \dots \\ &&|&
      \hex{FC}~\hex{0C}~~\hex{00}~x{:}\Belemidx &\Rightarrow& \TABLEINIT~x \\ &&|&
      \hex{FC}~\hex{0D}~~x{:}\Belemidx &\Rightarrow& \TABLEDROP~x \\ &&|&
-     \hex{FC}~\hex{0E}~~\hex{00} &\Rightarrow& \TABLECOPY \\
+     \hex{FC}~\hex{0E}~~\hex{00}~~\hex{00} &\Rightarrow& \TABLECOPY \\
    \end{array}
 
 .. note::
-   In future versions of WebAssembly, the additional zero byte occurring in the encoding of the |TABLECOPY| instruction may be used to index an additional table.
+   In future versions of WebAssembly, the additional zero bytes occurring in the encoding of the |TABLECOPY| instruction may be used to index additional tables.
 
 
 .. index:: numeric instruction

From aa7efeab5a58c71c0a9c98a76295853ad96f0374 Mon Sep 17 00:00:00 2001
From: Heejin Ahn 
Date: Tue, 11 Dec 2018 20:33:15 -0800
Subject: [PATCH 040/199] Change DataCount section ID to 12 (#44)

---
 proposals/bulk-memory-operations/Overview.md | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/proposals/bulk-memory-operations/Overview.md b/proposals/bulk-memory-operations/Overview.md
index 46f280ce23..05ee5e2d70 100644
--- a/proposals/bulk-memory-operations/Overview.md
+++ b/proposals/bulk-memory-operations/Overview.md
@@ -390,7 +390,7 @@ appear in the following order:
 | Export | `7` | Exports |
 | Start | `8` | Start function declaration |
 | Element | `9` | Elements section |
-| DataCount | `13` | Data segment count |
+| DataCount | `12` | Data segment count |
 | Code | `10` | Function bodies (code) |
 | Data | `11` | Data segments |
 

From c34d22f8a13199ca4ce3a0566ee1b4ae334b94ce Mon Sep 17 00:00:00 2001
From: Andreas Rossberg 
Date: Wed, 12 Dec 2018 11:55:53 +0100
Subject: [PATCH 041/199] Forgot to rename in Overview

---
 proposals/reference-types/Overview.md | 22 +++++++++++-----------
 1 file changed, 11 insertions(+), 11 deletions(-)

diff --git a/proposals/reference-types/Overview.md b/proposals/reference-types/Overview.md
index 9b19db1256..22f4812c1d 100644
--- a/proposals/reference-types/Overview.md
+++ b/proposals/reference-types/Overview.md
@@ -27,7 +27,7 @@ Summary:
 
 * Add a new type `anyref` that can be used as both a value type and a table element type.
 
-* Also allow `anyfunc` as a value type.
+* Also allow `funcref` as a value type.
 
 * Introduce instructions to get and set table slots.
 
@@ -44,8 +44,8 @@ Notes:
 
 Typing extensions:
 
-* Introduce `anyref`, `anyfunc`, and `nullref` as a new class of *reference types*.
-  - `reftype ::= anyref | anyfunc | nullref`
+* Introduce `anyref`, `funcref`, and `nullref` as a new class of *reference types*.
+  - `reftype ::= anyref | funcref | nullref`
   - `nullref` is merely an internal type and is neither expressible in the binary format, nor the text format, nor the JS API.
   - Question: should it be?
 
@@ -60,7 +60,7 @@ Typing extensions:
 * Introduce a simple subtype relation between reference types.
   - reflexive transitive closure of the following rules
   - `t < anyref` for all reftypes `t`
-  - `anyfunc < anyref`
+  - `nullref < anyref` and `nullref < funcref`
   - Note: No rule `nullref < t` for all reftypes `t` -- while that is derivable from the above given the current set of types it might not hold for future reference types which don't allow null.
 
 
@@ -79,7 +79,7 @@ New/extended instructions:
   - `table.fill $x : [i32 i32 t] -> []` iff `t` is the element type of table `$x`
 
 * The `call_indirect` instruction takes a table index as immediate that identifies the table it calls through.
-  - `call_indirect (type $t) $x : [t1* i32] -> [t2*]` iff `$t` denotes the function type `[t1*] -> [t2*]` and the element type of table `$x` is a subtype of `anyfunc`.
+  - `call_indirect (type $t) $x : [t1* i32] -> [t2*]` iff `$t` denotes the function type `[t1*] -> [t2*]` and the element type of table `$x` is a subtype of `funcref`.
   - In the binary format, space for the index is already reserved.
   - For backwards compatibility, the index may be omitted in the text format, in which case it defaults to 0.
 
@@ -99,7 +99,7 @@ API extensions:
 
 * Any JS value can be passed as `anyref` to a Wasm function, stored in a global, or in a table.
 
-* Any Wasm exported function object or `null` can be passed as `anyfunc` to a Wasm function, stored in a global, or in a table.
+* Any Wasm exported function object or `null` can be passed as `funcref` to a Wasm function, stored in a global, or in a table.
 
 
 ## Possible Future Extensions
@@ -147,12 +147,12 @@ Additions:
 * Add `(ref $t)` as a reference type
   - `reftype ::= ... | ref `
 * Add `(ref.func $f)` and `(call_ref)` instructions
-  - `ref.func $f : [] -> (ref $t)  iff $f : $t`
+  - `ref.func $f : [] -> (ref $t)` iff `$f : $t`
   - `call_ref : [ts1 (ref $t)] -> [ts2]` iff `$t = [ts1] -> [ts2]`
-* Introduce subtyping `ref  < anyfunc`
+* Introduce subtyping `ref  < funcref`
 * Subtying between concrete and universal reference types
   - `ref $t < anyref`
-  - `ref  < anyfunc`
+  - `ref  < funcref`
   - Note: reference types are not necessarily subtypes of `eqref`, including functions
 
 * Typed function references cannot be null!
@@ -198,8 +198,8 @@ Questions:
 
 * Do we need to impose constraints on the order of imports, to stratify section dependencies? Should type import and export be separate sections instead?
 
-* Do we need a nullable `(ref opt $t)` type to allow use with locals etc.? Could a `(nullable T)` type constructor work instead?
-  - Unclear how `nullable` constructor would integrate exactly. Would it only allow (non-nullable) reference types as argument? Does this require a kind system? Should `anyref` be different from `(nullable anyref)`, or the latter disallowed? What about `anyfunc`?
+* Do we need a nullable `(optref $t)` type to allow use with locals etc.? Could a `(nullable T)` type constructor work instead?
+  - Unclear how `nullable` constructor would integrate exactly. Would it only allow (non-nullable) reference types as argument? Does this require a kind system? Should `anyref` be different from `(nullable anyref)`, or the latter disallowed? What about `funcref`?
   - Semantically, thinking of `(nullable T)` as `T | nullref` could answer these questions, but we cannot support arbitrary unions in Wasm.
 
 * Should we add `(new)` definitional type to enable Wasm modules to define new types, too?

From 59e2ee5c70bf5200a0d60b003f457d0570ea8a6b Mon Sep 17 00:00:00 2001
From: Andreas Rossberg 
Date: Wed, 12 Dec 2018 12:59:45 +0100
Subject: [PATCH 042/199] Add store typing

---
 document/core/appendix/properties.rst | 31 +++++++++++++++++++++++++++
 document/core/exec/runtime.rst        |  3 ++-
 2 files changed, 33 insertions(+), 1 deletion(-)

diff --git a/document/core/appendix/properties.rst b/document/core/appendix/properties.rst
index 330f42dc4d..1339d5b871 100644
--- a/document/core/appendix/properties.rst
+++ b/document/core/appendix/properties.rst
@@ -468,6 +468,37 @@ To that end, all previous typing judgements :math:`C \vdash \X{prop}` are genera
    }
 
 
+.. index:: host address
+
+:math:`\REFHOST~\hostaddr`
+..........................
+
+* The instruction is valid with type :math:`[] \to [\ANYREF]`.
+
+.. math::
+   \frac{
+   }{
+     S; C \vdashadmininstr \REFHOST~\hostaddr : [] \to [\ANYREF]
+   }
+
+
+.. index:: function address, extern value, extern type, function type
+
+:math:`\REFFUNC~\funcaddr`
+..........................
+
+* The :ref:`external function value ` :math:`\EVFUNC~\funcaddr` must be :ref:`valid ` with :ref:`external function type ` :math:`\ETFUNC \functype`.
+
+* Then the instruction is valid with type :math:`[] \to [\FUNCREF]`.
+
+.. math::
+   \frac{
+     S \vdashexternval \EVFUNC~\funcaddr : \ETFUNC~\functype
+   }{
+     S; C \vdashadmininstr \REFFUNC~\funcaddr : [] \to [\FUNCREF]
+   }
+
+
 .. index:: function address, extern value, extern type, function type
 
 :math:`\INVOKE~\funcaddr`
diff --git a/document/core/exec/runtime.rst b/document/core/exec/runtime.rst
index 84b5e853cf..45107da7b1 100644
--- a/document/core/exec/runtime.rst
+++ b/document/core/exec/runtime.rst
@@ -478,6 +478,7 @@ In order to express the reduction of :ref:`traps `, :ref:`calls `, :ref:`calls `.
+The |REFFUNC| instruction represents :ref:`function reference values `. Similarly, |REFHOST| represents :ref:`host references `.
 
 The |INVOKE| instruction represents the imminent invocation of a :ref:`function instance `, identified by its :ref:`address `.
 It unifies the handling of different forms of calls.

From fa335d78e7f2b881dc91cf570a521e8014fd92dc Mon Sep 17 00:00:00 2001
From: Andreas Rossberg 
Date: Wed, 12 Dec 2018 13:30:18 +0100
Subject: [PATCH 043/199] Check that ref.null is a const instruction

---
 document/core/valid/instructions.rst | 2 ++
 test/core/ref_null.wast              | 3 +++
 2 files changed, 5 insertions(+)

diff --git a/document/core/valid/instructions.rst b/document/core/valid/instructions.rst
index 8627914cbd..8ba4c0e645 100644
--- a/document/core/valid/instructions.rst
+++ b/document/core/valid/instructions.rst
@@ -877,6 +877,8 @@ Constant Expressions
 
   * either of the form :math:`t.\CONST~c`,
 
+  * or of the form :math:`\REFNULL`,
+
   * or of the form :math:`\GLOBALGET~x`, in which case :math:`C.\CGLOBALS[x]` must be a :ref:`global type ` of the form :math:`\CONST~t`.
 
 .. math::
diff --git a/test/core/ref_null.wast b/test/core/ref_null.wast
index 19fba696a6..30384802be 100644
--- a/test/core/ref_null.wast
+++ b/test/core/ref_null.wast
@@ -1,6 +1,9 @@
 (module
   (func (export "anyref") (result anyref) (ref.null))
   (func (export "funcref") (result funcref) (ref.null))
+
+  (global anyref (ref.null))
+  (global funcref (ref.null))
 )
 
 (assert_return (invoke "anyref") (ref.null))

From 2a00b2e12bc9a8468dfe582e3db7cd20f1964e75 Mon Sep 17 00:00:00 2001
From: Andreas Rossberg 
Date: Wed, 12 Dec 2018 21:53:30 +0100
Subject: [PATCH 044/199] Add ref.func instruction (#24)

---
 document/core/appendix/index-instructions.rst |  1 +
 document/core/appendix/properties.rst         |  6 +-
 document/core/binary/instructions.rst         |  3 +-
 document/core/exec/instructions.rst           | 24 +++++++-
 document/core/exec/modules.rst                |  4 +-
 document/core/exec/runtime.rst                |  8 +--
 document/core/syntax/instructions.rst         |  4 +-
 document/core/text/instructions.rst           |  4 +-
 document/core/util/macros.def                 |  3 +-
 document/core/valid/instructions.rst          | 23 ++++++++
 interpreter/README.md                         |  2 +-
 interpreter/binary/decode.ml                  |  1 +
 interpreter/binary/encode.ml                  |  1 +
 interpreter/exec/eval.ml                      | 18 +++---
 interpreter/syntax/ast.ml                     |  1 +
 interpreter/syntax/operators.ml               |  1 +
 interpreter/text/arrange.ml                   |  1 +
 interpreter/text/lexer.mll                    |  1 +
 interpreter/text/parser.mly                   |  3 +-
 interpreter/valid/valid.ml                    | 21 ++++---
 proposals/reference-types/Overview.md         |  6 +-
 test/core/ref_func.wast                       | 55 +++++++++++++++++++
 22 files changed, 158 insertions(+), 33 deletions(-)
 create mode 100644 test/core/ref_func.wast

diff --git a/document/core/appendix/index-instructions.rst b/document/core/appendix/index-instructions.rst
index 74b51fcb35..f640cf83ee 100644
--- a/document/core/appendix/index-instructions.rst
+++ b/document/core/appendix/index-instructions.rst
@@ -217,4 +217,5 @@ Instruction                             Binary Opcode     Type
 (reserved)                              :math:`\hex{CF}`                                                  
 :math:`\REFNULL`                        :math:`\hex{D0}`  :math:`[] \to [\NULLREF]`                   :ref:`validation `        :ref:`execution `
 :math:`\REFISNULL`                      :math:`\hex{D1}`  :math:`[\ANYREF] \to [\I32]`                :ref:`validation `      :ref:`execution `
+:math:`\REFFUNC~x`                      :math:`\hex{D2}`  :math:`[] \to [\FUNCREF]`                   :ref:`validation `        :ref:`execution `
 ======================================  ================  ==========================================  ========================================  ===============================================================
diff --git a/document/core/appendix/properties.rst b/document/core/appendix/properties.rst
index 1339d5b871..62cbd75ace 100644
--- a/document/core/appendix/properties.rst
+++ b/document/core/appendix/properties.rst
@@ -484,8 +484,8 @@ To that end, all previous typing judgements :math:`C \vdash \X{prop}` are genera
 
 .. index:: function address, extern value, extern type, function type
 
-:math:`\REFFUNC~\funcaddr`
-..........................
+:math:`\REFFUNCADDR~\funcaddr`
+..............................
 
 * The :ref:`external function value ` :math:`\EVFUNC~\funcaddr` must be :ref:`valid ` with :ref:`external function type ` :math:`\ETFUNC \functype`.
 
@@ -495,7 +495,7 @@ To that end, all previous typing judgements :math:`C \vdash \X{prop}` are genera
    \frac{
      S \vdashexternval \EVFUNC~\funcaddr : \ETFUNC~\functype
    }{
-     S; C \vdashadmininstr \REFFUNC~\funcaddr : [] \to [\FUNCREF]
+     S; C \vdashadmininstr \REFFUNCADDR~\funcaddr : [] \to [\FUNCREF]
    }
 
 
diff --git a/document/core/binary/instructions.rst b/document/core/binary/instructions.rst
index 2a17bc985f..7b41829ce7 100644
--- a/document/core/binary/instructions.rst
+++ b/document/core/binary/instructions.rst
@@ -77,7 +77,8 @@ Reference Instructions
    \begin{array}{llclll}
    \production{instruction} & \Binstr &::=& \dots \\ &&|&
      \hex{D0} &\Rightarrow& \REFNULL \\ &&|&
-     \hex{D1} &\Rightarrow& \REFISNULL \\
+     \hex{D1} &\Rightarrow& \REFISNULL \\ &&|&
+     \hex{D2}~~x{:}\Bfuncidx &\Rightarrow& \REFFUNC~x \\
    \end{array}
 
 .. note::
diff --git a/document/core/exec/instructions.rst b/document/core/exec/instructions.rst
index 4014c85a9c..0cfdf1da64 100644
--- a/document/core/exec/instructions.rst
+++ b/document/core/exec/instructions.rst
@@ -219,6 +219,26 @@ Reference Instructions
    \end{array}
 
 
+.. _exec-ref.func:
+
+:math:`\REFFUNC~x`
+..................
+
+1. Let :math:`F` be the :ref:`current ` :ref:`frame `.
+
+2. Assert: due to :ref:`validation `, :math:`F.\AMODULE.\MIFUNCS[x]` exists.
+
+3. Let :math:`a` be the :ref:`function address ` :math:`F.\AMODULE.\MIFUNCS[x]`.
+
+4. Push the value :math:`\REFFUNCADDR~a` to the stack.
+
+.. math::
+   \begin{array}{lcl@{\qquad}l}
+   F; \REFFUNC~x &\stepto& F; \REFFUNCADDR~a
+     & (\iff a = F.\AMODULE.\MIFUNCS[x]) \\
+   \end{array}
+
+
 .. index:: parametric instructions, value
    pair: execution; instruction
    single: abstract syntax; instruction
@@ -1042,7 +1062,7 @@ Control Instructions
 
 13. Assert: due to :ref:`validation of table mutation `, :math:`r` is a :ref:`function reference `.
 
-14. Let :math:`\REFFUNC~a` be the :ref:`function reference ` :math:`r`.
+14. Let :math:`\REFFUNCADDR~a` be the :ref:`function reference ` :math:`r`.
 
 15. Assert: due to :ref:`validation of table mutation `, :math:`S.\SFUNCS[a]` exists.
 
@@ -1064,7 +1084,7 @@ Control Instructions
    \end{array}
    \\ \qquad
      \begin{array}[t]{@{}r@{~}l@{}}
-     (\iff & S.\STABLES[F.\AMODULE.\MITABLES[x]].\TIELEM[i] = \REFFUNC~a \\
+     (\iff & S.\STABLES[F.\AMODULE.\MITABLES[x]].\TIELEM[i] = \REFFUNCADDR~a \\
      \wedge & S.\SFUNCS[a] = f \\
      \wedge & F.\AMODULE.\MITYPES[y] = f.\FITYPE)
      \end{array}
diff --git a/document/core/exec/modules.rst b/document/core/exec/modules.rst
index 6782152fb2..3078d9441c 100644
--- a/document/core/exec/modules.rst
+++ b/document/core/exec/modules.rst
@@ -677,7 +677,7 @@ It is up to the :ref:`embedder ` to define how such conditions are rep
 
        ii. Let :math:`\funcaddr_{ij}` be the :ref:`function address ` :math:`\moduleinst.\MIFUNCS[\funcidx_{ij}]`.
 
-       iii. Replace :math:`\tableinst_i.\TIELEM[\X{eo}_i + j]` with :math:`\REFFUNC~\funcaddr_{ij}`.
+       iii. Replace :math:`\tableinst_i.\TIELEM[\X{eo}_i + j]` with :math:`\REFFUNCADDR~\funcaddr_{ij}`.
 
 14. For each :ref:`data segment ` :math:`\data_i` in :math:`\module.\MDATA`, do:
 
@@ -727,7 +727,7 @@ It is up to the :ref:`embedder ` to define how such conditions are rep
      S; F; \epsilon \\
    S; F; \INITELEM~a~i~(x_0~x^\ast) &\stepto&
      S'; F; \INITELEM~a~(i+1)~x^\ast \\ &&
-     (\iff S' = S \with \STABLES[a].\TIELEM[i] = \REFFUNC~F.\AMODULE.\MIFUNCS[x_0])
+     (\iff S' = S \with \STABLES[a].\TIELEM[i] = \REFFUNCADDR~F.\AMODULE.\MIFUNCS[x_0])
    \\[1ex]
    S; F; \INITDATA~a~i~\epsilon &\stepto&
      S; F; \epsilon \\
diff --git a/document/core/exec/runtime.rst b/document/core/exec/runtime.rst
index 45107da7b1..e4febcbac4 100644
--- a/document/core/exec/runtime.rst
+++ b/document/core/exec/runtime.rst
@@ -11,7 +11,6 @@ Runtime Structure
    pair: abstract syntax; value
 .. _syntax-num:
 .. _syntax-ref:
-.. _syntax-ref.func:
 .. _syntax-ref.host:
 .. _syntax-val:
 
@@ -37,7 +36,7 @@ or *host references* pointing to an uninterpreted form of :ref:`host address `, :ref:`calls `, :ref:`calls `. Similarly, |REFHOST| represents :ref:`host references `.
+The |REFFUNCADDR| instruction represents :ref:`function reference values `. Similarly, |REFHOST| represents :ref:`host references `.
 
 The |INVOKE| instruction represents the imminent invocation of a :ref:`function instance `, identified by its :ref:`address `.
 It unifies the handling of different forms of calls.
diff --git a/document/core/syntax/instructions.rst b/document/core/syntax/instructions.rst
index f889d33d7c..60aab45277 100644
--- a/document/core/syntax/instructions.rst
+++ b/document/core/syntax/instructions.rst
@@ -171,6 +171,7 @@ Occasionally, it is convenient to group operators together according to the foll
    pair: abstract syntax; instruction
 .. _syntax-ref.null:
 .. _syntax-ref.isnull:
+.. _syntax-ref.func:
 .. _syntax-instr-ref:
 
 Reference Instructions
@@ -183,7 +184,8 @@ Instructions in this group are concerned with accessing :ref:`references ` of the form :math:`\CONST~t`.
 
 .. math::
@@ -899,6 +916,12 @@ Constant Expressions
      C \vdashinstrconst \REFNULL \const
    }
    \qquad
+   \frac{
+   }{
+     C \vdashinstrconst \REFFUNC~x \const
+   }
+
+.. math::
    \frac{
      C.\CGLOBALS[x] = \CONST~t
    }{
diff --git a/interpreter/README.md b/interpreter/README.md
index 94b00ad2f1..d228700241 100644
--- a/interpreter/README.md
+++ b/interpreter/README.md
@@ -232,7 +232,7 @@ op:
   memory.grow
   ref.null
   ref.isnull
-  ref.eq
+  ref.func 
   .const 
   .
   .
diff --git a/interpreter/binary/decode.ml b/interpreter/binary/decode.ml
index f5f617667e..d7299bd913 100644
--- a/interpreter/binary/decode.ml
+++ b/interpreter/binary/decode.ml
@@ -446,6 +446,7 @@ let rec instr s =
   (* TODO: Allocate more adequate opcodes *)
   | 0xd0 -> ref_null
   | 0xd1 -> ref_isnull
+  | 0xd2 -> ref_func (at var s)
 
   | b -> illegal s pos b
 
diff --git a/interpreter/binary/encode.ml b/interpreter/binary/encode.ml
index 8915803b78..e4d25b2658 100644
--- a/interpreter/binary/encode.ml
+++ b/interpreter/binary/encode.ml
@@ -375,6 +375,7 @@ let encode m =
       (* TODO: Allocate more adequate opcodes *)
       | RefNull -> op 0xd0
       | RefIsNull -> op 0xd1
+      | RefFunc x -> op 0xd2; var x
 
     let const c =
       list instr c.it; end_ ()
diff --git a/interpreter/exec/eval.ml b/interpreter/exec/eval.ml
index a2919ff745..bd6b408b6d 100644
--- a/interpreter/exec/eval.ml
+++ b/interpreter/exec/eval.ml
@@ -248,6 +248,10 @@ let rec step (c : config) : config =
       | RefIsNull, v :: vs' ->
         Num (I32 0l) :: vs', []
 
+      | RefFunc x, vs' ->
+        let f = func frame.inst x in
+        Ref (FuncRef f) :: vs', []
+
       | Const n, vs ->
         Num n.it :: vs, []
 
@@ -455,15 +459,15 @@ let init (m : module_) (exts : extern list) : module_inst =
       types = List.map (fun type_ -> type_.it) types }
   in
   let fs = List.map (create_func inst0) funcs in
-  let inst1 =
-    { inst0 with
-      funcs = inst0.funcs @ fs;
-      tables = inst0.tables @ List.map (create_table inst0) tables;
-      memories = inst0.memories @ List.map (create_memory inst0) memories;
-      globals = inst0.globals @ List.map (create_global inst0) globals;
+  let inst1 = {inst0 with funcs = inst0.funcs @ fs} in
+  let inst2 =
+    { inst1 with
+      tables = inst1.tables @ List.map (create_table inst1) tables;
+      memories = inst1.memories @ List.map (create_memory inst1) memories;
+      globals = inst1.globals @ List.map (create_global inst1) globals;
     }
   in
-  let inst = {inst1 with exports = List.map (create_export inst1) exports} in
+  let inst = {inst2 with exports = List.map (create_export inst2) exports} in
   List.iter (init_func inst) fs;
   let init_elems = List.map (init_table inst) elems in
   let init_datas = List.map (init_memory inst) data in
diff --git a/interpreter/syntax/ast.ml b/interpreter/syntax/ast.ml
index 7e4a84e8ae..da0563cde6 100644
--- a/interpreter/syntax/ast.ml
+++ b/interpreter/syntax/ast.ml
@@ -95,6 +95,7 @@ and instr' =
   | MemoryGrow                        (* grow linear memory *)
   | RefNull                           (* null reference *)
   | RefIsNull                         (* null test *)
+  | RefFunc of var                    (* function reference *)
   | Const of literal                  (* constant *)
   | Test of testop                    (* numeric test *)
   | Compare of relop                  (* numeric comparison *)
diff --git a/interpreter/syntax/operators.ml b/interpreter/syntax/operators.ml
index 806d687a04..6257137846 100644
--- a/interpreter/syntax/operators.ml
+++ b/interpreter/syntax/operators.ml
@@ -11,6 +11,7 @@ let f32_const n = Const (F32 n.it @@ n.at)
 let f64_const n = Const (F64 n.it @@ n.at)
 let ref_null = RefNull
 let ref_isnull = RefIsNull
+let ref_func x = RefFunc x
 
 let unreachable = Unreachable
 let nop = Nop
diff --git a/interpreter/text/arrange.ml b/interpreter/text/arrange.ml
index 8ec8192f2b..147ee515fe 100644
--- a/interpreter/text/arrange.ml
+++ b/interpreter/text/arrange.ml
@@ -251,6 +251,7 @@ let rec instr e =
     | MemoryGrow -> "memory.grow", []
     | RefNull -> "ref.null", []
     | RefIsNull -> "ref.isnull", []
+    | RefFunc x -> "ref.func " ^ var x, []
     | Const lit -> constop lit ^ " " ^ num lit, []
     | Test op -> testop op, []
     | Compare op -> relop op, []
diff --git a/interpreter/text/lexer.mll b/interpreter/text/lexer.mll
index 8cf63bd8a9..4e1805d5b4 100644
--- a/interpreter/text/lexer.mll
+++ b/interpreter/text/lexer.mll
@@ -178,6 +178,7 @@ rule token = parse
           f64_const (n @@ s.at), Values.F64 n))
     }
   | "ref.null" { REF_NULL }
+  | "ref.func" { REF_FUNC }
   | "ref.host" { REF_HOST }
   | "ref.isnull" { REF_ISNULL }
 
diff --git a/interpreter/text/parser.mly b/interpreter/text/parser.mly
index abaf6b1586..b6a9237a14 100644
--- a/interpreter/text/parser.mly
+++ b/interpreter/text/parser.mly
@@ -152,7 +152,7 @@ let inline_type_explicit (c : context) x ft at =
 %token CALL CALL_INDIRECT RETURN
 %token LOCAL_GET LOCAL_SET LOCAL_TEE GLOBAL_GET GLOBAL_SET TABLE_GET TABLE_SET
 %token LOAD STORE OFFSET_EQ_NAT ALIGN_EQ_NAT
-%token REF_NULL REF_HOST REF_ISNULL
+%token REF_NULL REF_FUNC REF_HOST REF_ISNULL
 %token CONST UNARY BINARY TEST COMPARE CONVERT
 %token UNREACHABLE MEMORY_SIZE MEMORY_GROW
 %token FUNC START TYPE PARAM RESULT LOCAL GLOBAL
@@ -332,6 +332,7 @@ plain_instr :
   | MEMORY_GROW { fun c -> memory_grow }
   | REF_NULL { fun c -> ref_null }
   | REF_ISNULL { fun c -> ref_isnull }
+  | REF_FUNC var { fun c -> ref_func ($2 c func) }
   | CONST literal { fun c -> fst (literal $1 $2) }
   | TEST { fun c -> $1 }
   | COMPARE { fun c -> $1 }
diff --git a/interpreter/valid/valid.ml b/interpreter/valid/valid.ml
index 4eb764135d..22dcc63f7d 100644
--- a/interpreter/valid/valid.ml
+++ b/interpreter/valid/valid.ml
@@ -155,7 +155,7 @@ let type_cvtop at = function
 (* Expressions *)
 
 let check_memop (c : context) (memop : 'a memop) get_sz at =
-  ignore (memory c (0l @@ at));
+  let _mt = memory c (0l @@ at) in
   let size =
     match get_sz memop.sz with
     | None -> size memop.ty
@@ -295,11 +295,11 @@ let rec check_instr (c : context) (e : instr) (s : infer_stack_type) : op_type =
     [NumType I32Type; NumType memop.ty] --> []
 
   | MemorySize ->
-    ignore (memory c (0l @@ e.at));
+    let _mt = memory c (0l @@ e.at) in
     [] --> [NumType I32Type]
 
   | MemoryGrow ->
-    ignore (memory c (0l @@ e.at));
+    let _mt = memory c (0l @@ e.at) in
     [NumType I32Type] --> [NumType I32Type]
 
   | RefNull ->
@@ -308,6 +308,10 @@ let rec check_instr (c : context) (e : instr) (s : infer_stack_type) : op_type =
   | RefIsNull ->
     [RefType AnyRefType] --> [NumType I32Type]
 
+  | RefFunc x ->
+    let _ft = func c x in
+    [] --> [RefType FuncRefType]
+
   | Const v ->
     let t = NumType (type_num v.it) in
     [] --> [t]
@@ -421,6 +425,7 @@ let check_func (c : context) (f : func) =
 let is_const (c : context) (e : instr) =
   match e.it with
   | RefNull
+  | RefFunc _
   | Const _ -> true
   | GlobalGet x -> let GlobalType (_, mut) = global c x in mut = Immutable
   | _ -> false
@@ -443,14 +448,14 @@ let check_memory (c : context) (mem : memory) =
 
 let check_elem (c : context) (seg : table_segment) =
   let {index; offset; init} = seg.it in
-  check_const c offset (NumType I32Type);
-  ignore (table c index);
-  ignore (List.map (func c) init)
+  let _tt = table c index in
+  let _xs = List.map (func c) init in
+  check_const c offset (NumType I32Type)
 
 let check_data (c : context) (seg : memory_segment) =
   let {index; offset; init} = seg.it in
-  check_const c offset (NumType I32Type);
-  ignore (memory c index)
+  let _mt = memory c index in
+  check_const c offset (NumType I32Type)
 
 let check_global (c : context) (glob : global) =
   let {gtype; value} = glob.it in
diff --git a/proposals/reference-types/Overview.md b/proposals/reference-types/Overview.md
index 22f4812c1d..fba4380322 100644
--- a/proposals/reference-types/Overview.md
+++ b/proposals/reference-types/Overview.md
@@ -73,6 +73,9 @@ New/extended instructions:
 * The new instruction `ref.isnull` checks for null.
   - `ref.isnull : [anyref] -> [i32]`
 
+* The new instruction `ref.func` creates a reference to a given function.
+  - `ref.func $x : [] -> [funcref]` iff `$x` is a function
+
 * The new instructions `table.get` and `table.set` access tables.
   - `table.get $x : [i32] -> [t]` iff `t` is the element type of table `$x`
   - `table.set $x : [i32 t] -> []` iff `t` is the element type of table `$x`
@@ -146,8 +149,9 @@ Additions:
 
 * Add `(ref $t)` as a reference type
   - `reftype ::= ... | ref `
-* Add `(ref.func $f)` and `(call_ref)` instructions
+* Refine `(ref.func $f)` instruction
   - `ref.func $f : [] -> (ref $t)` iff `$f : $t`
+* Add `(call_ref)` instruction
   - `call_ref : [ts1 (ref $t)] -> [ts2]` iff `$t = [ts1] -> [ts2]`
 * Introduce subtyping `ref  < funcref`
 * Subtying between concrete and universal reference types
diff --git a/test/core/ref_func.wast b/test/core/ref_func.wast
new file mode 100644
index 0000000000..5f370d55fe
--- /dev/null
+++ b/test/core/ref_func.wast
@@ -0,0 +1,55 @@
+(module
+  (func (export "f") (param $x i32) (result i32) (local.get $x))
+)
+(register "M")
+
+(module
+  (func $f (import "M" "f") (param i32) (result i32))
+  (func $g (param $x i32) (result i32) (i32.add (local.get $x) (i32.const 1)))
+
+  (global anyref (ref.func $f))
+  (global anyref (ref.func $g))
+  (global funcref (ref.func $f))
+  (global funcref (ref.func $g))
+  (global $v (mut funcref) (ref.func $f))
+
+  (func (export "is_null-f") (result i32)
+    (ref.isnull (ref.func $f))
+  )
+  (func (export "is_null-g") (result i32)
+    (ref.isnull (ref.func $g))
+  )
+  (func (export "is_null-v") (result i32)
+    (ref.isnull (global.get $v))
+  )
+
+  (func (export "set-f") (global.set $v (ref.func $f)))
+  (func (export "set-g") (global.set $v (ref.func $g)))
+
+  (table $t 1 funcref)
+
+  (func (export "call-f") (param $x i32) (result i32)
+    (table.set $t (i32.const 0) (ref.func $f))
+    (call_indirect $t (param i32) (result i32) (local.get $x) (i32.const 0))
+  )
+  (func (export "call-g") (param $x i32) (result i32)
+    (table.set $t (i32.const 0) (ref.func $g))
+    (call_indirect $t (param i32) (result i32) (local.get $x) (i32.const 0))
+  )
+  (func (export "call-v") (param $x i32) (result i32)
+    (table.set $t (i32.const 0) (global.get $v))
+    (call_indirect $t (param i32) (result i32) (local.get $x) (i32.const 0))
+  )
+)
+
+(assert_return (invoke "is_null-f") (i32.const 0))
+(assert_return (invoke "is_null-g") (i32.const 0))
+(assert_return (invoke "is_null-v") (i32.const 0))
+
+(assert_return (invoke "call-f" (i32.const 4)) (i32.const 4))
+(assert_return (invoke "call-g" (i32.const 4)) (i32.const 5))
+(assert_return (invoke "call-v" (i32.const 4)) (i32.const 4))
+(invoke "set-g")
+(assert_return (invoke "call-v" (i32.const 4)) (i32.const 5))
+(invoke "set-f")
+(assert_return (invoke "call-v" (i32.const 4)) (i32.const 4))

From b70d03c26d39616dc13c167836d055ecaa412fa2 Mon Sep 17 00:00:00 2001
From: Andreas Rossberg 
Date: Thu, 13 Dec 2018 10:29:38 +0100
Subject: [PATCH 045/199] Rename ref.isnull to ref.is_null (#23)

---
 document/core/appendix/index-instructions.rst   | 2 +-
 document/core/exec/instructions.rst             | 4 ++--
 document/core/syntax/instructions.rst           | 2 +-
 document/core/text/instructions.rst             | 4 ++--
 document/core/util/macros.def                   | 2 +-
 document/core/valid/instructions.rst            | 2 +-
 interpreter/binary/decode.ml                    | 2 +-
 interpreter/syntax/operators.ml                 | 2 +-
 interpreter/text/arrange.ml                     | 2 +-
 interpreter/text/lexer.mll                      | 2 +-
 interpreter/text/parser.mly                     | 4 ++--
 proposals/reference-types/Overview.md           | 4 ++--
 test/core/ref_func.wast                         | 6 +++---
 test/core/{ref_isnull.wast => ref_is_null.wast} | 4 ++--
 test/core/table_get.wast                        | 8 ++++----
 test/core/table_set.wast                        | 6 +++---
 16 files changed, 28 insertions(+), 28 deletions(-)
 rename test/core/{ref_isnull.wast => ref_is_null.wast} (95%)

diff --git a/document/core/appendix/index-instructions.rst b/document/core/appendix/index-instructions.rst
index f640cf83ee..9861774fdc 100644
--- a/document/core/appendix/index-instructions.rst
+++ b/document/core/appendix/index-instructions.rst
@@ -216,6 +216,6 @@ Instruction                             Binary Opcode     Type
 (reserved)                              :math:`\hex{CE}`                                                  
 (reserved)                              :math:`\hex{CF}`                                                  
 :math:`\REFNULL`                        :math:`\hex{D0}`  :math:`[] \to [\NULLREF]`                   :ref:`validation `        :ref:`execution `
-:math:`\REFISNULL`                      :math:`\hex{D1}`  :math:`[\ANYREF] \to [\I32]`                :ref:`validation `      :ref:`execution `
+:math:`\REFISNULL`                      :math:`\hex{D1}`  :math:`[\ANYREF] \to [\I32]`                :ref:`validation `     :ref:`execution `
 :math:`\REFFUNC~x`                      :math:`\hex{D2}`  :math:`[] \to [\FUNCREF]`                   :ref:`validation `        :ref:`execution `
 ======================================  ================  ==========================================  ========================================  ===============================================================
diff --git a/document/core/exec/instructions.rst b/document/core/exec/instructions.rst
index 0cfdf1da64..2673db49b8 100644
--- a/document/core/exec/instructions.rst
+++ b/document/core/exec/instructions.rst
@@ -193,12 +193,12 @@ Reference Instructions
    No formal reduction rule is required for this instruction, since the |REFNULL| instruction is already a :ref:`value `.
 
 
-.. _exec-ref.isnull:
+.. _exec-ref.is_null:
 
 :math:`\REFISNULL`
 ..................
 
-1. Assert: due to :ref:`validation `, a :ref:`reference value ` is on the top of the stack.
+1. Assert: due to :ref:`validation `, a :ref:`reference value ` is on the top of the stack.
 
 2. Pop the value :math:`\val` from the stack.
 
diff --git a/document/core/syntax/instructions.rst b/document/core/syntax/instructions.rst
index 60aab45277..19efae09f9 100644
--- a/document/core/syntax/instructions.rst
+++ b/document/core/syntax/instructions.rst
@@ -170,7 +170,7 @@ Occasionally, it is convenient to group operators together according to the foll
 .. index:: ! reference instruction, reference, null
    pair: abstract syntax; instruction
 .. _syntax-ref.null:
-.. _syntax-ref.isnull:
+.. _syntax-ref.is_null:
 .. _syntax-ref.func:
 .. _syntax-instr-ref:
 
diff --git a/document/core/text/instructions.rst b/document/core/text/instructions.rst
index f3a6b576ca..002866e190 100644
--- a/document/core/text/instructions.rst
+++ b/document/core/text/instructions.rst
@@ -137,14 +137,14 @@ Reference Instructions
 ~~~~~~~~~~~~~~~~~~~~~~
 
 .. _text-ref.null:
-.. _text-ref.isnull:
+.. _text-ref.is_null:
 .. _text-ref.func:
 
 .. math::
    \begin{array}{llclll}
    \production{instruction} & \Tplaininstr_I &::=& \dots \\ &&|&
      \text{ref.null} &\Rightarrow& \REFNULL \\ &&|&
-     \text{ref.isnull} &\Rightarrow& \REFISNULL \\ &&|&
+     \text{ref.is\_null} &\Rightarrow& \REFISNULL \\
      \text{ref.func}~~x{:}\Tfuncidx &\Rightarrow& \REFFUNC~x \\ &&|&
    \end{array}
 
diff --git a/document/core/util/macros.def b/document/core/util/macros.def
index 8d494cecea..3fe9dfd722 100644
--- a/document/core/util/macros.def
+++ b/document/core/util/macros.def
@@ -335,7 +335,7 @@
 .. |MEMORYGROW| mathdef:: \xref{syntax/instructions}{syntax-instr-memory}{\K{memory.grow}}
 
 .. |REFNULL| mathdef:: \xref{syntax/instructions}{syntax-instr-ref}{\K{ref{.}null}}
-.. |REFISNULL| mathdef:: \xref{syntax/instructions}{syntax-instr-ref}{\K{ref{.}isnull}}
+.. |REFISNULL| mathdef:: \xref{syntax/instructions}{syntax-instr-ref}{\K{ref{.}is\_null}}
 .. |REFFUNC| mathdef:: \xref{syntax/instructions}{syntax-instr-ref}{\K{ref{.}func}}
 
 .. |CONST| mathdef:: \xref{syntax/instructions}{syntax-instr-numeric}{\K{const}}
diff --git a/document/core/valid/instructions.rst b/document/core/valid/instructions.rst
index 9c8114c2bc..619c9d7d8d 100644
--- a/document/core/valid/instructions.rst
+++ b/document/core/valid/instructions.rst
@@ -176,7 +176,7 @@ Reference Instructions
    }
 
 
-.. _valid-ref.isnull:
+.. _valid-ref.is_null:
 
 :math:`\REFISNULL`
 ..................
diff --git a/interpreter/binary/decode.ml b/interpreter/binary/decode.ml
index d7299bd913..e6bb53eba4 100644
--- a/interpreter/binary/decode.ml
+++ b/interpreter/binary/decode.ml
@@ -445,7 +445,7 @@ let rec instr s =
 
   (* TODO: Allocate more adequate opcodes *)
   | 0xd0 -> ref_null
-  | 0xd1 -> ref_isnull
+  | 0xd1 -> ref_is_null
   | 0xd2 -> ref_func (at var s)
 
   | b -> illegal s pos b
diff --git a/interpreter/syntax/operators.ml b/interpreter/syntax/operators.ml
index 6257137846..c77d1e4297 100644
--- a/interpreter/syntax/operators.ml
+++ b/interpreter/syntax/operators.ml
@@ -10,7 +10,7 @@ let i64_const n = Const (I64 n.it @@ n.at)
 let f32_const n = Const (F32 n.it @@ n.at)
 let f64_const n = Const (F64 n.it @@ n.at)
 let ref_null = RefNull
-let ref_isnull = RefIsNull
+let ref_is_null = RefIsNull
 let ref_func x = RefFunc x
 
 let unreachable = Unreachable
diff --git a/interpreter/text/arrange.ml b/interpreter/text/arrange.ml
index 147ee515fe..2d97083aef 100644
--- a/interpreter/text/arrange.ml
+++ b/interpreter/text/arrange.ml
@@ -250,7 +250,7 @@ let rec instr e =
     | MemorySize -> "memory.size", []
     | MemoryGrow -> "memory.grow", []
     | RefNull -> "ref.null", []
-    | RefIsNull -> "ref.isnull", []
+    | RefIsNull -> "ref.is_null", []
     | RefFunc x -> "ref.func " ^ var x, []
     | Const lit -> constop lit ^ " " ^ num lit, []
     | Test op -> testop op, []
diff --git a/interpreter/text/lexer.mll b/interpreter/text/lexer.mll
index 4e1805d5b4..b9f253b58a 100644
--- a/interpreter/text/lexer.mll
+++ b/interpreter/text/lexer.mll
@@ -180,7 +180,7 @@ rule token = parse
   | "ref.null" { REF_NULL }
   | "ref.func" { REF_FUNC }
   | "ref.host" { REF_HOST }
-  | "ref.isnull" { REF_ISNULL }
+  | "ref.is_null" { REF_IS_NULL }
 
   | "nop" { NOP }
   | "unreachable" { UNREACHABLE }
diff --git a/interpreter/text/parser.mly b/interpreter/text/parser.mly
index b6a9237a14..df2c3f85f2 100644
--- a/interpreter/text/parser.mly
+++ b/interpreter/text/parser.mly
@@ -152,7 +152,7 @@ let inline_type_explicit (c : context) x ft at =
 %token CALL CALL_INDIRECT RETURN
 %token LOCAL_GET LOCAL_SET LOCAL_TEE GLOBAL_GET GLOBAL_SET TABLE_GET TABLE_SET
 %token LOAD STORE OFFSET_EQ_NAT ALIGN_EQ_NAT
-%token REF_NULL REF_FUNC REF_HOST REF_ISNULL
+%token REF_NULL REF_FUNC REF_HOST REF_IS_NULL
 %token CONST UNARY BINARY TEST COMPARE CONVERT
 %token UNREACHABLE MEMORY_SIZE MEMORY_GROW
 %token FUNC START TYPE PARAM RESULT LOCAL GLOBAL
@@ -331,7 +331,7 @@ plain_instr :
   | MEMORY_SIZE { fun c -> memory_size }
   | MEMORY_GROW { fun c -> memory_grow }
   | REF_NULL { fun c -> ref_null }
-  | REF_ISNULL { fun c -> ref_isnull }
+  | REF_IS_NULL { fun c -> ref_is_null }
   | REF_FUNC var { fun c -> ref_func ($2 c func) }
   | CONST literal { fun c -> fst (literal $1 $2) }
   | TEST { fun c -> $1 }
diff --git a/proposals/reference-types/Overview.md b/proposals/reference-types/Overview.md
index fba4380322..95e5bd5671 100644
--- a/proposals/reference-types/Overview.md
+++ b/proposals/reference-types/Overview.md
@@ -70,8 +70,8 @@ New/extended instructions:
   - `ref.null : [] -> [nullref]`
   - allowed in constant expressions
 
-* The new instruction `ref.isnull` checks for null.
-  - `ref.isnull : [anyref] -> [i32]`
+* The new instruction `ref.is_null` checks for null.
+  - `ref.is_null : [anyref] -> [i32]`
 
 * The new instruction `ref.func` creates a reference to a given function.
   - `ref.func $x : [] -> [funcref]` iff `$x` is a function
diff --git a/test/core/ref_func.wast b/test/core/ref_func.wast
index 5f370d55fe..f3c8010bab 100644
--- a/test/core/ref_func.wast
+++ b/test/core/ref_func.wast
@@ -14,13 +14,13 @@
   (global $v (mut funcref) (ref.func $f))
 
   (func (export "is_null-f") (result i32)
-    (ref.isnull (ref.func $f))
+    (ref.is_null (ref.func $f))
   )
   (func (export "is_null-g") (result i32)
-    (ref.isnull (ref.func $g))
+    (ref.is_null (ref.func $g))
   )
   (func (export "is_null-v") (result i32)
-    (ref.isnull (global.get $v))
+    (ref.is_null (global.get $v))
   )
 
   (func (export "set-f") (global.set $v (ref.func $f)))
diff --git a/test/core/ref_isnull.wast b/test/core/ref_is_null.wast
similarity index 95%
rename from test/core/ref_isnull.wast
rename to test/core/ref_is_null.wast
index d8bd9fe197..ca4bddbae0 100644
--- a/test/core/ref_isnull.wast
+++ b/test/core/ref_is_null.wast
@@ -1,9 +1,9 @@
 (module
   (func $f2 (export "anyref") (param $x anyref) (result i32)
-    (ref.isnull (local.get $x))
+    (ref.is_null (local.get $x))
   )
   (func $f3 (export "funcref") (param $x funcref) (result i32)
-    (ref.isnull (local.get $x))
+    (ref.is_null (local.get $x))
   )
 
   (table $t2 2 anyref)
diff --git a/test/core/table_get.wast b/test/core/table_get.wast
index 225fd75d6c..bd0c30c9fb 100644
--- a/test/core/table_get.wast
+++ b/test/core/table_get.wast
@@ -15,8 +15,8 @@
     (table.get $t3 (local.get $i))
   )
 
-  (func (export "isnull-funcref") (param $i i32) (result i32)
-    (ref.isnull (call $f3 (local.get $i)))
+  (func (export "is_null-funcref") (param $i i32) (result i32)
+    (ref.is_null (call $f3 (local.get $i)))
   )
 )
 
@@ -26,8 +26,8 @@
 (assert_return (invoke "get-anyref" (i32.const 1)) (ref.host 1))
 
 (assert_return (invoke "get-funcref" (i32.const 0)) (ref.null))
-(assert_return (invoke "isnull-funcref" (i32.const 1)) (i32.const 0))
-(assert_return (invoke "isnull-funcref" (i32.const 2)) (i32.const 0))
+(assert_return (invoke "is_null-funcref" (i32.const 1)) (i32.const 0))
+(assert_return (invoke "is_null-funcref" (i32.const 2)) (i32.const 0))
 
 (assert_trap (invoke "get-anyref" (i32.const 2)) "out of bounds")
 (assert_trap (invoke "get-funcref" (i32.const 3)) "out of bounds")
diff --git a/test/core/table_set.wast b/test/core/table_set.wast
index 222cc43aa9..9cb231b57c 100644
--- a/test/core/table_set.wast
+++ b/test/core/table_set.wast
@@ -20,8 +20,8 @@
     (table.set $t3 (local.get $i) (table.get $t3 (local.get $j)))
   )
 
-  (func (export "isnull-funcref") (param $i i32) (result i32)
-    (ref.isnull (call $f3 (local.get $i)))
+  (func (export "is_null-funcref") (param $i i32) (result i32)
+    (ref.is_null (call $f3 (local.get $i)))
   )
 )
 
@@ -33,7 +33,7 @@
 
 (assert_return (invoke "get-funcref" (i32.const 0)) (ref.null))
 (assert_return (invoke "set-funcref-from" (i32.const 0) (i32.const 1)))
-(assert_return (invoke "isnull-funcref" (i32.const 0)) (i32.const 0))
+(assert_return (invoke "is_null-funcref" (i32.const 0)) (i32.const 0))
 (assert_return (invoke "set-funcref" (i32.const 0) (ref.null)))
 (assert_return (invoke "get-funcref" (i32.const 0)) (ref.null))
 

From 178a7f6338f97a233de82fa45971d35d122a97e6 Mon Sep 17 00:00:00 2001
From: Ben Smith 
Date: Wed, 9 Jan 2019 08:32:18 -0800
Subject: [PATCH 046/199] Two zero immediates for memory.copy and table.copy
 (#43)

See https://github.com/WebAssembly/reference-types/issues/18, #29, and #36
---
 proposals/bulk-memory-operations/Overview.md | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/proposals/bulk-memory-operations/Overview.md b/proposals/bulk-memory-operations/Overview.md
index 05ee5e2d70..6184f767d5 100644
--- a/proposals/bulk-memory-operations/Overview.md
+++ b/proposals/bulk-memory-operations/Overview.md
@@ -287,8 +287,8 @@ that were dropped after being copied into memory during module instantiation.
 Copy data from a source memory region to destination region; these regions may
 overlap: the copy is performed as if the source region was first copied to a
 temporary buffer, then the temporary buffer is copied to the destination
-region. This instruction has an immediate argument of which memory to operate
-on, and it must be zero for now.
+region. This instruction has two immediate arguments: the source and
+destination memory indices. They currently both must be zero.
 
 The instruction has the signature `[i32 i32 i32] -> []`. The parameters are, in order:
 
@@ -355,11 +355,11 @@ instr ::= ...
 | ---- | ---- | ---- | ---- |
 | `memory.init` | `0xfc 0x08` | `memory:0x00`, `segment:varuint32` | :thinking: copy from a passive data segment to linear memory |
 | `memory.drop` | `0xfc 0x09` | `segment:varuint32` | :thinking: prevent further use of passive data segment |
-| `memory.copy` | `0xfc 0x0a` | `memory:0x00` | :thinking: copy from one region of linear memory to another region |
+| `memory.copy` | `0xfc 0x0a` | `memory_src:0x00` `memory_dst:0x00` | :thinking: copy from one region of linear memory to another region |
 | `memory.fill` | `0xfc 0x0b` | `memory:0x00` | :thinking: fill a region of linear memory with a given byte value |
 | `table.init` | `0xfc 0x0c` | `table:0x00`, `segment:varuint32` | :thinking: copy from a passive element segment to a table |
 | `table.drop` | `0xfc 0x0d` | `segment:varuint32` | :thinking: prevent further use of a passive element segment |
-| `table.copy` | `0xfc 0x0e` | `table:0x00` | :thinking: copy from one region of a table to another region |
+| `table.copy` | `0xfc 0x0e` | `table_src:0x00` `table_dst:0x00` | :thinking: copy from one region of a table to another region |
 
 ### `DataCount` section
 

From 446b9c2b8ac5186768bb1d0eccd96052f20a7f03 Mon Sep 17 00:00:00 2001
From: Ben Smith 
Date: Wed, 9 Jan 2019 10:37:30 -0800
Subject: [PATCH 047/199] Reverse order of {table,memory}.init immediates (#45)

The order of the `table.init` and `memory.init` immediates should be the index followed by the reserved byte (which is a placeholder for the table or memory index). This matches ordering of immediates in `call_indirect` (type index, followed by table index reserved byte).
---
 proposals/bulk-memory-operations/Overview.md | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/proposals/bulk-memory-operations/Overview.md b/proposals/bulk-memory-operations/Overview.md
index 6184f767d5..feaad17ccd 100644
--- a/proposals/bulk-memory-operations/Overview.md
+++ b/proposals/bulk-memory-operations/Overview.md
@@ -353,11 +353,11 @@ instr ::= ...
 
 | Name | Opcode | Immediate | Description |
 | ---- | ---- | ---- | ---- |
-| `memory.init` | `0xfc 0x08` | `memory:0x00`, `segment:varuint32` | :thinking: copy from a passive data segment to linear memory |
+| `memory.init` | `0xfc 0x08` | `segment:varuint32`, `memory:0x00` | :thinking: copy from a passive data segment to linear memory |
 | `memory.drop` | `0xfc 0x09` | `segment:varuint32` | :thinking: prevent further use of passive data segment |
 | `memory.copy` | `0xfc 0x0a` | `memory_src:0x00` `memory_dst:0x00` | :thinking: copy from one region of linear memory to another region |
 | `memory.fill` | `0xfc 0x0b` | `memory:0x00` | :thinking: fill a region of linear memory with a given byte value |
-| `table.init` | `0xfc 0x0c` | `table:0x00`, `segment:varuint32` | :thinking: copy from a passive element segment to a table |
+| `table.init` | `0xfc 0x0c` | `segment:varuint32`, `table:0x00` | :thinking: copy from a passive element segment to a table |
 | `table.drop` | `0xfc 0x0d` | `segment:varuint32` | :thinking: prevent further use of a passive element segment |
 | `table.copy` | `0xfc 0x0e` | `table_src:0x00` `table_dst:0x00` | :thinking: copy from one region of a table to another region |
 

From 3115daaf9c89870e43156687da2efd45926147e5 Mon Sep 17 00:00:00 2001
From: gahaas 
Date: Wed, 16 Jan 2019 12:57:06 +0100
Subject: [PATCH 048/199] Fix small typo in validation->set_table (#27)

---
 document/core/valid/instructions.rst | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/document/core/valid/instructions.rst b/document/core/valid/instructions.rst
index 619c9d7d8d..7241562330 100644
--- a/document/core/valid/instructions.rst
+++ b/document/core/valid/instructions.rst
@@ -384,7 +384,7 @@ Table Instructions
 :math:`\TABLESET~x`
 ...................
 
-* The local :math:`C.\CTABLES[x]` must be defined in the context.
+* The table :math:`C.\CTABLES[x]` must be defined in the context.
 
 * Let :math:`\limits~t` be the :ref:`table type ` :math:`C.\CTABLES[x]`.
 

From af60ffe3c1f75f54857a2f1d537fd68daa607b19 Mon Sep 17 00:00:00 2001
From: Lars T Hansen 
Date: Tue, 22 Jan 2019 17:58:39 +0100
Subject: [PATCH 049/199] Rename memory.drop and table.drop as per agreement
 (#46)

---
 proposals/bulk-memory-operations/Overview.md | 26 ++++++++++----------
 1 file changed, 13 insertions(+), 13 deletions(-)

diff --git a/proposals/bulk-memory-operations/Overview.md b/proposals/bulk-memory-operations/Overview.md
index feaad17ccd..c9e63c0643 100644
--- a/proposals/bulk-memory-operations/Overview.md
+++ b/proposals/bulk-memory-operations/Overview.md
@@ -183,12 +183,12 @@ as an operand to `memory.init` or `table.init`.
 
 Segments can also be discarded by using the following new instructions:
 
-* `memory.drop`: prevent further use of a data segment
-* `table.drop`: prevent further use of an element segment
+* `data.drop`: prevent further use of a data segment
+* `elem.drop`: prevent further use of an element segment
 
 An active segment is equivalent to a passive segment, but with an implicit
-`memory.init` followed by a `memory.drop` (or `table.init` followed by a
-`table.drop`) that is prepended to the module's start function.
+`memory.init` followed by a `data.drop` (or `table.init` followed by a
+`elem.drop`) that is prepended to the module's start function.
 
 The new encoding of a data segment is now:
 
@@ -261,7 +261,7 @@ target offset, and length as given by the `memory.init` operands.
 It is a validation error to use `memory.init` with an out-of-bounds segment index.
 
 A trap occurs if:
-* the segment is used after it has been dropped via `memory.drop`. This includes
+* the segment is used after it has been dropped via `data.drop`. This includes
   active segments that were dropped after being copied into memory during module
   instantiation.
 * any of the accessed bytes lies outside the source data segment or the target memory
@@ -269,15 +269,15 @@ A trap occurs if:
 Note that it is allowed to use `memory.init` on the same data segment more than
 once.
 
-### `memory.drop` instruction
+### `data.drop` instruction
 
-The `memory.drop` instruction prevents further use of a given segment. After a
+The `data.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 `memory.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.
 
-It is a validation error to use `memory.drop` with an out-of-bounds segment index.
+It is a validation error to use `data.drop` with an out-of-bounds segment index.
 
 A trap occurs if the segment was already dropped. This includes active segments
 that were dropped after being copied into memory during module instantiation.
@@ -307,7 +307,7 @@ The instruction has the signature `[i32 i32 i32] -> []`. The parameters are, in
 - top-1: byte value to set
 - top-0: size of memory region in bytes
 
-### `table.init`, `table.drop`, and `table.copy` instructions
+### `table.init`, `elem.drop`, and `table.copy` instructions
 
 The `table.*` instructions behave similary to the `memory.*` instructions, with
 the difference that they operate on element segments and tables, instead of
@@ -337,7 +337,7 @@ implemented as follows:
 
     ;; The memory used by this segment is no longer needed, so this segment can
     ;; be dropped.
-    (memory.drop 1))
+    (data.drop 1))
 )
 ```
 
@@ -354,11 +354,11 @@ instr ::= ...
 | Name | Opcode | Immediate | Description |
 | ---- | ---- | ---- | ---- |
 | `memory.init` | `0xfc 0x08` | `segment:varuint32`, `memory:0x00` | :thinking: copy from a passive data segment to linear memory |
-| `memory.drop` | `0xfc 0x09` | `segment:varuint32` | :thinking: prevent further use of passive data segment |
+| `data.drop` | `0xfc 0x09` | `segment:varuint32` | :thinking: prevent further use of passive data segment |
 | `memory.copy` | `0xfc 0x0a` | `memory_src:0x00` `memory_dst:0x00` | :thinking: copy from one region of linear memory to another region |
 | `memory.fill` | `0xfc 0x0b` | `memory:0x00` | :thinking: fill a region of linear memory with a given byte value |
 | `table.init` | `0xfc 0x0c` | `segment:varuint32`, `table:0x00` | :thinking: copy from a passive element segment to a table |
-| `table.drop` | `0xfc 0x0d` | `segment:varuint32` | :thinking: prevent further use of a passive element segment |
+| `elem.drop` | `0xfc 0x0d` | `segment:varuint32` | :thinking: prevent further use of a passive element segment |
 | `table.copy` | `0xfc 0x0e` | `table_src:0x00` `table_dst:0x00` | :thinking: copy from one region of a table to another region |
 
 ### `DataCount` section
@@ -403,4 +403,4 @@ segments in the `Data` section:
 
 It is a validation error if `count` is not equal to the number of data segments
 in the `Data` section. It is also a validation error if the `DataCount` section
-is omitted and a `memory.init` or `memory.drop` instruction is used.
+is omitted and a `memory.init` or `data.drop` instruction is used.

From 241c48d0c0f7ef0acf2e6e7528435f00a7649ab4 Mon Sep 17 00:00:00 2001
From: gahaas 
Date: Wed, 23 Jan 2019 11:49:37 +0100
Subject: [PATCH 050/199] [spec] Fix typo (#28)

---
 document/core/valid/types.rst | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/document/core/valid/types.rst b/document/core/valid/types.rst
index bf85cbdaae..1d3de66a0f 100644
--- a/document/core/valid/types.rst
+++ b/document/core/valid/types.rst
@@ -166,7 +166,7 @@ A :ref:`number type ` :math:`\numtype_1` matches a :ref:`number
 Reference Types
 ...............
 
-A :ref:`reference type ` :math:`\reftype_1` matches a :ref:`number type ` :math:`\reftype_2` if and only if:
+A :ref:`reference type ` :math:`\reftype_1` matches a :ref:`reference type ` :math:`\reftype_2` if and only if:
 
 * Either both :math:`\reftype_1` and :math:`\reftype_2` are the same.
 

From e27277dac4ea78123b257da8da57258d4e4860ba Mon Sep 17 00:00:00 2001
From: Ben Smith 
Date: Thu, 24 Jan 2019 10:46:48 -0800
Subject: [PATCH 051/199] Clarify *.{init,copy,fill} w/ zero count (#48)

`memory.init`, `memory.copy`, `memory.fill`, `table.init`, and `table.copy` should all fail if their ranges are out-of-bounds, even if the count is zero, similar to for active segments. See the discussions here: https://github.com/WebAssembly/design/issues/897, https://github.com/WebAssembly/bulk-memory-operations/issues/11.
---
 proposals/bulk-memory-operations/Overview.md | 11 +++++++++++
 1 file changed, 11 insertions(+)

diff --git a/proposals/bulk-memory-operations/Overview.md b/proposals/bulk-memory-operations/Overview.md
index c9e63c0643..304f20a570 100644
--- a/proposals/bulk-memory-operations/Overview.md
+++ b/proposals/bulk-memory-operations/Overview.md
@@ -265,6 +265,8 @@ A trap occurs if:
   active segments that were dropped after being copied into memory during module
   instantiation.
 * any of the accessed bytes lies outside the source data segment or the target memory
+* the source offset is outside the source data segment
+* the destination offset is outside the target memory
 
 Note that it is allowed to use `memory.init` on the same data segment more than
 once.
@@ -296,6 +298,11 @@ The instruction has the signature `[i32 i32 i32] -> []`. The parameters are, in
 - top-1: source address
 - top-0: size of memory region in bytes
 
+A trap occurs if:
+* any of the accessed bytes lies outside the source or target memory
+* the source offset is outside the source memory
+* the destination offset is outside the target memory
+
 ### `memory.fill` instruction
 
 Set all bytes in a memory region to a given byte. This instruction has an
@@ -307,6 +314,10 @@ The instruction has the signature `[i32 i32 i32] -> []`. The parameters are, in
 - top-1: byte value to set
 - top-0: size of memory region in bytes
 
+A trap occurs if:
+* any of the accessed bytes lies outside the target memory
+* the destination offset is outside the target memory
+
 ### `table.init`, `elem.drop`, and `table.copy` instructions
 
 The `table.*` instructions behave similary to the `memory.*` instructions, with

From b752e8bc9a2d963d3adcd4804a8687f0305bd120 Mon Sep 17 00:00:00 2001
From: Lars T Hansen 
Date: Mon, 28 Jan 2019 13:05:20 +0100
Subject: [PATCH 052/199] Clarify trapping semantics (#50)

* Clarify trapping semantics
---
 proposals/bulk-memory-operations/Overview.md | 35 ++++++++++++++++++++
 1 file changed, 35 insertions(+)

diff --git a/proposals/bulk-memory-operations/Overview.md b/proposals/bulk-memory-operations/Overview.md
index 304f20a570..9eb3849220 100644
--- a/proposals/bulk-memory-operations/Overview.md
+++ b/proposals/bulk-memory-operations/Overview.md
@@ -271,6 +271,21 @@ A trap occurs if:
 Note that it is allowed to use `memory.init` on the same data segment more than
 once.
 
+Initialization takes place bytewise from lower addresses toward higher
+addresses.  A trap resulting from an access outside the source data
+segment or target memory only occurs once the first byte that is
+outside the source or target is reached.  Bytes written before the
+trap stay written.
+
+(Data are read and written as-if individual bytes were read and
+written, but various optimizations are possible that avoid reading and
+writing only individual bytes.)
+
+Note that the semantics require bytewise accesses, so a trap that
+might result from, say, reading a sequence of several words before
+writing any, will have to be handled carefully: the reads that
+succeeded will have to be written, if possible.
+
 ### `data.drop` instruction
 
 The `data.drop` instruction prevents further use of a given segment. After a
@@ -303,6 +318,18 @@ A trap occurs if:
 * the source offset is outside the source memory
 * the destination offset is outside the target memory
 
+All the data are read before any is written, and writing takes place
+bytewise from lower addresses toward higher addresses.  A trap
+resulting from an access outside the source memory is thus signalled
+before any target bytes are affected.  A trap resulting from an access
+outside the target memory only occurs once the first byte that is
+outside the target is reached.  Bytes written before the trap stay
+written.
+
+TODO: While those semantics are efficient in the context of unshared
+memory, they are not efficient in the context of shared memory with
+mprotect, and need to be improved.
+
 ### `memory.fill` instruction
 
 Set all bytes in a memory region to a given byte. This instruction has an
@@ -318,6 +345,14 @@ A trap occurs if:
 * any of the accessed bytes lies outside the target memory
 * the destination offset is outside the target memory
 
+Filling takes place bytewise from lower addresses toward higher
+addresses.  A trap resulting from an access outside the target memory
+only occurs once the first byte that is outside the target is reached.
+Bytes written before the trap stay written.
+
+(Data are written as-if individual bytes were written, but various
+optimizations are possible that avoid writing only individual bytes.)
+
 ### `table.init`, `elem.drop`, and `table.copy` instructions
 
 The `table.*` instructions behave similary to the `memory.*` instructions, with

From 79bf48c60644c7af6be3abcbe174b53fe372919c Mon Sep 17 00:00:00 2001
From: Lars T Hansen 
Date: Wed, 30 Jan 2019 09:36:36 +0100
Subject: [PATCH 053/199] Remove the intermediate buffer for memory.copy (#51)

---
 proposals/bulk-memory-operations/Overview.md | 42 +++++++++++++-------
 1 file changed, 27 insertions(+), 15 deletions(-)

diff --git a/proposals/bulk-memory-operations/Overview.md b/proposals/bulk-memory-operations/Overview.md
index 9eb3849220..9979b9d0b7 100644
--- a/proposals/bulk-memory-operations/Overview.md
+++ b/proposals/bulk-memory-operations/Overview.md
@@ -301,12 +301,27 @@ that were dropped after being copied into memory during module instantiation.
 
 ### `memory.copy` instruction
 
-Copy data from a source memory region to destination region; these regions may
-overlap: the copy is performed as if the source region was first copied to a
-temporary buffer, then the temporary buffer is copied to the destination
-region. This instruction has two immediate arguments: the source and
+Copy data from a source memory region to destination region.  The
+regions are said to overlap if they are in the same memory and the
+start address of one region is one of the addresses that's read or
+written (by the copy operation) in the other region.
+
+This instruction has two immediate arguments: the source and
 destination memory indices. They currently both must be zero.
 
+If the regions overlap, and the source region starts at a lower
+address than the target region, then the copy takes place as if from
+higher to lower addresses: the highest source address is read first
+and the value is written to the highest target address, then the next
+highest, and so on.  Otherwise, the copy takes place as if from lower
+to higher addresses: the lowest source address is read first and the
+value is written to the lowest target address, then the next lowest,
+and so on.
+
+(The direction of the copy is defined in order to future-proof
+`memory.copy` for shared memory and a memory read/write protection
+feature.)
+
 The instruction has the signature `[i32 i32 i32] -> []`. The parameters are, in order:
 
 - top-2: destination address
@@ -318,17 +333,14 @@ A trap occurs if:
 * the source offset is outside the source memory
 * the destination offset is outside the target memory
 
-All the data are read before any is written, and writing takes place
-bytewise from lower addresses toward higher addresses.  A trap
-resulting from an access outside the source memory is thus signalled
-before any target bytes are affected.  A trap resulting from an access
-outside the target memory only occurs once the first byte that is
-outside the target is reached.  Bytes written before the trap stay
-written.
-
-TODO: While those semantics are efficient in the context of unshared
-memory, they are not efficient in the context of shared memory with
-mprotect, and need to be improved.
+A trap resulting from an access outside the source or target region
+only occurs once the first byte that is outside the source or target
+is reached (in the defined copy order).  Bytes written before the trap
+stay written.
+
+(Data are read and written as-if individual bytes were read and
+written, but various optimizations are possible that avoid reading and
+writing only individual bytes.)
 
 ### `memory.fill` instruction
 

From f497d55822cb29ac8a6fd883468996fc1b47ff4f Mon Sep 17 00:00:00 2001
From: Ben Smith 
Date: Mon, 4 Feb 2019 10:27:31 -0800
Subject: [PATCH 054/199] [Overview] Update segment initialization text (#57)

See issue #56.
---
 proposals/bulk-memory-operations/Overview.md | 24 +++++++++++++++-----
 1 file changed, 18 insertions(+), 6 deletions(-)

diff --git a/proposals/bulk-memory-operations/Overview.md b/proposals/bulk-memory-operations/Overview.md
index 9979b9d0b7..8f2ff08fb9 100644
--- a/proposals/bulk-memory-operations/Overview.md
+++ b/proposals/bulk-memory-operations/Overview.md
@@ -241,6 +241,24 @@ An `elem_expr` is like an `init_expr`, but can only contain expressions of the f
 
 TODO: coordinate with other proposals to determine the binary encoding for `ref.null` and `ref.func`.
 
+### Segment Initialization
+
+In the MVP, segments are initialized during module instantiation. If any segment
+would be initialized out-of-bounds, then the memory or table instance is not
+modified.
+
+This behavior is changed in the bulk memory proposal.
+
+Each active segment is initialized in module-definition order. For each
+segment, each byte in the data segment is copied into the memory, in order of
+lowest to highest addresses. If, for a given byte, the copy is out-of-bounds,
+instantiation fails and no further bytes in this segment nor further segments
+are copied. Bytes written before this point stay written.
+
+The behavior of element segment initialization is changed similarly, with the
+difference that elements are copied from element segments into tables, instead
+of bytes being copied from data segments into memories.
+
 ### `memory.init` instruction
 
 The `memory.init` instruction copies data from a given passive segment into a target
@@ -252,12 +270,6 @@ The instruction has the signature `[i32 i32 i32] -> []`. The parameters are, in
 - top-1: offset into the source segment
 - top-0: size of memory region in bytes
 
-When `memory.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 `memory.init` operands.
-
 It is a validation error to use `memory.init` with an out-of-bounds segment index.
 
 A trap occurs if:

From a252581ee41e30f00eef849c7deb6817ec74ece5 Mon Sep 17 00:00:00 2001
From: Ben Smith 
Date: Tue, 5 Feb 2019 12:00:35 -0800
Subject: [PATCH 055/199] [interpreter] Implement bulk memory operations (#54)

This adds the new operations, as well as the new data and element
segment formats.

Implemented:

* Text parsing/writing
* Binary encoding/decoding
* Validation

TODO:

* Tests
* DataCount section
* Proper encoding of passive element segments (using ref.null etc)
* Evaluation
---
 interpreter/binary/decode.ml    | 54 ++++++++++++++++-----
 interpreter/binary/encode.ml    | 22 ++++++++-
 interpreter/exec/eval.ml        | 42 ++++++++++-------
 interpreter/syntax/ast.ml       | 14 +++++-
 interpreter/syntax/operators.ml |  7 +++
 interpreter/syntax/types.ml     |  1 +
 interpreter/text/arrange.ml     | 14 +++++-
 interpreter/text/lexer.mll      | 10 ++++
 interpreter/text/parser.mly     | 84 ++++++++++++++++++++++++++-------
 interpreter/valid/valid.ml      | 61 ++++++++++++++++++++----
 10 files changed, 248 insertions(+), 61 deletions(-)

diff --git a/interpreter/binary/decode.ml b/interpreter/binary/decode.ml
index 1c6da1d4bd..631f7d14be 100644
--- a/interpreter/binary/decode.ml
+++ b/interpreter/binary/decode.ml
@@ -193,6 +193,7 @@ let var s = vu32 s
 
 let op s = u8 s
 let end_ s = expect 0x0b s "END opcode expected"
+let zero_flag s = expect 0x00 s "zero flag expected"
 
 let memop s =
   let align = vu32 s in
@@ -200,6 +201,25 @@ let memop s =
   let offset = vu32 s in
   Int32.to_int align, offset
 
+let misc_instr s =
+  let pos = pos s in
+  match op s with
+  | 0x08 ->
+    let x = at var s in
+    zero_flag s;
+    memory_init x
+  | 0x09 -> data_drop (at var s)
+  | 0x0a -> zero_flag s; zero_flag s; memory_copy
+  | 0x0b -> zero_flag s; memory_fill
+  | 0x0c ->
+    let x = at var s in
+    zero_flag s;
+    table_init x
+  | 0x0d -> elem_drop (at var s)
+  | 0x0e -> zero_flag s; zero_flag s; table_copy
+
+  | b -> illegal s pos b
+
 let rec instr s =
   let pos = pos s in
   match op s with
@@ -244,7 +264,7 @@ let rec instr s =
   | 0x10 -> call (at var s)
   | 0x11 ->
     let x = at var s in
-    expect 0x00 s "zero flag expected";
+    zero_flag s;
     call_indirect x
 
   | 0x12 | 0x13 | 0x14 | 0x15 | 0x16 | 0x17 | 0x18 | 0x19 as b -> illegal s pos b
@@ -287,12 +307,8 @@ let rec instr s =
   | 0x3d -> let a, o = memop s in i64_store16 a o
   | 0x3e -> let a, o = memop s in i64_store32 a o
 
-  | 0x3f ->
-    expect 0x00 s "zero flag expected";
-    memory_size
-  | 0x40 ->
-    expect 0x00 s "zero flag expected";
-    memory_grow
+  | 0x3f -> zero_flag s; memory_size
+  | 0x40 -> zero_flag s; memory_grow
 
   | 0x41 -> i32_const (at vs32 s)
   | 0x42 -> i64_const (at vs64 s)
@@ -432,6 +448,8 @@ let rec instr s =
   | 0xbe -> f32_reinterpret_i32
   | 0xbf -> f64_reinterpret_i64
 
+  | 0xfc -> misc_instr s
+
   | b -> illegal s pos b
 
 and instr_block s = List.rev (instr_block' s [])
@@ -589,10 +607,24 @@ let code_section s =
 (* Element section *)
 
 let segment dat s =
-  let index = at var s in
-  let offset = const s in
-  let init = dat s in
-  {index; offset; init}
+  match vu32 s with
+  | 0l ->
+    let index = Source.(0l @@ Source.no_region) in
+    let offset = const s in
+    let sdesc = Active {index; offset} in
+    let init = dat s in
+    {sdesc; init}
+  | 1l ->
+    let sdesc = Passive in
+    let init = dat s in
+    {sdesc; init}
+  | 2l ->
+    let index = at var s in
+    let offset = const s in
+    let sdesc = Active {index; offset} in
+    let init = dat s in
+    {sdesc; init}
+  | _ -> error s (pos s - 1) "invalid segment flags"
 
 let table_segment s =
   segment (vec (at var)) s
diff --git a/interpreter/binary/encode.ml b/interpreter/binary/encode.ml
index 696dac418e..0dd29afe4c 100644
--- a/interpreter/binary/encode.ml
+++ b/interpreter/binary/encode.ml
@@ -363,6 +363,14 @@ let encode m =
       | Convert (F64 F64Op.DemoteF64) -> assert false
       | Convert (F64 F64Op.ReinterpretInt) -> op 0xbf
 
+      | MemoryInit x -> op 0xfc; op 0x08; var x; u8 0x00
+      | DataDrop x -> op 0xfc; op 0x09; var x
+      | MemoryCopy -> op 0xfc; op 0x0a; u8 0x00; u8 0x00
+      | MemoryFill -> op 0xfc; op 0x0b; u8 0x00
+      | TableInit x -> op 0xfc; op 0x0c; var x; u8 0x00
+      | ElemDrop x -> op 0xfc; op 0x0d; var x
+      | TableCopy -> op 0xfc; op 0x0e; u8 0x00; u8 0x00
+
     let const c =
       list instr c.it; end_ ()
 
@@ -470,8 +478,18 @@ let encode m =
 
     (* Element section *)
     let segment dat seg =
-      let {index; offset; init} = seg.it in
-      var index; const offset; dat init
+      let {sdesc; init} = seg.it in
+      match sdesc with
+      | Active {index; offset} ->
+        if index.it = 0l then
+          u8 0x00
+        else begin
+          u8 0x02; var index
+        end;
+        const offset;
+        dat init
+      | Passive ->
+          u8 0x01; dat init
 
     let table_segment seg =
       segment (vec var) seg
diff --git a/interpreter/exec/eval.ml b/interpreter/exec/eval.ml
index ca82b73453..a4646983aa 100644
--- a/interpreter/exec/eval.ml
+++ b/interpreter/exec/eval.ml
@@ -388,26 +388,32 @@ let init_func (inst : module_inst) (func : func_inst) =
   | _ -> assert false
 
 let init_table (inst : module_inst) (seg : table_segment) =
-  let {index; offset = const; init} = seg.it in
-  let tab = table inst index in
-  let offset = i32 (eval_const inst const) const.at in
-  let end_ = Int32.(add offset (of_int (List.length init))) in
-  let bound = Table.size tab in
-  if I32.lt_u bound end_ || I32.lt_u end_ offset then
-    Link.error seg.at "elements segment does not fit table";
-  fun () ->
-    Table.blit tab offset (List.map (fun x -> FuncElem (func inst x)) init)
+  let {sdesc; init} = seg.it in
+  match sdesc with
+  | Active {index; offset = const} ->
+    let tab = table inst index in
+    let offset = i32 (eval_const inst const) const.at in
+    let end_ = Int32.(add offset (of_int (List.length init))) in
+    let bound = Table.size tab in
+    if I32.lt_u bound end_ || I32.lt_u end_ offset then
+      Link.error seg.at "elements segment does not fit table";
+    fun () ->
+      Table.blit tab offset (List.map (fun x -> FuncElem (func inst x)) init)
+  | Passive -> fun () -> ()
 
 let init_memory (inst : module_inst) (seg : memory_segment) =
-  let {index; offset = const; init} = seg.it in
-  let mem = memory inst index in
-  let offset' = i32 (eval_const inst const) const.at in
-  let offset = I64_convert.extend_u_i32 offset' in
-  let end_ = Int64.(add offset (of_int (String.length init))) in
-  let bound = Memory.bound mem in
-  if I64.lt_u bound end_ || I64.lt_u end_ offset then
-    Link.error seg.at "data segment does not fit memory";
-  fun () -> Memory.store_bytes mem offset init
+  let {sdesc; init} = seg.it in
+  match sdesc with
+  | Active {index; offset = const} ->
+    let mem = memory inst index in
+    let offset' = i32 (eval_const inst const) const.at in
+    let offset = I64_convert.extend_u_i32 offset' in
+    let end_ = Int64.(add offset (of_int (String.length init))) in
+    let bound = Memory.bound mem in
+    if I64.lt_u bound end_ || I64.lt_u end_ offset then
+      Link.error seg.at "data segment does not fit memory";
+    fun () -> Memory.store_bytes mem offset init
+  | Passive -> fun () -> ()
 
 
 let add_import (m : module_) (ext : extern) (im : import) (inst : module_inst)
diff --git a/interpreter/syntax/ast.ml b/interpreter/syntax/ast.ml
index 51b2f9213e..501e5e36aa 100644
--- a/interpreter/syntax/ast.ml
+++ b/interpreter/syntax/ast.ml
@@ -97,12 +97,23 @@ and instr' =
   | Unary of unop                     (* unary numeric operator *)
   | Binary of binop                   (* binary numeric operator *)
   | Convert of cvtop                  (* conversion *)
+  | MemoryInit of var                 (* initialize memory from segment *)
+  | DataDrop of var                   (* drop passive data segment *)
+  | MemoryCopy                        (* copy memory regions *)
+  | MemoryFill                        (* fill memory region with value *)
+  | TableInit of var                  (* initialize table from segment *)
+  | ElemDrop of var                   (* drop passive element segment *)
+  | TableCopy                         (* copy elements between table regions *)
 
 
 (* Globals & Functions *)
 
 type const = instr list Source.phrase
 
+type segment_desc =
+  | Active of {index : var; offset : const}
+  | Passive
+
 type global = global' Source.phrase
 and global' =
 {
@@ -136,8 +147,7 @@ and memory' =
 type 'data segment = 'data segment' Source.phrase
 and 'data segment' =
 {
-  index : var;
-  offset : const;
+  sdesc : segment_desc;
   init : 'data;
 }
 
diff --git a/interpreter/syntax/operators.ml b/interpreter/syntax/operators.ml
index 2b84fcea0f..590e80cb24 100644
--- a/interpreter/syntax/operators.ml
+++ b/interpreter/syntax/operators.ml
@@ -202,3 +202,10 @@ let f64_reinterpret_i64 = Convert (F64 F64Op.ReinterpretInt)
 let memory_size = MemorySize
 let memory_grow = MemoryGrow
 
+let memory_init x = MemoryInit x
+let data_drop x = DataDrop x
+let memory_copy = MemoryCopy
+let memory_fill = MemoryFill
+let table_init x = TableInit x
+let elem_drop x = ElemDrop x
+let table_copy = TableCopy
diff --git a/interpreter/syntax/types.ml b/interpreter/syntax/types.ml
index f708e4b890..7bea4aa699 100644
--- a/interpreter/syntax/types.ml
+++ b/interpreter/syntax/types.ml
@@ -15,6 +15,7 @@ type extern_type =
   | ExternTableType of table_type
   | ExternMemoryType of memory_type
   | ExternGlobalType of global_type
+type segment_type = Seg
 
 
 (* Attributes *)
diff --git a/interpreter/text/arrange.ml b/interpreter/text/arrange.ml
index 76f279aba0..dd19840d13 100644
--- a/interpreter/text/arrange.ml
+++ b/interpreter/text/arrange.ml
@@ -252,6 +252,13 @@ let rec instr e =
     | Unary op -> unop op, []
     | Binary op -> binop op, []
     | Convert op -> cvtop op, []
+    | MemoryInit x -> "memory.init " ^ var x, []
+    | DataDrop x -> "data.drop " ^ var x, []
+    | MemoryCopy -> "memory.copy", []
+    | MemoryFill -> "memory.fill", []
+    | TableInit x -> "table.init " ^ var x, []
+    | ElemDrop x -> "elem.drop " ^ var x, []
+    | TableCopy -> "table.copy", []
   in Node (head, inner)
 
 let const c =
@@ -290,8 +297,11 @@ let memory off i mem =
   Node ("memory $" ^ nat (off + i) ^ " " ^ limits nat32 lim, [])
 
 let segment head dat seg =
-  let {index; offset; init} = seg.it in
-  Node (head, atom var index :: Node ("offset", const offset) :: dat init)
+  let {sdesc; init} = seg.it in
+  match sdesc with
+  | Active {index; offset} ->
+    Node (head, atom var index :: Node ("offset", const offset) :: dat init)
+  | Passive -> Node (head, dat init)
 
 let elems seg =
   segment "elem" (list (atom var)) seg
diff --git a/interpreter/text/lexer.mll b/interpreter/text/lexer.mll
index 3b67da7ce1..893bc18b67 100644
--- a/interpreter/text/lexer.mll
+++ b/interpreter/text/lexer.mll
@@ -317,6 +317,16 @@ rule token = parse
   | "memory.size" { MEMORY_SIZE }
   | "memory.grow" { MEMORY_GROW }
 
+  | "memory.init" { MEMORY_INIT }
+  | "data.drop" { DATA_DROP }
+  | "memory.copy" { MEMORY_COPY }
+  | "memory.fill" { MEMORY_FILL }
+  | "table.init" { TABLE_INIT }
+  | "elem.drop" { ELEM_DROP }
+  | "table.copy" { TABLE_COPY }
+
+  | "passive" { PASSIVE }
+
   | "type" { TYPE }
   | "func" { FUNC }
   | "start" { START }
diff --git a/interpreter/text/parser.mly b/interpreter/text/parser.mly
index c72b3cf3fe..2041a811ad 100644
--- a/interpreter/text/parser.mly
+++ b/interpreter/text/parser.mly
@@ -64,11 +64,14 @@ let empty_types () = {space = empty (); list = []}
 
 type context =
   { types : types; tables : space; memories : space;
-    funcs : space; locals : space; globals : space; labels : int32 VarMap.t }
+    funcs : space; locals : space; globals : space;
+    data : space; elems : space;
+    labels : int32 VarMap.t }
 
 let empty_context () =
   { types = empty_types (); tables = empty (); memories = empty ();
     funcs = empty (); locals = empty (); globals = empty ();
+    data = empty (); elems = empty ();
     labels = VarMap.empty }
 
 let enter_func (c : context) =
@@ -84,6 +87,8 @@ let local (c : context) x = lookup "local" c.locals x
 let global (c : context) x = lookup "global" c.globals x
 let table (c : context) x = lookup "table" c.tables x
 let memory (c : context) x = lookup "memory" c.memories x
+let data (c : context) x = lookup "data segment" c.data x
+let elem (c : context) x = lookup "elem segment" c.elems x
 let label (c : context) x =
   try VarMap.find x.it c.labels
   with Not_found -> error x.at ("unknown label " ^ x.it)
@@ -111,6 +116,8 @@ let bind_local (c : context) x = bind "local" c.locals x
 let bind_global (c : context) x = bind "global" c.globals x
 let bind_table (c : context) x = bind "table" c.tables x
 let bind_memory (c : context) x = bind "memory" c.memories x
+let bind_data (c : context) x = bind "data segment" c.data x
+let bind_elem (c : context) x = bind "elem segment" c.elems x
 let bind_label (c : context) x =
   {c with labels = VarMap.add x.it 0l (VarMap.map (Int32.add 1l) c.labels)}
 
@@ -130,6 +137,8 @@ let anon_locals (c : context) ts =
 let anon_global (c : context) = anon "global" c.globals 1l
 let anon_table (c : context) = anon "table" c.tables 1l
 let anon_memory (c : context) = anon "memory" c.memories 1l
+let anon_data (c : context) = anon "data segment" c.data 1l
+let anon_elem (c : context) = anon "elem segment" c.elems 1l
 let anon_label (c : context) =
   {c with labels = VarMap.map (Int32.add 1l) c.labels}
 
@@ -152,8 +161,11 @@ let inline_type_explicit (c : context) x ft at =
 %token LOAD STORE OFFSET_EQ_NAT ALIGN_EQ_NAT
 %token CONST UNARY BINARY TEST COMPARE CONVERT
 %token UNREACHABLE MEMORY_SIZE MEMORY_GROW
+%token MEMORY_INIT DATA_DROP MEMORY_COPY MEMORY_FILL
+%token TABLE_INIT ELEM_DROP TABLE_COPY
 %token FUNC START TYPE PARAM RESULT LOCAL GLOBAL
 %token TABLE ELEM MEMORY DATA OFFSET IMPORT EXPORT TABLE
+%token PASSIVE
 %token MODULE BIN QUOTE
 %token SCRIPT REGISTER INVOKE GET
 %token ASSERT_MALFORMED ASSERT_INVALID ASSERT_SOFT_INVALID ASSERT_UNLINKABLE
@@ -325,6 +337,13 @@ plain_instr :
   | UNARY { fun c -> $1 }
   | BINARY { fun c -> $1 }
   | CONVERT { fun c -> $1 }
+  | MEMORY_INIT var { fun c -> memory_init ($2 c data) }
+  | DATA_DROP var { fun c -> data_drop ($2 c data) }
+  | MEMORY_COPY { fun c -> memory_copy }
+  | MEMORY_FILL { fun c -> memory_fill }
+  | TABLE_INIT var { fun c -> table_init ($2 c elem) }
+  | ELEM_DROP var { fun c -> elem_drop ($2 c elem) }
+  | TABLE_COPY { fun c -> table_copy }
 
 
 call_instr :
@@ -550,12 +569,25 @@ offset :
   | expr { let at = at () in fun c -> $1 c @@ at }  /* Sugar */
 
 elem :
+  | LPAR ELEM bind_var_opt PASSIVE var_list RPAR
+    { let at = at () in
+      fun c -> ignore ($3 c anon_elem bind_elem @@ at);
+      fun () -> {sdesc = Passive; init = $5 c func} @@ at }
+  | LPAR ELEM bind_var var offset var_list RPAR
+    { let at = at () in
+      fun c -> ignore ((bind_elem c $3) @@ at);
+      fun () -> {sdesc = Active {index = $4 c table; offset = $5 c};
+                 init = $6 c func} @@ at }
   | LPAR ELEM var offset var_list RPAR
     { let at = at () in
-      fun c -> {index = $3 c table; offset = $4 c; init = $5 c func} @@ at }
-  | LPAR ELEM offset var_list RPAR  /* Sugar */
+      fun c -> ignore (anon_elem c @@ at);
+      fun () -> {sdesc = Active {index = $3 c table; offset = $4 c};
+                 init = $5 c func} @@ at }
+  | LPAR ELEM offset var_list RPAR /* Sugar */
     { let at = at () in
-      fun c -> {index = 0l @@ at; offset = $3 c; init = $4 c func} @@ at }
+      fun c -> ignore (anon_elem c @@ at);
+      fun () -> {sdesc = Active {index = 0l @@ at; offset = $3 c};
+                 init = $4 c func} @@ at }
 
 table :
   | LPAR TABLE bind_var_opt table_fields RPAR
@@ -577,17 +609,32 @@ table_fields :
   | elem_type LPAR ELEM var_list RPAR  /* Sugar */
     { fun c x at ->
       let init = $4 c func in let size = Int32.of_int (List.length init) in
+      let sdesc =
+        Active {index = x; offset = [i32_const (0l @@ at) @@ at] @@ at} in
       [{ttype = TableType ({min = size; max = Some size}, $1)} @@ at],
-      [{index = x; offset = [i32_const (0l @@ at) @@ at] @@ at; init} @@ at],
+      [{sdesc; init} @@ at],
       [], [] }
 
 data :
-  | LPAR DATA var offset string_list RPAR
+  | LPAR DATA bind_var_opt PASSIVE string_list RPAR
     { let at = at () in
-      fun c -> {index = $3 c memory; offset = $4 c; init = $5} @@ at }
-  | LPAR DATA offset string_list RPAR  /* Sugar */
-    { let at = at () in
-      fun c -> {index = 0l @@ at; offset = $3 c; init = $4} @@ at }
+      fun c -> ignore ($3 c anon_data bind_data @@ at);
+      fun () -> {sdesc = Passive; init = $5} @@ at }
+ | LPAR DATA bind_var var offset string_list RPAR
+   { let at = at () in
+     fun c -> ignore ((bind_data c $3) @@ at);
+     fun () -> {sdesc = Active {index = $4 c memory;
+                offset = $5 c}; init = $6} @@ at }
+ | LPAR DATA var offset string_list RPAR
+   { let at = at () in
+     fun c -> ignore (anon_data c @@ at);
+     fun () -> {sdesc = Active {index = $3 c memory;
+                offset = $4 c}; init = $5} @@ at }
+ | LPAR DATA offset string_list RPAR /* Sugar */
+   { let at = at () in
+     fun c -> ignore (anon_data c @@ at);
+     fun () -> {sdesc = Active {index = 0l @@ at;
+                offset = $3 c}; init = $4} @@ at }
 
 memory :
   | LPAR MEMORY bind_var_opt memory_fields RPAR
@@ -609,9 +656,10 @@ memory_fields :
   | LPAR DATA string_list RPAR  /* Sugar */
     { fun c x at ->
       let size = Int32.(div (add (of_int (String.length $3)) 65535l) 65536l) in
+      let sdesc =
+        Active {index = x; offset = [i32_const (0l @@ at) @@ at] @@ at} in
       [{mtype = MemoryType {min = size; max = Some size}} @@ at],
-      [{index = x;
-        offset = [i32_const (0l @@ at) @@ at] @@ at; init = $3} @@ at],
+      [{sdesc; init = $3} @@ at],
       [], [] }
 
 global :
@@ -730,13 +778,13 @@ module_fields1 :
       { m with funcs = funcs @ m.funcs;
         imports = ims @ m.imports; exports = exs @ m.exports } }
   | elem module_fields
-    { fun c -> let mf = $2 c in
-      fun () -> let m = mf () in
-      {m with elems = $1 c :: m.elems} }
+    { fun c -> let ef = $1 c in let mf = $2 c in
+      fun () -> let elems = ef () in let m = mf () in
+      {m with elems = elems :: m.elems} }
   | data module_fields
-    { fun c -> let mf = $2 c in
-      fun () -> let m = mf () in
-      {m with data = $1 c :: m.data} }
+    { fun c -> let df = $1 c in let mf = $2 c in
+      fun () -> let data = df () in let m = mf () in
+      {m with data = data :: m.data} }
   | start module_fields
     { fun c -> let mf = $2 c in
       fun () -> let m = mf () in let x = $1 c in
diff --git a/interpreter/valid/valid.ml b/interpreter/valid/valid.ml
index d3d8a4155d..0f3a00b9b9 100644
--- a/interpreter/valid/valid.ml
+++ b/interpreter/valid/valid.ml
@@ -21,6 +21,8 @@ type context =
   tables : table_type list;
   memories : memory_type list;
   globals : global_type list;
+  data : segment_type list;
+  elems : segment_type list;
   locals : value_type list;
   results : value_type list;
   labels : stack_type list;
@@ -28,7 +30,8 @@ type context =
 
 let empty_context =
   { types = []; funcs = []; tables = []; memories = [];
-    globals = []; locals = []; results = []; labels = [] }
+    globals = []; data = []; elems = [];
+    locals = []; results = []; labels = [] }
 
 let lookup category list x =
   try Lib.List32.nth list x.it with Failure _ ->
@@ -39,6 +42,8 @@ let func (c : context) x = lookup "function" c.funcs x
 let table (c : context) x = lookup "table" c.tables x
 let memory (c : context) x = lookup "memory" c.memories x
 let global (c : context) x = lookup "global" c.globals x
+let data (c : context) x = lookup "data segment" c.data x
+let elem (c : context) x = lookup "elem segment" c.elems x
 let local (c : context) x = lookup "local" c.locals x
 let label (c : context) x = lookup "label" c.labels x
 
@@ -288,6 +293,38 @@ let rec check_instr (c : context) (e : instr) (s : infer_stack_type) : op_type =
     let t1, t2 = type_cvtop e.at cvtop in
     [t1] --> [t2]
 
+  | MemoryInit x ->
+    ignore (memory c (0l @@ e.at));
+    ignore (data c x);
+    [I32Type; I32Type; I32Type] --> []
+
+  | DataDrop x ->
+    ignore (memory c (0l @@ e.at));
+    ignore (data c x);
+    [] --> []
+
+  | MemoryCopy ->
+    ignore (memory c (0l @@ e.at));
+    [I32Type; I32Type; I32Type] --> []
+
+  | MemoryFill ->
+    ignore (memory c (0l @@ e.at));
+    [I32Type; I32Type; I32Type] --> []
+
+  | TableInit x ->
+    ignore (table c (0l @@ e.at));
+    ignore (elem c x);
+    [I32Type; I32Type; I32Type] --> []
+
+  | ElemDrop x ->
+    ignore (table c (0l @@ e.at));
+    ignore (elem c x);
+    [] --> []
+
+  | TableCopy ->
+    ignore (table c (0l @@ e.at));
+    [I32Type; I32Type; I32Type] --> []
+
 and check_seq (c : context) (es : instr list) : infer_stack_type =
   match es with
   | [] ->
@@ -391,15 +428,21 @@ let check_memory (c : context) (mem : memory) =
   check_memory_type mtype mem.at
 
 let check_elem (c : context) (seg : table_segment) =
-  let {index; offset; init} = seg.it in
-  check_const c offset I32Type;
-  ignore (table c index);
-  ignore (List.map (func c) init)
+  let {sdesc; init} = seg.it in
+  ignore (List.map (func c) init);
+  match sdesc with
+  | Active {index; offset} ->
+    check_const c offset I32Type;
+    ignore (table c index)
+  | Passive -> ()
 
 let check_data (c : context) (seg : memory_segment) =
-  let {index; offset; init} = seg.it in
-  check_const c offset I32Type;
-  ignore (memory c index)
+  let {sdesc; init} = seg.it in
+  match sdesc with
+  | Active {index; offset} ->
+    check_const c offset I32Type;
+    ignore (memory c index)
+  | Passive -> ()
 
 let check_global (c : context) (glob : global) =
   let {gtype; value} = glob.it in
@@ -463,6 +506,8 @@ let check_module (m : module_) =
       funcs = c0.funcs @ List.map (fun f -> type_ c0 f.it.ftype) funcs;
       tables = c0.tables @ List.map (fun tab -> tab.it.ttype) tables;
       memories = c0.memories @ List.map (fun mem -> mem.it.mtype) memories;
+      elems = List.map (fun elem -> Seg) elems;
+      data = List.map (fun data -> Seg) data;
     }
   in
   let c =

From 1e03671b9b4c87d6782daec5d52bf5c8f1000b65 Mon Sep 17 00:00:00 2001
From: Andreas Rossberg 
Date: Thu, 7 Feb 2019 17:29:07 +0100
Subject: [PATCH 056/199] [interpreter] Flatten segment AST (#58)

---
 interpreter/binary/decode.ml    | 11 +++---
 interpreter/binary/encode.ml    |  9 +++--
 interpreter/exec/eval.ml        | 14 ++++----
 interpreter/syntax/ast.ml       | 10 ++----
 interpreter/syntax/operators.ml |  5 ++-
 interpreter/syntax/types.ml     |  2 +-
 interpreter/text/arrange.ml     |  7 ++--
 interpreter/text/parser.mly     | 61 +++++++++++++++------------------
 interpreter/valid/valid.ml      | 27 +++++++--------
 9 files changed, 63 insertions(+), 83 deletions(-)

diff --git a/interpreter/binary/decode.ml b/interpreter/binary/decode.ml
index 631f7d14be..6e8a2fd3bb 100644
--- a/interpreter/binary/decode.ml
+++ b/interpreter/binary/decode.ml
@@ -611,20 +611,17 @@ let segment dat s =
   | 0l ->
     let index = Source.(0l @@ Source.no_region) in
     let offset = const s in
-    let sdesc = Active {index; offset} in
     let init = dat s in
-    {sdesc; init}
+    Active {index; offset; init}
   | 1l ->
-    let sdesc = Passive in
     let init = dat s in
-    {sdesc; init}
+    Passive init
   | 2l ->
     let index = at var s in
     let offset = const s in
-    let sdesc = Active {index; offset} in
     let init = dat s in
-    {sdesc; init}
-  | _ -> error s (pos s - 1) "invalid segment flags"
+    Active {index; offset; init}
+  | _ -> error s (pos s - 1) "invalid segment kind"
 
 let table_segment s =
   segment (vec (at var)) s
diff --git a/interpreter/binary/encode.ml b/interpreter/binary/encode.ml
index 0dd29afe4c..a24b48e345 100644
--- a/interpreter/binary/encode.ml
+++ b/interpreter/binary/encode.ml
@@ -478,9 +478,8 @@ let encode m =
 
     (* Element section *)
     let segment dat seg =
-      let {sdesc; init} = seg.it in
-      match sdesc with
-      | Active {index; offset} ->
+      match seg.it with
+      | Active {index; offset; init} ->
         if index.it = 0l then
           u8 0x00
         else begin
@@ -488,8 +487,8 @@ let encode m =
         end;
         const offset;
         dat init
-      | Passive ->
-          u8 0x01; dat init
+      | Passive init ->
+        u8 0x01; dat init
 
     let table_segment seg =
       segment (vec var) seg
diff --git a/interpreter/exec/eval.ml b/interpreter/exec/eval.ml
index a4646983aa..4c93ea734c 100644
--- a/interpreter/exec/eval.ml
+++ b/interpreter/exec/eval.ml
@@ -388,9 +388,8 @@ let init_func (inst : module_inst) (func : func_inst) =
   | _ -> assert false
 
 let init_table (inst : module_inst) (seg : table_segment) =
-  let {sdesc; init} = seg.it in
-  match sdesc with
-  | Active {index; offset = const} ->
+  match seg.it with
+  | Active {index; offset = const; init} ->
     let tab = table inst index in
     let offset = i32 (eval_const inst const) const.at in
     let end_ = Int32.(add offset (of_int (List.length init))) in
@@ -399,12 +398,11 @@ let init_table (inst : module_inst) (seg : table_segment) =
       Link.error seg.at "elements segment does not fit table";
     fun () ->
       Table.blit tab offset (List.map (fun x -> FuncElem (func inst x)) init)
-  | Passive -> fun () -> ()
+  | Passive init -> fun () -> ()
 
 let init_memory (inst : module_inst) (seg : memory_segment) =
-  let {sdesc; init} = seg.it in
-  match sdesc with
-  | Active {index; offset = const} ->
+  match seg.it with
+  | Active {index; offset = const; init} ->
     let mem = memory inst index in
     let offset' = i32 (eval_const inst const) const.at in
     let offset = I64_convert.extend_u_i32 offset' in
@@ -413,7 +411,7 @@ let init_memory (inst : module_inst) (seg : memory_segment) =
     if I64.lt_u bound end_ || I64.lt_u end_ offset then
       Link.error seg.at "data segment does not fit memory";
     fun () -> Memory.store_bytes mem offset init
-  | Passive -> fun () -> ()
+  | Passive init -> fun () -> ()
 
 
 let add_import (m : module_) (ext : extern) (im : import) (inst : module_inst)
diff --git a/interpreter/syntax/ast.ml b/interpreter/syntax/ast.ml
index 501e5e36aa..cad9b34638 100644
--- a/interpreter/syntax/ast.ml
+++ b/interpreter/syntax/ast.ml
@@ -110,10 +110,6 @@ and instr' =
 
 type const = instr list Source.phrase
 
-type segment_desc =
-  | Active of {index : var; offset : const}
-  | Passive
-
 type global = global' Source.phrase
 and global' =
 {
@@ -146,10 +142,8 @@ and memory' =
 
 type 'data segment = 'data segment' Source.phrase
 and 'data segment' =
-{
-  sdesc : segment_desc;
-  init : 'data;
-}
+  | Active of {index : var; offset : const; init : 'data}
+  | Passive of 'data
 
 type table_segment = var list segment
 type memory_segment = string segment
diff --git a/interpreter/syntax/operators.ml b/interpreter/syntax/operators.ml
index 590e80cb24..8cec587ef4 100644
--- a/interpreter/syntax/operators.ml
+++ b/interpreter/syntax/operators.ml
@@ -201,11 +201,10 @@ let f64_reinterpret_i64 = Convert (F64 F64Op.ReinterpretInt)
 
 let memory_size = MemorySize
 let memory_grow = MemoryGrow
-
 let memory_init x = MemoryInit x
-let data_drop x = DataDrop x
 let memory_copy = MemoryCopy
 let memory_fill = MemoryFill
 let table_init x = TableInit x
-let elem_drop x = ElemDrop x
 let table_copy = TableCopy
+let data_drop x = DataDrop x
+let elem_drop x = ElemDrop x
diff --git a/interpreter/syntax/types.ml b/interpreter/syntax/types.ml
index 7bea4aa699..6e5f1d6ac9 100644
--- a/interpreter/syntax/types.ml
+++ b/interpreter/syntax/types.ml
@@ -10,12 +10,12 @@ type mutability = Immutable | Mutable
 type table_type = TableType of Int32.t limits * elem_type
 type memory_type = MemoryType of Int32.t limits
 type global_type = GlobalType of value_type * mutability
+type segment_type = SegmentType
 type extern_type =
   | ExternFuncType of func_type
   | ExternTableType of table_type
   | ExternMemoryType of memory_type
   | ExternGlobalType of global_type
-type segment_type = Seg
 
 
 (* Attributes *)
diff --git a/interpreter/text/arrange.ml b/interpreter/text/arrange.ml
index dd19840d13..5d508acbc2 100644
--- a/interpreter/text/arrange.ml
+++ b/interpreter/text/arrange.ml
@@ -297,11 +297,10 @@ let memory off i mem =
   Node ("memory $" ^ nat (off + i) ^ " " ^ limits nat32 lim, [])
 
 let segment head dat seg =
-  let {sdesc; init} = seg.it in
-  match sdesc with
-  | Active {index; offset} ->
+  match seg.it with
+  | Active {index; offset; init} ->
     Node (head, atom var index :: Node ("offset", const offset) :: dat init)
-  | Passive -> Node (head, dat init)
+  | Passive init -> Node (head, dat init)
 
 let elems seg =
   segment "elem" (list (atom var)) seg
diff --git a/interpreter/text/parser.mly b/interpreter/text/parser.mly
index 2041a811ad..342513e4d5 100644
--- a/interpreter/text/parser.mly
+++ b/interpreter/text/parser.mly
@@ -87,8 +87,8 @@ let local (c : context) x = lookup "local" c.locals x
 let global (c : context) x = lookup "global" c.globals x
 let table (c : context) x = lookup "table" c.tables x
 let memory (c : context) x = lookup "memory" c.memories x
-let data (c : context) x = lookup "data segment" c.data x
 let elem (c : context) x = lookup "elem segment" c.elems x
+let data (c : context) x = lookup "data segment" c.data x
 let label (c : context) x =
   try VarMap.find x.it c.labels
   with Not_found -> error x.at ("unknown label " ^ x.it)
@@ -116,8 +116,8 @@ let bind_local (c : context) x = bind "local" c.locals x
 let bind_global (c : context) x = bind "global" c.globals x
 let bind_table (c : context) x = bind "table" c.tables x
 let bind_memory (c : context) x = bind "memory" c.memories x
-let bind_data (c : context) x = bind "data segment" c.data x
 let bind_elem (c : context) x = bind "elem segment" c.elems x
+let bind_data (c : context) x = bind "data segment" c.data x
 let bind_label (c : context) x =
   {c with labels = VarMap.add x.it 0l (VarMap.map (Int32.add 1l) c.labels)}
 
@@ -137,8 +137,8 @@ let anon_locals (c : context) ts =
 let anon_global (c : context) = anon "global" c.globals 1l
 let anon_table (c : context) = anon "table" c.tables 1l
 let anon_memory (c : context) = anon "memory" c.memories 1l
-let anon_data (c : context) = anon "data segment" c.data 1l
 let anon_elem (c : context) = anon "elem segment" c.elems 1l
+let anon_data (c : context) = anon "data segment" c.data 1l
 let anon_label (c : context) =
   {c with labels = VarMap.map (Int32.add 1l) c.labels}
 
@@ -571,23 +571,23 @@ offset :
 elem :
   | LPAR ELEM bind_var_opt PASSIVE var_list RPAR
     { let at = at () in
-      fun c -> ignore ($3 c anon_elem bind_elem @@ at);
-      fun () -> {sdesc = Passive; init = $5 c func} @@ at }
+      fun c -> ignore ($3 c anon_elem bind_elem);
+      fun () -> Passive ($5 c func) @@ at }
   | LPAR ELEM bind_var var offset var_list RPAR
     { let at = at () in
-      fun c -> ignore ((bind_elem c $3) @@ at);
-      fun () -> {sdesc = Active {index = $4 c table; offset = $5 c};
-                 init = $6 c func} @@ at }
+      fun c -> ignore (bind_elem c $3);
+      fun () ->
+      Active {index = $4 c table; offset = $5 c; init = $6 c func} @@ at }
   | LPAR ELEM var offset var_list RPAR
     { let at = at () in
-      fun c -> ignore (anon_elem c @@ at);
-      fun () -> {sdesc = Active {index = $3 c table; offset = $4 c};
-                 init = $5 c func} @@ at }
-  | LPAR ELEM offset var_list RPAR /* Sugar */
+      fun c -> ignore (anon_elem c);
+      fun () ->
+      Active {index = $3 c table; offset = $4 c; init = $5 c func} @@ at }
+  | LPAR ELEM offset var_list RPAR  /* Sugar */
     { let at = at () in
-      fun c -> ignore (anon_elem c @@ at);
-      fun () -> {sdesc = Active {index = 0l @@ at; offset = $3 c};
-                 init = $4 c func} @@ at }
+      fun c -> ignore (anon_elem c);
+      fun () ->
+      Active {index = 0l @@ at; offset = $3 c; init = $4 c func} @@ at }
 
 table :
   | LPAR TABLE bind_var_opt table_fields RPAR
@@ -608,33 +608,29 @@ table_fields :
       tabs, elems, ims, $1 (TableExport x) c :: exs }
   | elem_type LPAR ELEM var_list RPAR  /* Sugar */
     { fun c x at ->
+      let offset = [i32_const (0l @@ at) @@ at] @@ at in
       let init = $4 c func in let size = Int32.of_int (List.length init) in
-      let sdesc =
-        Active {index = x; offset = [i32_const (0l @@ at) @@ at] @@ at} in
       [{ttype = TableType ({min = size; max = Some size}, $1)} @@ at],
-      [{sdesc; init} @@ at],
+      [Active {index = x; offset; init} @@ at],
       [], [] }
 
 data :
   | LPAR DATA bind_var_opt PASSIVE string_list RPAR
     { let at = at () in
-      fun c -> ignore ($3 c anon_data bind_data @@ at);
-      fun () -> {sdesc = Passive; init = $5} @@ at }
+      fun c -> ignore ($3 c anon_data bind_data);
+      fun () -> Passive $5 @@ at }
  | LPAR DATA bind_var var offset string_list RPAR
    { let at = at () in
-     fun c -> ignore ((bind_data c $3) @@ at);
-     fun () -> {sdesc = Active {index = $4 c memory;
-                offset = $5 c}; init = $6} @@ at }
+     fun c -> ignore (bind_data c $3);
+     fun () -> Active {index = $4 c memory; offset = $5 c; init = $6} @@ at }
  | LPAR DATA var offset string_list RPAR
    { let at = at () in
-     fun c -> ignore (anon_data c @@ at);
-     fun () -> {sdesc = Active {index = $3 c memory;
-                offset = $4 c}; init = $5} @@ at }
- | LPAR DATA offset string_list RPAR /* Sugar */
+     fun c -> ignore (anon_data c);
+     fun () -> Active {index = $3 c memory; offset = $4 c; init = $5} @@ at }
+ | LPAR DATA offset string_list RPAR  /* Sugar */
    { let at = at () in
-     fun c -> ignore (anon_data c @@ at);
-     fun () -> {sdesc = Active {index = 0l @@ at;
-                offset = $3 c}; init = $4} @@ at }
+     fun c -> ignore (anon_data c);
+     fun () -> Active {index = 0l @@ at; offset = $3 c; init = $4} @@ at }
 
 memory :
   | LPAR MEMORY bind_var_opt memory_fields RPAR
@@ -655,11 +651,10 @@ memory_fields :
       mems, data, ims, $1 (MemoryExport x) c :: exs }
   | LPAR DATA string_list RPAR  /* Sugar */
     { fun c x at ->
+      let offset = [i32_const (0l @@ at) @@ at] @@ at in
       let size = Int32.(div (add (of_int (String.length $3)) 65535l) 65536l) in
-      let sdesc =
-        Active {index = x; offset = [i32_const (0l @@ at) @@ at] @@ at} in
       [{mtype = MemoryType {min = size; max = Some size}} @@ at],
-      [{sdesc; init = $3} @@ at],
+      [Active {index = x; offset; init = $3} @@ at],
       [], [] }
 
 global :
diff --git a/interpreter/valid/valid.ml b/interpreter/valid/valid.ml
index 0f3a00b9b9..b6f30d08de 100644
--- a/interpreter/valid/valid.ml
+++ b/interpreter/valid/valid.ml
@@ -428,21 +428,20 @@ let check_memory (c : context) (mem : memory) =
   check_memory_type mtype mem.at
 
 let check_elem (c : context) (seg : table_segment) =
-  let {sdesc; init} = seg.it in
-  ignore (List.map (func c) init);
-  match sdesc with
-  | Active {index; offset} ->
+  match seg.it with
+  | Active {index; offset; init} ->
+    ignore (table c index);
     check_const c offset I32Type;
-    ignore (table c index)
-  | Passive -> ()
+    ignore (List.map (func c) init)
+  | Passive init ->
+    ignore (List.map (func c) init)
 
 let check_data (c : context) (seg : memory_segment) =
-  let {sdesc; init} = seg.it in
-  match sdesc with
-  | Active {index; offset} ->
-    check_const c offset I32Type;
-    ignore (memory c index)
-  | Passive -> ()
+  match seg.it with
+  | Active {index; offset; init} ->
+    ignore (memory c index);
+    check_const c offset I32Type
+  | Passive init -> ()
 
 let check_global (c : context) (glob : global) =
   let {gtype; value} = glob.it in
@@ -506,8 +505,8 @@ let check_module (m : module_) =
       funcs = c0.funcs @ List.map (fun f -> type_ c0 f.it.ftype) funcs;
       tables = c0.tables @ List.map (fun tab -> tab.it.ttype) tables;
       memories = c0.memories @ List.map (fun mem -> mem.it.mtype) memories;
-      elems = List.map (fun elem -> Seg) elems;
-      data = List.map (fun data -> Seg) data;
+      elems = List.map (fun elem -> SegmentType) elems;
+      data = List.map (fun data -> SegmentType) data;
     }
   in
   let c =

From 564fc4045a1c3d2b3d4995641a2df1f52e5032af Mon Sep 17 00:00:00 2001
From: Andreas Rossberg 
Date: Tue, 12 Feb 2019 14:48:19 +0100
Subject: [PATCH 057/199] [proposal] Link to function reference proposal

---
 README.md                             | 2 +-
 proposals/reference-types/Overview.md | 9 ++-------
 2 files changed, 3 insertions(+), 8 deletions(-)

diff --git a/README.md b/README.md
index ec165c54eb..226bb1d847 100644
--- a/README.md
+++ b/README.md
@@ -1,4 +1,4 @@
-[![Build Status](https://travis-ci.org/WebAssembly/multi-value.svg?branch=master)](https://travis-ci.org/WebAssembly/reference-types)
+[![Build Status](https://travis-ci.org/WebAssembly/reference-types.svg?branch=master)](https://travis-ci.org/WebAssembly/reference-types)
 
 # Reference Types Proposal for WebAssembly
 
diff --git a/proposals/reference-types/Overview.md b/proposals/reference-types/Overview.md
index 95e5bd5671..a12571608b 100644
--- a/proposals/reference-types/Overview.md
+++ b/proposals/reference-types/Overview.md
@@ -140,6 +140,8 @@ Questions:
 
 ### Typed function references
 
+See the [typed function references proposal](https://github.com/WebAssembly/function-references/blob/master/proposals/function-references/Overview.md)
+
 Motivation:
 
 * Allow function pointers to be expressed directly without going through table and dynamic type check.
@@ -167,13 +169,6 @@ Additions:
   - optional for backwards compatibility, defaults to `null`
 
 
-Question:
-
-* General function have no reasonable default, do we need scoped variables like `let`?
-* Should there be a down cast instruction?
-* Should there be depth subtyping for function types?
-
-
 ### Type Import/Export
 
 Motivation:

From 5e3df2889a555881d9baf7717ac93cfd94dccaeb Mon Sep 17 00:00:00 2001
From: Ben Smith 
Date: Thu, 21 Feb 2019 10:38:24 -0800
Subject: [PATCH 058/199] [Interpreter] Decode/encode the data count section
 (#59)

---
 interpreter/binary/decode.ml | 12 ++++++++++++
 interpreter/binary/encode.ml |  6 ++++++
 test/core/custom.wast        | 10 ++++++++++
 3 files changed, 28 insertions(+)

diff --git a/interpreter/binary/decode.ml b/interpreter/binary/decode.ml
index 6e8a2fd3bb..54fae2449b 100644
--- a/interpreter/binary/decode.ml
+++ b/interpreter/binary/decode.ml
@@ -485,6 +485,7 @@ let id s =
     | 9 -> `ElemSection
     | 10 -> `CodeSection
     | 11 -> `DataSection
+    | 12 -> `DataCountSection
     | _ -> error s (pos s) "invalid section id"
     ) bo
 
@@ -639,6 +640,12 @@ let data_section s =
   section `DataSection (vec (at memory_segment)) [] s
 
 
+(* DataCount section *)
+
+let data_count_section s =
+  section `DataCountSection (opt vu32 true) None s
+
+
 (* Custom section *)
 
 let custom size s =
@@ -679,6 +686,8 @@ let module_ s =
   iterate custom_section s;
   let elems = elem_section s in
   iterate custom_section s;
+  let data_count = data_count_section s in
+  iterate custom_section s;
   let func_bodies = code_section s in
   iterate custom_section s;
   let data = data_section s in
@@ -686,6 +695,9 @@ let module_ s =
   require (pos s = len s) s (len s) "junk after last section";
   require (List.length func_types = List.length func_bodies)
     s (len s) "function and code section have inconsistent lengths";
+  require
+    (data_count = None || data_count = Some (Int32.of_int (List.length data)))
+    s (len s) "data count and data section have inconsistent lengths";
   let funcs =
     List.map2 Source.(fun t f -> {f.it with ftype = t} @@ f.at)
       func_types func_bodies
diff --git a/interpreter/binary/encode.ml b/interpreter/binary/encode.ml
index a24b48e345..83dce15737 100644
--- a/interpreter/binary/encode.ml
+++ b/interpreter/binary/encode.ml
@@ -503,6 +503,11 @@ let encode m =
     let data_section data =
       section 11 (vec memory_segment) data (data <> [])
 
+    (* DataCount section *)
+
+    let data_count_section data =
+      section 12 len (List.length data) (data <> [])
+
     (* Module *)
 
     let module_ m =
@@ -517,6 +522,7 @@ let encode m =
       export_section m.it.exports;
       start_section m.it.start;
       elem_section m.it.elems;
+      data_count_section m.it.data;
       code_section m.it.funcs;
       data_section m.it.data
   end
diff --git a/test/core/custom.wast b/test/core/custom.wast
index fb04f2f6b9..0310f76b54 100644
--- a/test/core/custom.wast
+++ b/test/core/custom.wast
@@ -118,3 +118,13 @@
   )
   "length out of bounds"
 )
+
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\05\03\01\00\01"                         ;; memory section
+    "\0c\01\02"                               ;; data count section (2 segments)
+    "\0b\06\01\00\41\00\0b\00"                ;; data section (1 segment)
+  )
+  "data count and data section have inconsistent lengths"
+)

From d91b74e9e28524a4293c1b1e8cb92f412a5c3c66 Mon Sep 17 00:00:00 2001
From: Ben Smith 
Date: Thu, 21 Feb 2019 11:10:48 -0800
Subject: [PATCH 059/199] [Interpreter] Implement memory.copy, memory.fill
 (#60)

---
 interpreter/exec/eval.ml       | 13 +++++
 interpreter/runtime/memory.ml  | 27 ++++++++++
 interpreter/runtime/memory.mli |  4 ++
 test/core/bulk.wast            | 97 ++++++++++++++++++++++++++++++++++
 4 files changed, 141 insertions(+)
 create mode 100644 test/core/bulk.wast

diff --git a/interpreter/exec/eval.ml b/interpreter/exec/eval.ml
index 4c93ea734c..908af8c8fe 100644
--- a/interpreter/exec/eval.ml
+++ b/interpreter/exec/eval.ml
@@ -226,6 +226,19 @@ let rec step (c : config) : config =
           with Memory.SizeOverflow | Memory.SizeLimit | Memory.OutOfMemory -> -1l
         in I32 result :: vs', []
 
+      | MemoryFill, I32 n :: I32 b :: I32 i :: vs' ->
+        let mem = memory frame.inst (0l @@ e.at) in
+        let addr = I64_convert.extend_u_i32 i in
+        (try Memory.fill mem addr (Int32.to_int b) n; vs', []
+        with exn -> vs', [Trapping (memory_error e.at exn) @@ e.at])
+
+      | MemoryCopy, I32 n :: I32 s :: I32 d :: vs' ->
+        let mem = memory frame.inst (0l @@ e.at) in
+        let dst = I64_convert.extend_u_i32 d in
+        let src = I64_convert.extend_u_i32 s in
+        (try Memory.copy mem dst src n; vs', []
+        with exn -> vs', [Trapping (memory_error e.at exn) @@ e.at])
+
       | Const v, vs ->
         v.it :: vs, []
 
diff --git a/interpreter/runtime/memory.ml b/interpreter/runtime/memory.ml
index d1f2bce982..bb2fead049 100644
--- a/interpreter/runtime/memory.ml
+++ b/interpreter/runtime/memory.ml
@@ -6,6 +6,7 @@ open Values
 type size = int32  (* number of pages *)
 type address = int64
 type offset = int32
+type count = int32
 
 type pack_size = Pack8 | Pack16 | Pack32
 type extension = SX | ZX
@@ -143,3 +144,29 @@ let store_packed sz mem a o v =
     | I64 x -> x
     | _ -> raise Type
   in storen mem a o n x
+
+let check_bounds mem a = if I64.ge_u a (bound mem) then raise Bounds
+
+let fill mem a v n =
+  let rec loop a n =
+    if n > 0l then begin
+      store_byte mem a v;
+      loop (Int64.add a 1L) (Int32.sub n 1l)
+    end
+  in check_bounds mem a; loop a n
+
+let copy mem d s n =
+  let n' = Int64.of_int32 n in
+  let overlap = I64.lt_s Int64.(abs (sub d s)) n' in
+  let rec loop d s n dx =
+    if n > 0l then begin
+      store_byte mem d (load_byte mem s);
+      loop (Int64.add d dx) (Int64.add s dx) (Int32.sub n 1l) dx
+    end
+  in
+  check_bounds mem d;
+  check_bounds mem s;
+  if overlap && s < d then
+    loop Int64.(add d (sub n' 1L)) Int64.(add s (sub n' 1L)) n (-1L)
+  else
+    loop d s n 1L
diff --git a/interpreter/runtime/memory.mli b/interpreter/runtime/memory.mli
index 2a2b8ae47a..6c25c5414b 100644
--- a/interpreter/runtime/memory.mli
+++ b/interpreter/runtime/memory.mli
@@ -7,6 +7,7 @@ type t = memory
 type size = int32  (* number of pages *)
 type address = int64
 type offset = int32
+type count = int32
 
 type pack_size = Pack8 | Pack16 | Pack32
 type extension = SX | ZX
@@ -42,3 +43,6 @@ val load_packed :
 val store_packed :
   pack_size -> memory -> address -> offset -> value -> unit
     (* raises Type, Bounds *)
+
+val fill : memory -> address -> int -> count -> unit (* raises Bounds *)
+val copy : memory -> address -> address -> count -> unit (* raises Bounds *)
diff --git a/test/core/bulk.wast b/test/core/bulk.wast
new file mode 100644
index 0000000000..f77ab71f0f
--- /dev/null
+++ b/test/core/bulk.wast
@@ -0,0 +1,97 @@
+(module
+  (memory 1)
+
+  (func (export "fill") (param i32 i32 i32)
+    (memory.fill
+      (get_local 0)
+      (get_local 1)
+      (get_local 2)))
+
+  (func (export "load8_u") (param i32) (result i32)
+    (i32.load8_u (get_local 0)))
+)
+
+;; Basic fill test.
+(invoke "fill" (i32.const 1) (i32.const 0xff) (i32.const 3))
+(assert_return (invoke "load8_u" (i32.const 0)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 1)) (i32.const 0xff))
+(assert_return (invoke "load8_u" (i32.const 2)) (i32.const 0xff))
+(assert_return (invoke "load8_u" (i32.const 3)) (i32.const 0xff))
+(assert_return (invoke "load8_u" (i32.const 4)) (i32.const 0))
+
+;; Fill value is stored as a byte.
+(invoke "fill" (i32.const 0) (i32.const 0xbbaa) (i32.const 2))
+(assert_return (invoke "load8_u" (i32.const 0)) (i32.const 0xaa))
+(assert_return (invoke "load8_u" (i32.const 1)) (i32.const 0xaa))
+
+;; Fill all of memory
+(invoke "fill" (i32.const 0) (i32.const 0) (i32.const 0x10000))
+
+;; Out-of-bounds writes trap, but all previous writes succeed.
+(assert_trap (invoke "fill" (i32.const 0xff00) (i32.const 1) (i32.const 0x101))
+    "out of bounds memory access")
+(assert_return (invoke "load8_u" (i32.const 0xff00)) (i32.const 1))
+(assert_return (invoke "load8_u" (i32.const 0xffff)) (i32.const 1))
+
+;; Fail on out-of-bounds even if filling 0 bytes.
+(assert_trap (invoke "fill" (i32.const 0x10000) (i32.const 0) (i32.const 0))
+    "out of bounds memory access")
+
+
+(module
+  (memory (data "\aa\bb\cc\dd"))
+
+  (func (export "copy") (param i32 i32 i32)
+    (memory.copy
+      (get_local 0)
+      (get_local 1)
+      (get_local 2)))
+
+  (func (export "load8_u") (param i32) (result i32)
+    (i32.load8_u (get_local 0)))
+)
+
+;; Non-overlapping copy.
+(invoke "copy" (i32.const 10) (i32.const 0) (i32.const 4))
+
+(assert_return (invoke "load8_u" (i32.const 9)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 10)) (i32.const 0xaa))
+(assert_return (invoke "load8_u" (i32.const 11)) (i32.const 0xbb))
+(assert_return (invoke "load8_u" (i32.const 12)) (i32.const 0xcc))
+(assert_return (invoke "load8_u" (i32.const 13)) (i32.const 0xdd))
+(assert_return (invoke "load8_u" (i32.const 14)) (i32.const 0))
+
+;; Overlap, source > dest
+(invoke "copy" (i32.const 8) (i32.const 10) (i32.const 4))
+(assert_return (invoke "load8_u" (i32.const 8)) (i32.const 0xaa))
+(assert_return (invoke "load8_u" (i32.const 9)) (i32.const 0xbb))
+(assert_return (invoke "load8_u" (i32.const 10)) (i32.const 0xcc))
+(assert_return (invoke "load8_u" (i32.const 11)) (i32.const 0xdd))
+(assert_return (invoke "load8_u" (i32.const 12)) (i32.const 0xcc))
+(assert_return (invoke "load8_u" (i32.const 13)) (i32.const 0xdd))
+
+;; Overlap, source < dest
+(invoke "copy" (i32.const 10) (i32.const 7) (i32.const 6))
+(assert_return (invoke "load8_u" (i32.const 10)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 11)) (i32.const 0xaa))
+(assert_return (invoke "load8_u" (i32.const 12)) (i32.const 0xbb))
+(assert_return (invoke "load8_u" (i32.const 13)) (i32.const 0xcc))
+(assert_return (invoke "load8_u" (i32.const 14)) (i32.const 0xdd))
+(assert_return (invoke "load8_u" (i32.const 15)) (i32.const 0xcc))
+(assert_return (invoke "load8_u" (i32.const 16)) (i32.const 0))
+
+;; Copy ending at memory limit is ok.
+(invoke "copy" (i32.const 0xff00) (i32.const 0) (i32.const 0x100))
+(invoke "copy" (i32.const 0xfe00) (i32.const 0xff00) (i32.const 0x100))
+
+;; Out-of-bounds writes trap, but all previous writes succeed.
+(assert_trap (invoke "copy" (i32.const 0xfffe) (i32.const 0) (i32.const 3))
+    "out of bounds memory access")
+(assert_return (invoke "load8_u" (i32.const 0xfffe)) (i32.const 0xaa))
+(assert_return (invoke "load8_u" (i32.const 0xffff)) (i32.const 0xbb))
+
+;; Fail on out-of-bounds even if copying 0 bytes.
+(assert_trap (invoke "copy" (i32.const 0x10000) (i32.const 0) (i32.const 0))
+    "out of bounds memory access")
+(assert_trap (invoke "copy" (i32.const 0) (i32.const 0x10000) (i32.const 0))
+    "out of bounds memory access")

From 63986ffa736c9eaf5ddd069e753a422f331ecf27 Mon Sep 17 00:00:00 2001
From: Ben Smith 
Date: Thu, 21 Feb 2019 14:01:06 -0800
Subject: [PATCH 060/199] Move MemoryCopy and MemoryFill definitions

This uses the same as order as defined in syntax/ast.
---
 interpreter/exec/eval.ml | 26 +++++++++++++-------------
 1 file changed, 13 insertions(+), 13 deletions(-)

diff --git a/interpreter/exec/eval.ml b/interpreter/exec/eval.ml
index 2437b5f593..a317829206 100644
--- a/interpreter/exec/eval.ml
+++ b/interpreter/exec/eval.ml
@@ -226,19 +226,6 @@ let rec step (c : config) : config =
           with Memory.SizeOverflow | Memory.SizeLimit | Memory.OutOfMemory -> -1l
         in I32 result :: vs', []
 
-      | MemoryFill, I32 n :: I32 b :: I32 i :: vs' ->
-        let mem = memory frame.inst (0l @@ e.at) in
-        let addr = I64_convert.extend_i32_u i in
-        (try Memory.fill mem addr (Int32.to_int b) n; vs', []
-        with exn -> vs', [Trapping (memory_error e.at exn) @@ e.at])
-
-      | MemoryCopy, I32 n :: I32 s :: I32 d :: vs' ->
-        let mem = memory frame.inst (0l @@ e.at) in
-        let dst = I64_convert.extend_i32_u d in
-        let src = I64_convert.extend_i32_u s in
-        (try Memory.copy mem dst src n; vs', []
-        with exn -> vs', [Trapping (memory_error e.at exn) @@ e.at])
-
       | Const v, vs ->
         v.it :: vs, []
 
@@ -262,6 +249,19 @@ let rec step (c : config) : config =
         (try Eval_numeric.eval_cvtop cvtop v :: vs', []
         with exn -> vs', [Trapping (numeric_error e.at exn) @@ e.at])
 
+      | MemoryCopy, I32 n :: I32 s :: I32 d :: vs' ->
+        let mem = memory frame.inst (0l @@ e.at) in
+        let dst = I64_convert.extend_i32_u d in
+        let src = I64_convert.extend_i32_u s in
+        (try Memory.copy mem dst src n; vs', []
+        with exn -> vs', [Trapping (memory_error e.at exn) @@ e.at])
+
+      | MemoryFill, I32 n :: I32 b :: I32 i :: vs' ->
+        let mem = memory frame.inst (0l @@ e.at) in
+        let addr = I64_convert.extend_i32_u i in
+        (try Memory.fill mem addr (Int32.to_int b) n; vs', []
+        with exn -> vs', [Trapping (memory_error e.at exn) @@ e.at])
+
       | _ ->
         let s1 = string_of_values (List.rev vs) in
         let s2 = string_of_value_types (List.map type_of (List.rev vs)) in

From 1671a381b1e382e0a9fc74d09b53210ae7f86c54 Mon Sep 17 00:00:00 2001
From: Ben Smith 
Date: Fri, 22 Feb 2019 10:07:25 -0800
Subject: [PATCH 061/199] [Interpreter] Handle 0-byte copies properly. (#61)

Similar to the MVP, a 0-byte access at the end of the region is legal.
---
 interpreter/runtime/memory.ml | 14 +++++++-------
 test/core/bulk.wast           | 17 ++++++++++++-----
 2 files changed, 19 insertions(+), 12 deletions(-)

diff --git a/interpreter/runtime/memory.ml b/interpreter/runtime/memory.ml
index bb2fead049..3b7bd31b48 100644
--- a/interpreter/runtime/memory.ml
+++ b/interpreter/runtime/memory.ml
@@ -145,7 +145,7 @@ let store_packed sz mem a o v =
     | _ -> raise Type
   in storen mem a o n x
 
-let check_bounds mem a = if I64.ge_u a (bound mem) then raise Bounds
+let check_bounds mem a = if I64.gt_u a (bound mem) then raise Bounds
 
 let fill mem a v n =
   let rec loop a n =
@@ -153,7 +153,8 @@ let fill mem a v n =
       store_byte mem a v;
       loop (Int64.add a 1L) (Int32.sub n 1l)
     end
-  in check_bounds mem a; loop a n
+  in loop a n;
+  check_bounds mem Int64.(add a (of_int32 n))
 
 let copy mem d s n =
   let n' = Int64.of_int32 n in
@@ -163,10 +164,9 @@ let copy mem d s n =
       store_byte mem d (load_byte mem s);
       loop (Int64.add d dx) (Int64.add s dx) (Int32.sub n 1l) dx
     end
-  in
-  check_bounds mem d;
-  check_bounds mem s;
-  if overlap && s < d then
+  in (if overlap && s < d then
     loop Int64.(add d (sub n' 1L)) Int64.(add s (sub n' 1L)) n (-1L)
   else
-    loop d s n 1L
+    loop d s n 1L);
+  check_bounds mem (Int64.add d n');
+  check_bounds mem (Int64.add s n')
diff --git a/test/core/bulk.wast b/test/core/bulk.wast
index 7408c3e3d1..769d9d8dc0 100644
--- a/test/core/bulk.wast
+++ b/test/core/bulk.wast
@@ -33,8 +33,11 @@
 (assert_return (invoke "load8_u" (i32.const 0xff00)) (i32.const 1))
 (assert_return (invoke "load8_u" (i32.const 0xffff)) (i32.const 1))
 
-;; Fail on out-of-bounds even if filling 0 bytes.
-(assert_trap (invoke "fill" (i32.const 0x10000) (i32.const 0) (i32.const 0))
+;; Succeed when writing 0 bytes at the end of the region.
+(invoke "fill" (i32.const 0x10000) (i32.const 0) (i32.const 0))
+
+;; Fail on out-of-bounds when writing 0 bytes outside of memory.
+(assert_trap (invoke "fill" (i32.const 0x10001) (i32.const 0) (i32.const 0))
     "out of bounds memory access")
 
 
@@ -90,8 +93,12 @@
 (assert_return (invoke "load8_u" (i32.const 0xfffe)) (i32.const 0xaa))
 (assert_return (invoke "load8_u" (i32.const 0xffff)) (i32.const 0xbb))
 
-;; Fail on out-of-bounds even if copying 0 bytes.
-(assert_trap (invoke "copy" (i32.const 0x10000) (i32.const 0) (i32.const 0))
+;; Succeed when copying 0 bytes at the end of the region.
+(invoke "copy" (i32.const 0x10000) (i32.const 0) (i32.const 0))
+(invoke "copy" (i32.const 0) (i32.const 0x10000) (i32.const 0))
+
+;; Fail on out-of-bounds when copying 0 bytes outside of memory.
+(assert_trap (invoke "copy" (i32.const 0x10001) (i32.const 0) (i32.const 0))
     "out of bounds memory access")
-(assert_trap (invoke "copy" (i32.const 0) (i32.const 0x10000) (i32.const 0))
+(assert_trap (invoke "copy" (i32.const 0) (i32.const 0x10001) (i32.const 0))
     "out of bounds memory access")

From f8175604dddbd2e0d57d152455c12a24d626eaa1 Mon Sep 17 00:00:00 2001
From: Ben Smith 
Date: Fri, 22 Feb 2019 10:14:23 -0800
Subject: [PATCH 062/199] [Interpreter] Initialized segments persist after
 instantiation failure

This behavior is a breaking change from the v1 spec, but it is unlikely
that any programs depend on it.
---
 interpreter/exec/eval.ml       | 25 ++++++++-----------------
 interpreter/runtime/memory.ml  | 22 ++++++++++++++--------
 interpreter/runtime/memory.mli |  3 ++-
 interpreter/runtime/table.ml   |  9 +++++----
 interpreter/runtime/table.mli  |  3 ++-
 test/core/linking.wast         | 12 ++++++++----
 6 files changed, 39 insertions(+), 35 deletions(-)

diff --git a/interpreter/exec/eval.ml b/interpreter/exec/eval.ml
index a317829206..2a7e812436 100644
--- a/interpreter/exec/eval.ml
+++ b/interpreter/exec/eval.ml
@@ -405,13 +405,9 @@ let init_table (inst : module_inst) (seg : table_segment) =
   | Active {index; offset = const; init} ->
     let tab = table inst index in
     let offset = i32 (eval_const inst const) const.at in
-    let end_ = Int32.(add offset (of_int (List.length init))) in
-    let bound = Table.size tab in
-    if I32.lt_u bound end_ || I32.lt_u end_ offset then
-      Link.error seg.at "elements segment does not fit table";
-    fun () ->
-      Table.blit tab offset (List.map (fun x -> FuncElem (func inst x)) init)
-  | Passive init -> fun () -> ()
+    (try Table.init tab offset (List.map (fun x -> FuncElem (func inst x)) init)
+    with Table.Bounds -> Link.error seg.at "elements segment does not fit table")
+  | Passive init -> ()
 
 let init_memory (inst : module_inst) (seg : memory_segment) =
   match seg.it with
@@ -419,12 +415,9 @@ let init_memory (inst : module_inst) (seg : memory_segment) =
     let mem = memory inst index in
     let offset' = i32 (eval_const inst const) const.at in
     let offset = I64_convert.extend_i32_u offset' in
-    let end_ = Int64.(add offset (of_int (String.length init))) in
-    let bound = Memory.bound mem in
-    if I64.lt_u bound end_ || I64.lt_u end_ offset then
-      Link.error seg.at "data segment does not fit memory";
-    fun () -> Memory.store_bytes mem offset init
-  | Passive init -> fun () -> ()
+    (try Memory.init mem offset init
+    with Memory.Bounds -> Link.error seg.at "data segment does not fit memory")
+  | Passive init -> ()
 
 
 let add_import (m : module_) (ext : extern) (im : import) (inst : module_inst)
@@ -460,9 +453,7 @@ let init (m : module_) (exts : extern list) : module_inst =
   in
   let inst = {inst1 with exports = List.map (create_export inst1) exports} in
   List.iter (init_func inst) fs;
-  let init_elems = List.map (init_table inst) elems in
-  let init_datas = List.map (init_memory inst) data in
-  List.iter (fun f -> f ()) init_elems;
-  List.iter (fun f -> f ()) init_datas;
+  List.iter (init_table inst) elems;
+  List.iter (init_memory inst) data;
   Lib.Option.app (fun x -> ignore (invoke (func inst x) [])) start;
   inst
diff --git a/interpreter/runtime/memory.ml b/interpreter/runtime/memory.ml
index 3b7bd31b48..7417e50a24 100644
--- a/interpreter/runtime/memory.ml
+++ b/interpreter/runtime/memory.ml
@@ -147,14 +147,11 @@ let store_packed sz mem a o v =
 
 let check_bounds mem a = if I64.gt_u a (bound mem) then raise Bounds
 
-let fill mem a v n =
-  let rec loop a n =
-    if n > 0l then begin
-      store_byte mem a v;
-      loop (Int64.add a 1L) (Int32.sub n 1l)
-    end
-  in loop a n;
-  check_bounds mem Int64.(add a (of_int32 n))
+let init mem a bs =
+  for i = 0 to String.length bs - 1 do
+    store_byte mem Int64.(add a (of_int i)) (Char.code bs.[i])
+  done;
+  check_bounds mem Int64.(add a (of_int (String.length bs)))
 
 let copy mem d s n =
   let n' = Int64.of_int32 n in
@@ -170,3 +167,12 @@ let copy mem d s n =
     loop d s n 1L);
   check_bounds mem (Int64.add d n');
   check_bounds mem (Int64.add s n')
+
+let fill mem a v n =
+  let rec loop a n =
+    if n > 0l then begin
+      store_byte mem a v;
+      loop (Int64.add a 1L) (Int32.sub n 1l)
+    end
+  in loop a n;
+  check_bounds mem Int64.(add a (of_int32 n))
diff --git a/interpreter/runtime/memory.mli b/interpreter/runtime/memory.mli
index 6c25c5414b..1ed53930c7 100644
--- a/interpreter/runtime/memory.mli
+++ b/interpreter/runtime/memory.mli
@@ -44,5 +44,6 @@ val store_packed :
   pack_size -> memory -> address -> offset -> value -> unit
     (* raises Type, Bounds *)
 
-val fill : memory -> address -> int -> count -> unit (* raises Bounds *)
+val init : memory -> address -> string -> unit (* raises Bounds *)
 val copy : memory -> address -> address -> count -> unit (* raises Bounds *)
+val fill : memory -> address -> int -> count -> unit (* raises Bounds *)
diff --git a/interpreter/runtime/table.ml b/interpreter/runtime/table.ml
index f48004d6cf..a3bfaf35a0 100644
--- a/interpreter/runtime/table.ml
+++ b/interpreter/runtime/table.ml
@@ -48,7 +48,8 @@ let load tab i =
 let store tab i v =
   try Lib.Array32.set tab.content i v with Invalid_argument _ -> raise Bounds
 
-let blit tab offset elems =
-  let data = Array.of_list elems in
-  try Lib.Array32.blit data 0l tab.content offset (Lib.Array32.length data)
-  with Invalid_argument _ -> raise Bounds
+let check_bounds tab i = if I32.gt_u i (size tab) then raise Bounds
+
+let init tab offset elems =
+  List.iteri (fun i -> store tab (Int32.(add offset (of_int i)))) elems;
+  check_bounds tab Int32.(add offset (of_int (List.length elems)))
diff --git a/interpreter/runtime/table.mli b/interpreter/runtime/table.mli
index 7956d986d2..f2eb70fe51 100644
--- a/interpreter/runtime/table.mli
+++ b/interpreter/runtime/table.mli
@@ -20,4 +20,5 @@ val grow : table -> size -> unit (* raises SizeOverflow, SizeLimit *)
 
 val load : table -> index -> elem (* raises Bounds *)
 val store : table -> index -> elem -> unit (* raises Bounds *)
-val blit : table -> index -> elem list -> unit (* raises Bounds *)
+
+val init : table -> index -> elem list -> unit (* raises Bounds *)
diff --git a/test/core/linking.wast b/test/core/linking.wast
index 67ff7dd926..650f1f2a62 100644
--- a/test/core/linking.wast
+++ b/test/core/linking.wast
@@ -224,6 +224,8 @@
 )
 (assert_trap (invoke $Mt "call" (i32.const 7)) "uninitialized")
 
+;; Unlike in the v1 spec, the elements stored before an out-of-bounds access
+;; persist after the instantiation failure.
 (assert_unlinkable
   (module
     (table (import "Mt" "tab") 10 funcref)
@@ -233,7 +235,7 @@
   )
   "elements segment does not fit"
 )
-(assert_trap (invoke $Mt "call" (i32.const 7)) "uninitialized")
+(assert_return (invoke $Mt "call" (i32.const 7)) (i32.const 0))
 
 (assert_unlinkable
   (module
@@ -245,7 +247,7 @@
   )
   "data segment does not fit"
 )
-(assert_trap (invoke $Mt "call" (i32.const 7)) "uninitialized")
+(assert_return (invoke $Mt "call" (i32.const 7)) (i32.const 0))
 
 
 ;; Memories
@@ -331,6 +333,8 @@
 )
 (assert_return (invoke $Mm "load" (i32.const 0)) (i32.const 0))
 
+;; Unlike in v1 spec, bytes written before an out-of-bounds access persist
+;; after the instantiation failure.
 (assert_unlinkable
   (module
     (memory (import "Mm" "mem") 1)
@@ -339,7 +343,7 @@
   )
   "data segment does not fit"
 )
-(assert_return (invoke $Mm "load" (i32.const 0)) (i32.const 0))
+(assert_return (invoke $Mm "load" (i32.const 0)) (i32.const 97))
 
 (assert_unlinkable
   (module
@@ -351,4 +355,4 @@
   )
   "elements segment does not fit"
 )
-(assert_return (invoke $Mm "load" (i32.const 0)) (i32.const 0))
+(assert_return (invoke $Mm "load" (i32.const 0)) (i32.const 97))

From f57436427d60f800a3d4896f47da834bef0a9c2d Mon Sep 17 00:00:00 2001
From: Ben Smith 
Date: Fri, 1 Mar 2019 12:53:02 -0800
Subject: [PATCH 063/199] [Interpreter] Implement rest of the instructions
 (#64)

`memory.init`, `data.drop`, `table.init`, `elem.drop`, `table.copy`

Also fix writing passive segments in the text format.
---
 interpreter/exec/eval.ml        |  71 +++++++++++-
 interpreter/runtime/instance.ml |   6 +-
 interpreter/runtime/memory.ml   |  20 +++-
 interpreter/runtime/memory.mli  |   3 +-
 interpreter/runtime/table.ml    |  29 ++++-
 interpreter/runtime/table.mli   |   5 +-
 interpreter/text/arrange.ml     |   2 +-
 test/core/bulk.wast             | 192 ++++++++++++++++++++++++++++++++
 8 files changed, 312 insertions(+), 16 deletions(-)

diff --git a/interpreter/exec/eval.ml b/interpreter/exec/eval.ml
index 2a7e812436..8aacf8d1c3 100644
--- a/interpreter/exec/eval.ml
+++ b/interpreter/exec/eval.ml
@@ -17,6 +17,10 @@ exception Trap = Trap.Error
 exception Crash = Crash.Error (* failure that cannot happen in valid code *)
 exception Exhaustion = Exhaustion.Error
 
+let table_error at = function
+  | Table.Bounds -> "out of bounds table access"
+  | exn -> raise exn
+
 let memory_error at = function
   | Memory.Bounds -> "out of bounds memory access"
   | Memory.SizeOverflow -> "memory size overflow"
@@ -78,6 +82,8 @@ let func (inst : module_inst) x = lookup "function" inst.funcs x
 let table (inst : module_inst) x = lookup "table" inst.tables x
 let memory (inst : module_inst) x = lookup "memory" inst.memories x
 let global (inst : module_inst) x = lookup "global" inst.globals x
+let elems (inst : module_inst) x = lookup "elems" inst.elems x
+let data (inst : module_inst) x = lookup "data" inst.data x
 let local (frame : frame) x = lookup "local" frame.locals x
 
 let elem inst x i at =
@@ -249,6 +255,22 @@ let rec step (c : config) : config =
         (try Eval_numeric.eval_cvtop cvtop v :: vs', []
         with exn -> vs', [Trapping (numeric_error e.at exn) @@ e.at])
 
+      | MemoryInit x, I32 n :: I32 s :: I32 d :: vs' ->
+        let mem = memory frame.inst (0l @@ e.at) in
+        (match !(data frame.inst x) with
+        | Some bs ->
+          let dst = I64_convert.extend_i32_u d in
+          let src = I64_convert.extend_i32_u s in
+          (try Memory.init mem bs dst src n; vs', []
+          with exn -> vs', [Trapping (memory_error e.at exn) @@ e.at])
+        | None -> vs', [Trapping "data segment dropped" @@ e.at])
+
+      | DataDrop x, vs ->
+        let seg = data frame.inst x in
+        (match !seg with
+        | Some _ -> seg := None; vs, []
+        | None -> vs, [Trapping "data segment dropped" @@ e.at])
+
       | MemoryCopy, I32 n :: I32 s :: I32 d :: vs' ->
         let mem = memory frame.inst (0l @@ e.at) in
         let dst = I64_convert.extend_i32_u d in
@@ -262,6 +284,25 @@ let rec step (c : config) : config =
         (try Memory.fill mem addr (Int32.to_int b) n; vs', []
         with exn -> vs', [Trapping (memory_error e.at exn) @@ e.at])
 
+      | TableInit x, I32 n :: I32 s :: I32 d :: vs' ->
+        let tab = table frame.inst (0l @@ e.at) in
+        (match !(elems frame.inst x) with
+        | Some es ->
+          (try Table.init tab es d s n; vs', []
+          with exn -> vs', [Trapping (table_error e.at exn) @@ e.at])
+        | None -> vs', [Trapping "elements segment dropped" @@ e.at])
+
+      | ElemDrop x, vs ->
+        let seg = elems frame.inst x in
+        (match !seg with
+        | Some _ -> seg := None; vs, []
+        | None -> vs, [Trapping "elements segment dropped" @@ e.at])
+
+      | TableCopy, I32 n :: I32 s :: I32 d :: vs' ->
+        let tab = table frame.inst (0l @@ e.at) in
+        (try Table.copy tab d s n; vs', []
+        with exn -> vs', [Trapping (table_error e.at exn) @@ e.at])
+
       | _ ->
         let s1 = string_of_values (List.rev vs) in
         let s2 = string_of_value_types (List.map type_of (List.rev vs)) in
@@ -394,6 +435,19 @@ let create_export (inst : module_inst) (ex : export) : export_inst =
     | GlobalExport x -> ExternGlobal (global inst x)
   in name, ext
 
+let elems_list inst init =
+  List.map (fun x -> (FuncElem (func inst x))) init
+
+let create_elems (inst : module_inst) (seg : table_segment) : elems_inst =
+  match seg.it with
+  | Active _ -> ref None
+  | Passive init -> ref (Some (elems_list inst init))
+
+let create_data (inst : module_inst) (seg : memory_segment) : data_inst =
+  match seg.it with
+  | Active _ -> ref None
+  | Passive init -> ref (Some init)
+
 
 let init_func (inst : module_inst) (func : func_inst) =
   match func with
@@ -405,7 +459,9 @@ let init_table (inst : module_inst) (seg : table_segment) =
   | Active {index; offset = const; init} ->
     let tab = table inst index in
     let offset = i32 (eval_const inst const) const.at in
-    (try Table.init tab offset (List.map (fun x -> FuncElem (func inst x)) init)
+    let elems = elems_list inst init in
+    let len = Int32.of_int (List.length elems) in
+    (try Table.init tab elems offset 0l len
     with Table.Bounds -> Link.error seg.at "elements segment does not fit table")
   | Passive init -> ()
 
@@ -415,7 +471,8 @@ let init_memory (inst : module_inst) (seg : memory_segment) =
     let mem = memory inst index in
     let offset' = i32 (eval_const inst const) const.at in
     let offset = I64_convert.extend_i32_u offset' in
-    (try Memory.init mem offset init
+    let len = Int32.of_int (String.length init) in
+    (try Memory.init mem init offset 0L len
     with Memory.Bounds -> Link.error seg.at "data segment does not fit memory")
   | Passive init -> ()
 
@@ -448,10 +505,16 @@ let init (m : module_) (exts : extern list) : module_inst =
       funcs = inst0.funcs @ fs;
       tables = inst0.tables @ List.map (create_table inst0) tables;
       memories = inst0.memories @ List.map (create_memory inst0) memories;
-      globals = inst0.globals @ List.map (create_global inst0) globals;
+      globals = inst0.globals @ List.map (create_global inst0) globals
+    }
+  in
+  let inst =
+    { inst1 with
+      exports = List.map (create_export inst1) exports;
+      elems = List.map (create_elems inst1) elems;
+      data = List.map (create_data inst1) data
     }
   in
-  let inst = {inst1 with exports = List.map (create_export inst1) exports} in
   List.iter (init_func inst) fs;
   List.iter (init_table inst) elems;
   List.iter (init_memory inst) data;
diff --git a/interpreter/runtime/instance.ml b/interpreter/runtime/instance.ml
index 6ac583742d..eb821d2ee0 100644
--- a/interpreter/runtime/instance.ml
+++ b/interpreter/runtime/instance.ml
@@ -8,6 +8,8 @@ type module_inst =
   memories : memory_inst list;
   globals : global_inst list;
   exports : export_inst list;
+  elems : elems_inst list;
+  data : data_inst list;
 }
 
 and func_inst = module_inst ref Func.t
@@ -15,6 +17,8 @@ and table_inst = Table.t
 and memory_inst = Memory.t
 and global_inst = Global.t
 and export_inst = Ast.name * extern
+and elems_inst = Table.elem list option ref
+and data_inst = string option ref
 
 and extern =
   | ExternFunc of func_inst
@@ -29,7 +33,7 @@ type Table.elem += FuncElem of func_inst
 
 let empty_module_inst =
   { types = []; funcs = []; tables = []; memories = []; globals = [];
-    exports = [] }
+    exports = []; elems = []; data = [] }
 
 let extern_type_of = function
   | ExternFunc func -> ExternFuncType (Func.type_of func)
diff --git a/interpreter/runtime/memory.ml b/interpreter/runtime/memory.ml
index 7417e50a24..05bb4c3db1 100644
--- a/interpreter/runtime/memory.ml
+++ b/interpreter/runtime/memory.ml
@@ -145,13 +145,23 @@ let store_packed sz mem a o v =
     | _ -> raise Type
   in storen mem a o n x
 
+let check_str_bounds bs a =
+  if I64.gt_u a (Int64.of_int (String.length bs)) then raise Bounds
+
 let check_bounds mem a = if I64.gt_u a (bound mem) then raise Bounds
 
-let init mem a bs =
-  for i = 0 to String.length bs - 1 do
-    store_byte mem Int64.(add a (of_int i)) (Char.code bs.[i])
-  done;
-  check_bounds mem Int64.(add a (of_int (String.length bs)))
+let init mem bs d s n =
+  let n' = Int64.of_int32 n in
+  let rec loop d s n =
+    if n > 0l then begin
+      check_str_bounds bs s;
+      let b = (Char.code bs.[Int64.to_int s]) in
+      store_byte mem d b;
+      loop (Int64.add d 1L) (Int64.add s 1L) (Int32.sub n 1l)
+    end
+  in loop d s n;
+  check_bounds mem (Int64.add d n');
+  check_str_bounds bs (Int64.add s n')
 
 let copy mem d s n =
   let n' = Int64.of_int32 n in
diff --git a/interpreter/runtime/memory.mli b/interpreter/runtime/memory.mli
index 1ed53930c7..a20714418d 100644
--- a/interpreter/runtime/memory.mli
+++ b/interpreter/runtime/memory.mli
@@ -44,6 +44,7 @@ val store_packed :
   pack_size -> memory -> address -> offset -> value -> unit
     (* raises Type, Bounds *)
 
-val init : memory -> address -> string -> unit (* raises Bounds *)
+val init :
+  memory -> string -> address -> address -> count -> unit (* raises Bounds *)
 val copy : memory -> address -> address -> count -> unit (* raises Bounds *)
 val fill : memory -> address -> int -> count -> unit (* raises Bounds *)
diff --git a/interpreter/runtime/table.ml b/interpreter/runtime/table.ml
index a3bfaf35a0..d095533c20 100644
--- a/interpreter/runtime/table.ml
+++ b/interpreter/runtime/table.ml
@@ -2,6 +2,7 @@ open Types
 
 type size = int32
 type index = int32
+type count = int32
 
 type elem = ..
 type elem += Uninitialized
@@ -50,6 +51,28 @@ let store tab i v =
 
 let check_bounds tab i = if I32.gt_u i (size tab) then raise Bounds
 
-let init tab offset elems =
-  List.iteri (fun i -> store tab (Int32.(add offset (of_int i)))) elems;
-  check_bounds tab Int32.(add offset (of_int (List.length elems)))
+let init tab es d s n =
+  let rec loop es d s n =
+    match s, n, es with
+    | 0l, 0l, _ -> ()
+    | 0l, n, e::es' ->
+      store tab d e;
+      loop es' (Int32.add d 1l) 0l (Int32.sub n 1l)
+    | s, n, _::es' -> loop es' d (Int32.sub s 1l) n
+    | _ -> raise Bounds
+  in loop es d s n;
+  check_bounds tab (Int32.add d n)
+
+let copy tab d s n =
+  let overlap = I32.lt_s Int32.(abs (sub d s)) n in
+  let rec loop d s n dx =
+    if n > 0l then begin
+      store tab d (load tab s);
+      loop (Int32.add d dx) (Int32.add s dx) (Int32.sub n 1l) dx
+    end
+  in (if overlap && s < d then
+    loop Int32.(add d (sub n 1l)) Int32.(add s (sub n 1l)) n (-1l)
+  else
+    loop d s n 1l);
+  check_bounds tab (Int32.add d n);
+  check_bounds tab (Int32.add s n)
diff --git a/interpreter/runtime/table.mli b/interpreter/runtime/table.mli
index f2eb70fe51..eadb713e74 100644
--- a/interpreter/runtime/table.mli
+++ b/interpreter/runtime/table.mli
@@ -5,6 +5,7 @@ type t = table
 
 type size = int32
 type index = int32
+type count = int32
 
 type elem = ..
 type elem += Uninitialized
@@ -21,4 +22,6 @@ val grow : table -> size -> unit (* raises SizeOverflow, SizeLimit *)
 val load : table -> index -> elem (* raises Bounds *)
 val store : table -> index -> elem -> unit (* raises Bounds *)
 
-val init : table -> index -> elem list -> unit (* raises Bounds *)
+val init :
+  table -> elem list -> index -> index -> count -> unit (* raises Bounds *)
+val copy : table -> index -> index -> count -> unit (* raises Bounds *)
diff --git a/interpreter/text/arrange.ml b/interpreter/text/arrange.ml
index 1ac29d7d76..1a8cafa44b 100644
--- a/interpreter/text/arrange.ml
+++ b/interpreter/text/arrange.ml
@@ -300,7 +300,7 @@ let segment head dat seg =
   match seg.it with
   | Active {index; offset; init} ->
     Node (head, atom var index :: Node ("offset", const offset) :: dat init)
-  | Passive init -> Node (head, dat init)
+  | Passive init -> Node (head ^ " passive", dat init)
 
 let elems seg =
   segment "elem" (list (atom var)) seg
diff --git a/test/core/bulk.wast b/test/core/bulk.wast
index 769d9d8dc0..14091b1649 100644
--- a/test/core/bulk.wast
+++ b/test/core/bulk.wast
@@ -1,3 +1,4 @@
+;; memory.fill
 (module
   (memory 1)
 
@@ -41,6 +42,7 @@
     "out of bounds memory access")
 
 
+;; memory.copy
 (module
   (memory (data "\aa\bb\cc\dd"))
 
@@ -102,3 +104,193 @@
     "out of bounds memory access")
 (assert_trap (invoke "copy" (i32.const 0) (i32.const 0x10001) (i32.const 0))
     "out of bounds memory access")
+
+
+;; memory.init
+(module
+  (memory 1)
+  (data passive "\aa\bb\cc\dd")
+
+  (func (export "init") (param i32 i32 i32)
+    (memory.init 0
+      (local.get 0)
+      (local.get 1)
+      (local.get 2)))
+
+  (func (export "load8_u") (param i32) (result i32)
+    (i32.load8_u (local.get 0)))
+)
+
+(invoke "init" (i32.const 0) (i32.const 1) (i32.const 2))
+(assert_return (invoke "load8_u" (i32.const 0)) (i32.const 0xbb))
+(assert_return (invoke "load8_u" (i32.const 1)) (i32.const 0xcc))
+(assert_return (invoke "load8_u" (i32.const 2)) (i32.const 0))
+
+;; Init ending at memory limit and segment limit is ok.
+(invoke "init" (i32.const 0xfffc) (i32.const 0) (i32.const 4))
+
+;; Out-of-bounds writes trap, but all previous writes succeed.
+(assert_trap (invoke "init" (i32.const 0xfffe) (i32.const 0) (i32.const 3))
+    "out of bounds memory access")
+(assert_return (invoke "load8_u" (i32.const 0xfffe)) (i32.const 0xaa))
+(assert_return (invoke "load8_u" (i32.const 0xffff)) (i32.const 0xbb))
+
+;; Succeed when writing 0 bytes at the end of either region.
+(invoke "init" (i32.const 0x10000) (i32.const 0) (i32.const 0))
+(invoke "init" (i32.const 0) (i32.const 4) (i32.const 0))
+
+;; Fail on out-of-bounds when writing 0 bytes outside of memory or segment.
+(assert_trap (invoke "init" (i32.const 0x10001) (i32.const 0) (i32.const 0))
+    "out of bounds memory access")
+(assert_trap (invoke "init" (i32.const 0) (i32.const 5) (i32.const 0))
+    "out of bounds memory access")
+
+;; data.drop
+(module
+  (memory 1)
+  (data $p passive "")
+  (data $a 0 (i32.const 0) "")
+
+  (func (export "drop_passive") (data.drop $p))
+  (func (export "init_passive")
+    (memory.init $p (i32.const 0) (i32.const 0) (i32.const 0)))
+
+  (func (export "drop_active") (data.drop $a))
+  (func (export "init_active")
+    (memory.init $a (i32.const 0) (i32.const 0) (i32.const 0)))
+)
+
+(invoke "init_passive")
+(invoke "drop_passive")
+(assert_trap (invoke "drop_passive") "data segment dropped")
+(assert_trap (invoke "init_passive") "data segment dropped")
+(assert_trap (invoke "drop_active") "data segment dropped")
+(assert_trap (invoke "init_active") "data segment dropped")
+
+
+;; table.init
+(module
+  (table 3 funcref)
+  (elem passive $zero $one $zero $one)
+
+  (func $zero (result i32) (i32.const 0))
+  (func $one (result i32) (i32.const 1))
+
+  (func (export "init") (param i32 i32 i32)
+    (table.init 0
+      (local.get 0)
+      (local.get 1)
+      (local.get 2)))
+
+  (func (export "call") (param i32) (result i32)
+    (call_indirect (result i32)
+      (local.get 0)))
+)
+
+(invoke "init" (i32.const 0) (i32.const 1) (i32.const 2))
+(assert_return (invoke "call" (i32.const 0)) (i32.const 1))
+(assert_return (invoke "call" (i32.const 1)) (i32.const 0))
+(assert_trap (invoke "call" (i32.const 2)) "uninitialized element")
+
+;; Init ending at table limit and segment limit is ok.
+(invoke "init" (i32.const 1) (i32.const 2) (i32.const 2))
+
+;; Out-of-bounds stores trap, but all previous stores succeed.
+(assert_trap (invoke "init" (i32.const 2) (i32.const 0) (i32.const 2))
+    "out of bounds table access")
+(assert_return (invoke "call" (i32.const 2)) (i32.const 0))
+
+;; Succeed when storing 0 elements at the end of either region.
+(invoke "init" (i32.const 3) (i32.const 0) (i32.const 0))
+(invoke "init" (i32.const 0) (i32.const 4) (i32.const 0))
+
+;; Fail on out-of-bounds when storing 0 elements outside of table or segment.
+(assert_trap (invoke "init" (i32.const 4) (i32.const 0) (i32.const 0))
+    "out of bounds table access")
+(assert_trap (invoke "init" (i32.const 0) (i32.const 5) (i32.const 0))
+    "out of bounds table access")
+
+
+;; elem.drop
+(module
+  (table 1 funcref)
+  (func $f)
+  (elem $p passive $f)
+  (elem $a 0 (i32.const 0) $f)
+
+  (func (export "drop_passive") (elem.drop $p))
+  (func (export "init_passive")
+    (table.init $p (i32.const 0) (i32.const 0) (i32.const 0)))
+
+  (func (export "drop_active") (elem.drop $a))
+  (func (export "init_active")
+    (table.init $a (i32.const 0) (i32.const 0) (i32.const 0)))
+)
+
+(invoke "init_passive")
+(invoke "drop_passive")
+(assert_trap (invoke "drop_passive") "elements segment dropped")
+(assert_trap (invoke "init_passive") "elements segment dropped")
+(assert_trap (invoke "drop_active") "elements segment dropped")
+(assert_trap (invoke "init_active") "elements segment dropped")
+
+
+;; table.copy
+(module
+  (table 10 funcref)
+  (elem (i32.const 0) $zero $one $two)
+  (func $zero (result i32) (i32.const 0))
+  (func $one (result i32) (i32.const 1))
+  (func $two (result i32) (i32.const 2))
+
+  (func (export "copy") (param i32 i32 i32)
+    (table.copy
+      (local.get 0)
+      (local.get 1)
+      (local.get 2)))
+
+  (func (export "call") (param i32) (result i32)
+    (call_indirect (result i32)
+      (local.get 0)))
+)
+
+;; Non-overlapping copy.
+(invoke "copy" (i32.const 3) (i32.const 0) (i32.const 3))
+;; Now [$zero, $one, $two, $zero, $one, $two, ...]
+(assert_return (invoke "call" (i32.const 3)) (i32.const 0))
+(assert_return (invoke "call" (i32.const 4)) (i32.const 1))
+(assert_return (invoke "call" (i32.const 5)) (i32.const 2))
+
+;; Overlap, source > dest
+(invoke "copy" (i32.const 0) (i32.const 1) (i32.const 3))
+;; Now [$one, $two, $zero, $zero, $one, $two, ...]
+(assert_return (invoke "call" (i32.const 0)) (i32.const 1))
+(assert_return (invoke "call" (i32.const 1)) (i32.const 2))
+(assert_return (invoke "call" (i32.const 2)) (i32.const 0))
+
+;; Overlap, source < dest
+(invoke "copy" (i32.const 2) (i32.const 0) (i32.const 3))
+;; Now [$one, $two, $one, $two, $zero, $two, ...]
+(assert_return (invoke "call" (i32.const 2)) (i32.const 1))
+(assert_return (invoke "call" (i32.const 3)) (i32.const 2))
+(assert_return (invoke "call" (i32.const 4)) (i32.const 0))
+
+;; Copy ending at table limit is ok.
+(invoke "copy" (i32.const 6) (i32.const 8) (i32.const 2))
+(invoke "copy" (i32.const 8) (i32.const 6) (i32.const 2))
+
+;; Out-of-bounds writes trap, but all previous writes succeed.
+(assert_trap (invoke "call" (i32.const 9)) "uninitialized element")
+(assert_trap (invoke "copy" (i32.const 9) (i32.const 0) (i32.const 2))
+    "out of bounds table access")
+(assert_return (invoke "call" (i32.const 9)) (i32.const 1))
+
+;; Succeed when copying 0 elements at the end of the region.
+(invoke "copy" (i32.const 10) (i32.const 0) (i32.const 0))
+(invoke "copy" (i32.const 0) (i32.const 10) (i32.const 0))
+
+;; Fail on out-of-bounds when copying 0 elements outside of table.
+(assert_trap (invoke "copy" (i32.const 11) (i32.const 0) (i32.const 0))
+    "out of bounds table access")
+(assert_trap (invoke "copy" (i32.const 0) (i32.const 11) (i32.const 0))
+    "out of bounds table access")

From d97e8fb93746d3b18599695d2a91200b0ba22f94 Mon Sep 17 00:00:00 2001
From: Ben Smith 
Date: Fri, 1 Mar 2019 13:11:38 -0800
Subject: [PATCH 064/199] [Interpreter] New syntax for passive elem segments
 (#65)

It uses instruction encoding instead of assuming that each element is a
function variable:

```
0xd0 -> ref.null
0xd2 x -> ref.func x
```
---
 interpreter/binary/decode.ml | 23 +++++++++++++++++------
 interpreter/binary/encode.ml | 20 +++++++++++++++-----
 interpreter/exec/eval.ml     |  6 +++++-
 interpreter/syntax/ast.ml    |  9 +++++++--
 interpreter/text/arrange.ml  | 20 +++++++++++++++-----
 interpreter/text/lexer.mll   |  3 +++
 interpreter/text/parser.mly  | 26 ++++++++++++++++++++------
 interpreter/valid/valid.ml   |  9 +++++++--
 test/core/bulk.wast          | 16 ++++++++++++++--
 9 files changed, 103 insertions(+), 29 deletions(-)

diff --git a/interpreter/binary/decode.ml b/interpreter/binary/decode.ml
index 90a0d9c14f..9665883707 100644
--- a/interpreter/binary/decode.ml
+++ b/interpreter/binary/decode.ml
@@ -612,25 +612,36 @@ let code_section s =
 
 (* Element section *)
 
-let segment dat s =
+let segment active passive s =
   match vu32 s with
   | 0l ->
     let index = Source.(0l @@ Source.no_region) in
     let offset = const s in
-    let init = dat s in
+    let init = active s in
     Active {index; offset; init}
   | 1l ->
-    let init = dat s in
+    let init = passive s in
     Passive init
   | 2l ->
     let index = at var s in
     let offset = const s in
-    let init = dat s in
+    let init = active s in
     Active {index; offset; init}
   | _ -> error s (pos s - 1) "invalid segment kind"
 
+let active_elem s = Func (at var s)
+
+let passive_elem s =
+  match u8 s with
+  | 0xd0 -> end_ s; Null
+  | 0xd2 ->
+    let x = at var s in
+    end_ s;
+    Func x
+  | _ -> error s (pos s - 1) "invalid elem"
+
 let table_segment s =
-  segment (vec (at var)) s
+  segment (vec (at active_elem)) (vec (at passive_elem)) s
 
 let elem_section s =
   section `ElemSection (vec (at table_segment)) [] s
@@ -639,7 +650,7 @@ let elem_section s =
 (* Data section *)
 
 let memory_segment s =
-  segment string s
+  segment string string s
 
 let data_section s =
   section `DataSection (vec (at memory_segment)) [] s
diff --git a/interpreter/binary/encode.ml b/interpreter/binary/encode.ml
index 7dfed605a4..7f8b7addf4 100644
--- a/interpreter/binary/encode.ml
+++ b/interpreter/binary/encode.ml
@@ -477,7 +477,7 @@ let encode m =
       section 10 (vec code) fs (fs <> [])
 
     (* Element section *)
-    let segment dat seg =
+    let segment active passive seg =
       match seg.it with
       | Active {index; offset; init} ->
         if index.it = 0l then
@@ -486,19 +486,29 @@ let encode m =
           u8 0x02; var index
         end;
         const offset;
-        dat init
+        active init
       | Passive init ->
-        u8 0x01; dat init
+        u8 0x01; passive init
+
+    let active_elem el =
+      match el.it with
+      | Null -> assert false
+      | Func x -> var x
+
+    let passive_elem el =
+      match el.it with
+      | Null -> u8 0xd0; end_ ()
+      | Func x -> u8 0xd2; var x; end_ ()
 
     let table_segment seg =
-      segment (vec var) seg
+      segment (vec active_elem) (vec passive_elem) seg
 
     let elem_section elems =
       section 9 (vec table_segment) elems (elems <> [])
 
     (* Data section *)
     let memory_segment seg =
-      segment string seg
+      segment string string seg
 
     let data_section data =
       section 11 (vec memory_segment) data (data <> [])
diff --git a/interpreter/exec/eval.ml b/interpreter/exec/eval.ml
index 8aacf8d1c3..77082a893d 100644
--- a/interpreter/exec/eval.ml
+++ b/interpreter/exec/eval.ml
@@ -436,7 +436,11 @@ let create_export (inst : module_inst) (ex : export) : export_inst =
   in name, ext
 
 let elems_list inst init =
-  List.map (fun x -> (FuncElem (func inst x))) init
+  let to_elem el =
+    match el.it with
+    | Null -> Table.Uninitialized
+    | Func x -> FuncElem (func inst x)
+  in List.map to_elem init
 
 let create_elems (inst : module_inst) (seg : table_segment) : elems_inst =
   match seg.it with
diff --git a/interpreter/syntax/ast.ml b/interpreter/syntax/ast.ml
index c1bb58ae1c..4550b7759d 100644
--- a/interpreter/syntax/ast.ml
+++ b/interpreter/syntax/ast.ml
@@ -145,7 +145,12 @@ and 'data segment' =
   | Active of {index : var; offset : const; init : 'data}
   | Passive of 'data
 
-type table_segment = var list segment
+type elem = elem' Source.phrase
+and elem' =
+  | Null
+  | Func of var
+
+type table_segment = elem list segment
 type memory_segment = string segment
 
 
@@ -191,7 +196,7 @@ and module_' =
   memories : memory list;
   funcs : func list;
   start : var option;
-  elems : var list segment list;
+  elems : elem list segment list;
   data : string segment list;
   imports : import list;
   exports : export list;
diff --git a/interpreter/text/arrange.ml b/interpreter/text/arrange.ml
index 1a8cafa44b..1217969b53 100644
--- a/interpreter/text/arrange.ml
+++ b/interpreter/text/arrange.ml
@@ -296,17 +296,27 @@ let memory off i mem =
   let {mtype = MemoryType lim} = mem.it in
   Node ("memory $" ^ nat (off + i) ^ " " ^ limits nat32 lim, [])
 
-let segment head dat seg =
+let segment head active passive seg =
   match seg.it with
   | Active {index; offset; init} ->
-    Node (head, atom var index :: Node ("offset", const offset) :: dat init)
-  | Passive init -> Node (head ^ " passive", dat init)
+    Node (head, atom var index :: Node ("offset", const offset) :: active init)
+  | Passive init -> Node (head ^ " passive", passive init)
+
+let active_elem el =
+  match el.it with
+  | Null -> assert false
+  | Func x -> atom var x
+
+let passive_elem el =
+  match el.it with
+  | Null -> Node ("ref.null", [])
+  | Func x -> Node ("ref.func", [atom var x])
 
 let elems seg =
-  segment "elem" (list (atom var)) seg
+  segment "elem" (list active_elem) (list passive_elem) seg
 
 let data seg =
-  segment "data" break_bytes seg
+  segment "data" break_bytes break_bytes seg
 
 
 (* Modules *)
diff --git a/interpreter/text/lexer.mll b/interpreter/text/lexer.mll
index afd7307ad4..d29f11bb6e 100644
--- a/interpreter/text/lexer.mll
+++ b/interpreter/text/lexer.mll
@@ -325,6 +325,9 @@ rule token = parse
   | "elem.drop" { ELEM_DROP }
   | "table.copy" { TABLE_COPY }
 
+  | "ref.null" { REF_NULL }
+  | "ref.func" { REF_FUNC }
+
   | "passive" { PASSIVE }
 
   | "type" { TYPE }
diff --git a/interpreter/text/parser.mly b/interpreter/text/parser.mly
index d405534c59..7abe892b69 100644
--- a/interpreter/text/parser.mly
+++ b/interpreter/text/parser.mly
@@ -163,6 +163,7 @@ let inline_type_explicit (c : context) x ft at =
 %token UNREACHABLE MEMORY_SIZE MEMORY_GROW
 %token MEMORY_INIT DATA_DROP MEMORY_COPY MEMORY_FILL
 %token TABLE_INIT ELEM_DROP TABLE_COPY
+%token REF_NULL REF_FUNC
 %token FUNC START TYPE PARAM RESULT LOCAL GLOBAL
 %token TABLE ELEM MEMORY DATA OFFSET IMPORT EXPORT TABLE
 %token PASSIVE
@@ -568,22 +569,35 @@ offset :
   | LPAR OFFSET const_expr RPAR { $3 }
   | expr { let at = at () in fun c -> $1 c @@ at }  /* Sugar */
 
+elemref :
+  | LPAR REF_NULL RPAR { let at = at () in fun c -> Null @@ at }
+  | LPAR REF_FUNC var RPAR { let at = at () in fun c -> Func ($3 c func) @@ at }
+
+passive_elemref_list :
+  | /* empty */ { fun c -> [] }
+  | elemref passive_elemref_list { fun c -> $1 c :: $2 c }
+
+active_elemref_list :
+  | var_list
+    { let f = function {at; _} as x -> Func x @@ at in
+      fun c lookup -> List.map f ($1 c lookup) }
+
 elem :
-  | LPAR ELEM bind_var_opt PASSIVE var_list RPAR
+  | LPAR ELEM bind_var_opt PASSIVE passive_elemref_list RPAR
     { let at = at () in
       fun c -> ignore ($3 c anon_elem bind_elem);
-      fun () -> Passive ($5 c func) @@ at }
-  | LPAR ELEM bind_var var offset var_list RPAR
+      fun () -> Passive ($5 c) @@ at }
+  | LPAR ELEM bind_var var offset active_elemref_list RPAR
     { let at = at () in
       fun c -> ignore (bind_elem c $3);
       fun () ->
       Active {index = $4 c table; offset = $5 c; init = $6 c func} @@ at }
-  | LPAR ELEM var offset var_list RPAR
+  | LPAR ELEM var offset active_elemref_list RPAR
     { let at = at () in
       fun c -> ignore (anon_elem c);
       fun () ->
       Active {index = $3 c table; offset = $4 c; init = $5 c func} @@ at }
-  | LPAR ELEM offset var_list RPAR  /* Sugar */
+  | LPAR ELEM offset active_elemref_list RPAR  /* Sugar */
     { let at = at () in
       fun c -> ignore (anon_elem c);
       fun () ->
@@ -606,7 +620,7 @@ table_fields :
   | inline_export table_fields  /* Sugar */
     { fun c x at -> let tabs, elems, ims, exs = $2 c x at in
       tabs, elems, ims, $1 (TableExport x) c :: exs }
-  | elem_type LPAR ELEM var_list RPAR  /* Sugar */
+  | elem_type LPAR ELEM active_elemref_list RPAR  /* Sugar */
     { fun c x at ->
       let offset = [i32_const (0l @@ at) @@ at] @@ at in
       let init = $4 c func in let size = Int32.of_int (List.length init) in
diff --git a/interpreter/valid/valid.ml b/interpreter/valid/valid.ml
index 184b489b62..ced695bf8f 100644
--- a/interpreter/valid/valid.ml
+++ b/interpreter/valid/valid.ml
@@ -424,14 +424,19 @@ let check_memory (c : context) (mem : memory) =
   let {mtype} = mem.it in
   check_memory_type mtype mem.at
 
+let check_elemref (c : context) (el : elem) =
+  match el.it with
+  | Null -> ()
+  | Func x -> ignore (func c x)
+
 let check_elem (c : context) (seg : table_segment) =
   match seg.it with
   | Active {index; offset; init} ->
     ignore (table c index);
     check_const c offset I32Type;
-    ignore (List.map (func c) init)
+    List.iter (check_elemref c) init
   | Passive init ->
-    ignore (List.map (func c) init)
+    List.iter (check_elemref c) init
 
 let check_data (c : context) (seg : memory_segment) =
   match seg.it with
diff --git a/test/core/bulk.wast b/test/core/bulk.wast
index 14091b1649..492b004094 100644
--- a/test/core/bulk.wast
+++ b/test/core/bulk.wast
@@ -1,3 +1,14 @@
+;; Passive segment syntax
+(module
+  (memory 1)
+  (data passive "foo"))
+
+(module
+  (table 3 funcref)
+  (elem passive (ref.func 0) (ref.null) (ref.func 1))
+  (func)
+  (func))
+
 ;; memory.fill
 (module
   (memory 1)
@@ -171,7 +182,8 @@
 ;; table.init
 (module
   (table 3 funcref)
-  (elem passive $zero $one $zero $one)
+  (elem passive
+    (ref.func $zero) (ref.func $one) (ref.func $zero) (ref.func $one))
 
   (func $zero (result i32) (i32.const 0))
   (func $one (result i32) (i32.const 1))
@@ -215,7 +227,7 @@
 (module
   (table 1 funcref)
   (func $f)
-  (elem $p passive $f)
+  (elem $p passive (ref.func $f))
   (elem $a 0 (i32.const 0) $f)
 
   (func (export "drop_passive") (elem.drop $p))

From 35d08d26e7164e9d488116cff2a3424b3512c814 Mon Sep 17 00:00:00 2001
From: Ben Smith 
Date: Tue, 5 Mar 2019 14:09:13 -0800
Subject: [PATCH 065/199] [Interpreter] Fix bugs found by Lars' tests (#66)

* The data count section is required if the `memory.init` or `data.drop`
  instructions are used.

* `memory.init` had an off-by-one bug when reading at the end of a segment.

* All instructions that operate on regions need to compare length to 0
  using unsigned comparison (e.g. `I32.gt_u n 0l`).

* Converting length from 32- to 64-bit now uses
  `I64_convert.extend_i32_u`, instead of `Int64.of_int32`, since the
  latter will sign-extend.

* The `table.copy` overlap test now uses an unsigned comparison.

* The passive element text syntax still allows function indexes, e.g.
  `(elem passive $f1 $f2)`.

* Add element type to passive element segments
---
 interpreter/binary/decode.ml  | 24 ++++++++++++++++++++----
 interpreter/binary/encode.ml  |  4 +++-
 interpreter/exec/eval.ml      |  4 ++--
 interpreter/runtime/memory.ml | 23 ++++++++++++-----------
 interpreter/runtime/table.ml  |  4 ++--
 interpreter/syntax/ast.ml     |  6 +++---
 interpreter/text/arrange.ml   |  4 +++-
 interpreter/text/parser.mly   | 17 +++++++++++------
 interpreter/valid/valid.ml    |  4 ++--
 test/core/bulk.wast           |  6 +++---
 10 files changed, 61 insertions(+), 35 deletions(-)

diff --git a/interpreter/binary/decode.ml b/interpreter/binary/decode.ml
index 9665883707..00b13d5442 100644
--- a/interpreter/binary/decode.ml
+++ b/interpreter/binary/decode.ml
@@ -5,11 +5,12 @@ type stream =
   name : string;
   bytes : string;
   pos : int ref;
+  has_data_count : bool ref;
 }
 
 exception EOS
 
-let stream name bs = {name; bytes = bs; pos = ref 0}
+let stream name bs = {name; bytes = bs; pos = ref 0; has_data_count = ref false}
 
 let len s = String.length s.bytes
 let pos s = !(s.pos)
@@ -201,14 +202,18 @@ let memop s =
   let offset = vu32 s in
   Int32.to_int align, offset
 
+let check_data_count s =
+  require !(s.has_data_count) s (pos s - 1) "data count section required"
+
 let misc_instr s =
   let pos = pos s in
   match op s with
   | 0x08 ->
+    check_data_count s;
     let x = at var s in
     zero_flag s;
     memory_init x
-  | 0x09 -> data_drop (at var s)
+  | 0x09 -> check_data_count s; data_drop (at var s)
   | 0x0a -> zero_flag s; zero_flag s; memory_copy
   | 0x0b -> zero_flag s; memory_fill
   | 0x0c ->
@@ -640,8 +645,16 @@ let passive_elem s =
     Func x
   | _ -> error s (pos s - 1) "invalid elem"
 
+let active_elem_segment s =
+  FuncRefType, vec (at active_elem) s
+
+let passive_elem_segment s =
+  let etype = elem_type s in
+  let init = vec (at passive_elem) s in
+  etype, init
+
 let table_segment s =
-  segment (vec (at active_elem)) (vec (at passive_elem)) s
+  segment active_elem_segment passive_elem_segment s
 
 let elem_section s =
   section `ElemSection (vec (at table_segment)) [] s
@@ -659,7 +672,10 @@ let data_section s =
 (* DataCount section *)
 
 let data_count_section s =
-  section `DataCountSection (opt vu32 true) None s
+  let contents s =
+    s.has_data_count := true;
+    opt vu32 true s
+  in section `DataCountSection contents None s
 
 
 (* Custom section *)
diff --git a/interpreter/binary/encode.ml b/interpreter/binary/encode.ml
index 7f8b7addf4..c983ca81c8 100644
--- a/interpreter/binary/encode.ml
+++ b/interpreter/binary/encode.ml
@@ -501,7 +501,9 @@ let encode m =
       | Func x -> u8 0xd2; var x; end_ ()
 
     let table_segment seg =
-      segment (vec active_elem) (vec passive_elem) seg
+      let active (_,init) = vec active_elem init in
+      let passive (etype,init) = elem_type etype; vec passive_elem init in
+      segment active passive seg
 
     let elem_section elems =
       section 9 (vec table_segment) elems (elems <> [])
diff --git a/interpreter/exec/eval.ml b/interpreter/exec/eval.ml
index 77082a893d..13220ae57b 100644
--- a/interpreter/exec/eval.ml
+++ b/interpreter/exec/eval.ml
@@ -445,7 +445,7 @@ let elems_list inst init =
 let create_elems (inst : module_inst) (seg : table_segment) : elems_inst =
   match seg.it with
   | Active _ -> ref None
-  | Passive init -> ref (Some (elems_list inst init))
+  | Passive (_,init) -> ref (Some (elems_list inst init))
 
 let create_data (inst : module_inst) (seg : memory_segment) : data_inst =
   match seg.it with
@@ -460,7 +460,7 @@ let init_func (inst : module_inst) (func : func_inst) =
 
 let init_table (inst : module_inst) (seg : table_segment) =
   match seg.it with
-  | Active {index; offset = const; init} ->
+  | Active {index; offset = const; init = (_,init)} ->
     let tab = table inst index in
     let offset = i32 (eval_const inst const) const.at in
     let elems = elems_list inst init in
diff --git a/interpreter/runtime/memory.ml b/interpreter/runtime/memory.ml
index 05bb4c3db1..2df2efd6c1 100644
--- a/interpreter/runtime/memory.ml
+++ b/interpreter/runtime/memory.ml
@@ -151,23 +151,24 @@ let check_str_bounds bs a =
 let check_bounds mem a = if I64.gt_u a (bound mem) then raise Bounds
 
 let init mem bs d s n =
-  let n' = Int64.of_int32 n in
-  let rec loop d s n =
-    if n > 0l then begin
-      check_str_bounds bs s;
-      let b = (Char.code bs.[Int64.to_int s]) in
-      store_byte mem d b;
+  let load_str_byte a =
+    try Char.code bs.[Int64.to_int a]
+    with _ -> raise Bounds
+  in let rec loop d s n =
+    if I32.gt_u n 0l then begin
+      store_byte mem d (load_str_byte s);
       loop (Int64.add d 1L) (Int64.add s 1L) (Int32.sub n 1l)
     end
   in loop d s n;
+  let n' = I64_convert.extend_i32_u n in
   check_bounds mem (Int64.add d n');
   check_str_bounds bs (Int64.add s n')
 
 let copy mem d s n =
-  let n' = Int64.of_int32 n in
-  let overlap = I64.lt_s Int64.(abs (sub d s)) n' in
+  let n' = I64_convert.extend_i32_u n in
+  let overlap = I64.lt_u Int64.(abs (sub d s)) n' in
   let rec loop d s n dx =
-    if n > 0l then begin
+    if I32.gt_u n 0l then begin
       store_byte mem d (load_byte mem s);
       loop (Int64.add d dx) (Int64.add s dx) (Int32.sub n 1l) dx
     end
@@ -180,9 +181,9 @@ let copy mem d s n =
 
 let fill mem a v n =
   let rec loop a n =
-    if n > 0l then begin
+    if I32.gt_u n 0l then begin
       store_byte mem a v;
       loop (Int64.add a 1L) (Int32.sub n 1l)
     end
   in loop a n;
-  check_bounds mem Int64.(add a (of_int32 n))
+  check_bounds mem (Int64.add a (I64_convert.extend_i32_u n))
diff --git a/interpreter/runtime/table.ml b/interpreter/runtime/table.ml
index d095533c20..b08a0e7188 100644
--- a/interpreter/runtime/table.ml
+++ b/interpreter/runtime/table.ml
@@ -64,9 +64,9 @@ let init tab es d s n =
   check_bounds tab (Int32.add d n)
 
 let copy tab d s n =
-  let overlap = I32.lt_s Int32.(abs (sub d s)) n in
+  let overlap = I32.lt_u Int32.(abs (sub d s)) n in
   let rec loop d s n dx =
-    if n > 0l then begin
+    if I32.gt_u n 0l then begin
       store tab d (load tab s);
       loop (Int32.add d dx) (Int32.add s dx) (Int32.sub n 1l) dx
     end
diff --git a/interpreter/syntax/ast.ml b/interpreter/syntax/ast.ml
index 4550b7759d..d33ed8a41b 100644
--- a/interpreter/syntax/ast.ml
+++ b/interpreter/syntax/ast.ml
@@ -150,7 +150,7 @@ and elem' =
   | Null
   | Func of var
 
-type table_segment = elem list segment
+type table_segment = (elem_type * (elem list)) segment
 type memory_segment = string segment
 
 
@@ -196,8 +196,8 @@ and module_' =
   memories : memory list;
   funcs : func list;
   start : var option;
-  elems : elem list segment list;
-  data : string segment list;
+  elems : table_segment list;
+  data : memory_segment list;
   imports : import list;
   exports : export list;
 }
diff --git a/interpreter/text/arrange.ml b/interpreter/text/arrange.ml
index 1217969b53..da39e9fba0 100644
--- a/interpreter/text/arrange.ml
+++ b/interpreter/text/arrange.ml
@@ -313,7 +313,9 @@ let passive_elem el =
   | Func x -> Node ("ref.func", [atom var x])
 
 let elems seg =
-  segment "elem" (list active_elem) (list passive_elem) seg
+  let active (_,init) = list active_elem init in
+  let passive (etype,init) = atom elem_type etype :: list passive_elem init in
+  segment "elem" active passive seg
 
 let data seg =
   segment "data" break_bytes break_bytes seg
diff --git a/interpreter/text/parser.mly b/interpreter/text/parser.mly
index 7abe892b69..f8871a2ea3 100644
--- a/interpreter/text/parser.mly
+++ b/interpreter/text/parser.mly
@@ -572,6 +572,7 @@ offset :
 elemref :
   | LPAR REF_NULL RPAR { let at = at () in fun c -> Null @@ at }
   | LPAR REF_FUNC var RPAR { let at = at () in fun c -> Func ($3 c func) @@ at }
+  | var { let at = at () in fun c -> Func ($1 c func) @@ at }
 
 passive_elemref_list :
   | /* empty */ { fun c -> [] }
@@ -583,25 +584,28 @@ active_elemref_list :
       fun c lookup -> List.map f ($1 c lookup) }
 
 elem :
-  | LPAR ELEM bind_var_opt PASSIVE passive_elemref_list RPAR
+  | LPAR ELEM bind_var_opt PASSIVE elem_type passive_elemref_list RPAR
     { let at = at () in
       fun c -> ignore ($3 c anon_elem bind_elem);
-      fun () -> Passive ($5 c) @@ at }
+      fun () -> Passive ($5, ($6 c)) @@ at }
   | LPAR ELEM bind_var var offset active_elemref_list RPAR
     { let at = at () in
       fun c -> ignore (bind_elem c $3);
       fun () ->
-      Active {index = $4 c table; offset = $5 c; init = $6 c func} @@ at }
+      let init = FuncRefType, ($6 c func) in
+      Active {index = $4 c table; offset = $5 c; init} @@ at }
   | LPAR ELEM var offset active_elemref_list RPAR
     { let at = at () in
       fun c -> ignore (anon_elem c);
       fun () ->
-      Active {index = $3 c table; offset = $4 c; init = $5 c func} @@ at }
+      let init = FuncRefType, $5 c func in
+      Active {index = $3 c table; offset = $4 c; init} @@ at }
   | LPAR ELEM offset active_elemref_list RPAR  /* Sugar */
     { let at = at () in
       fun c -> ignore (anon_elem c);
       fun () ->
-      Active {index = 0l @@ at; offset = $3 c; init = $4 c func} @@ at }
+      let init = FuncRefType, $4 c func in
+      Active {index = 0l @@ at; offset = $3 c; init} @@ at }
 
 table :
   | LPAR TABLE bind_var_opt table_fields RPAR
@@ -623,7 +627,8 @@ table_fields :
   | elem_type LPAR ELEM active_elemref_list RPAR  /* Sugar */
     { fun c x at ->
       let offset = [i32_const (0l @@ at) @@ at] @@ at in
-      let init = $4 c func in let size = Int32.of_int (List.length init) in
+      let init' = $4 c func in let size = Int32.of_int (List.length init') in
+      let init = FuncRefType, init' in
       [{ttype = TableType ({min = size; max = Some size}, $1)} @@ at],
       [Active {index = x; offset; init} @@ at],
       [], [] }
diff --git a/interpreter/valid/valid.ml b/interpreter/valid/valid.ml
index ced695bf8f..955e2ce113 100644
--- a/interpreter/valid/valid.ml
+++ b/interpreter/valid/valid.ml
@@ -431,11 +431,11 @@ let check_elemref (c : context) (el : elem) =
 
 let check_elem (c : context) (seg : table_segment) =
   match seg.it with
-  | Active {index; offset; init} ->
+  | Active {index; offset; init = (_,init)} ->
     ignore (table c index);
     check_const c offset I32Type;
     List.iter (check_elemref c) init
-  | Passive init ->
+  | Passive (etype,init) ->
     List.iter (check_elemref c) init
 
 let check_data (c : context) (seg : memory_segment) =
diff --git a/test/core/bulk.wast b/test/core/bulk.wast
index 492b004094..fd4194c289 100644
--- a/test/core/bulk.wast
+++ b/test/core/bulk.wast
@@ -5,7 +5,7 @@
 
 (module
   (table 3 funcref)
-  (elem passive (ref.func 0) (ref.null) (ref.func 1))
+  (elem passive funcref (ref.func 0) (ref.null) (ref.func 1))
   (func)
   (func))
 
@@ -182,7 +182,7 @@
 ;; table.init
 (module
   (table 3 funcref)
-  (elem passive
+  (elem passive funcref
     (ref.func $zero) (ref.func $one) (ref.func $zero) (ref.func $one))
 
   (func $zero (result i32) (i32.const 0))
@@ -227,7 +227,7 @@
 (module
   (table 1 funcref)
   (func $f)
-  (elem $p passive (ref.func $f))
+  (elem $p passive funcref (ref.func $f))
   (elem $a 0 (i32.const 0) $f)
 
   (func (export "drop_passive") (elem.drop $p))

From 72ada2bd116b3b0e1977fccb829dcc576d5d4124 Mon Sep 17 00:00:00 2001
From: Lars T Hansen 
Date: Tue, 5 Mar 2019 23:31:29 +0100
Subject: [PATCH 066/199] Bulk memory operations test cases (#67)

* Initial test generation code

* Cleanup

* Parameterize

* Cleanup

* Rename

* More tests

* Table copy

* table.init

* More tests

* More memory.init tests

* table.copy

* data.drop and elem.drop

* Updates for the reference interpreter

* Partial memory.fill

* Comment out test for reference interpreter

* Partial OOB for memory_init

* Partial table.init

* Partial OOB for table.copy

* Some binary tests

* Uncontroversial updates

* Test suite updates after discussion with binji

* Binary tests for elem segments

* Fix test bug, update comments
---
 test/core/binary.wast             |  155 +
 test/core/memory_copy.wast        | 5755 +++++++++++++++++++++++++++++
 test/core/memory_fill.wast        |  749 ++++
 test/core/memory_init.wast        |  947 +++++
 test/core/table_copy.wast         | 1448 ++++++++
 test/core/table_init.wast         | 1607 ++++++++
 test/meta/Makefile                |   27 +
 test/meta/README.md               |    1 +
 test/meta/common.js               |   36 +
 test/meta/generate_memory_copy.js |  764 ++++
 test/meta/generate_memory_fill.js |  156 +
 test/meta/generate_memory_init.js |  259 ++
 test/meta/generate_table_copy.js  |  319 ++
 test/meta/generate_table_init.js  |  320 ++
 14 files changed, 12543 insertions(+)
 create mode 100644 test/core/memory_copy.wast
 create mode 100644 test/core/memory_fill.wast
 create mode 100644 test/core/memory_init.wast
 create mode 100644 test/core/table_copy.wast
 create mode 100644 test/core/table_init.wast
 create mode 100644 test/meta/Makefile
 create mode 100644 test/meta/README.md
 create mode 100644 test/meta/common.js
 create mode 100644 test/meta/generate_memory_copy.js
 create mode 100644 test/meta/generate_memory_fill.js
 create mode 100644 test/meta/generate_memory_init.js
 create mode 100644 test/meta/generate_table_copy.js
 create mode 100644 test/meta/generate_table_init.js

diff --git a/test/core/binary.wast b/test/core/binary.wast
index 7ec8c46089..711bfbc64b 100644
--- a/test/core/binary.wast
+++ b/test/core/binary.wast
@@ -641,3 +641,158 @@
   "\00asm" "\01\00\00\00"
   "\0a\01\00"  ;; Code section with 0 functions
 )
+
+;; Fewer passive segments than datacount
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\0c\01\03"                   ;; Datacount section with value "3"
+    "\0b\05\02"                   ;; Data section with two entries
+    "\01\00"                      ;; Passive data section
+    "\01\00")                     ;; Passive data section
+  "data count and data section have inconsistent lengths")
+
+;; More passive segments than datacount
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+    "\0c\01\01"                   ;; Datacount section with value "1"
+    "\0b\05\02"                   ;; Data section with two entries
+    "\01\00"                      ;; Passive data section
+    "\01\00")                     ;; Passive data section
+  "data count and data section have inconsistent lengths")
+
+;; memory.init requires a datacount section
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+
+    "\01\04\01\60\00\00"       ;; Type section
+    "\03\02\01\00"             ;; Function section
+    "\05\03\01\00\00"          ;; Memory section
+    "\0a\0e\01"                ;; Code section
+
+    ;; function 0
+    "\0c\00"
+    "\41\00"                   ;; zero args
+    "\41\00"
+    "\41\00"
+    "\fc\08\00\00"             ;; memory.init
+    "\0b")                     ;; end
+  "data count section required")
+
+;; data.drop requires a datacount section
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+
+    "\01\04\01\60\00\00"       ;; Type section
+    "\03\02\01\00"             ;; Function section
+    "\05\03\01\00\00"          ;; Memory section
+    "\0a\07\01"                ;; Code section
+
+    ;; function 0
+    "\05\00"
+    "\fc\09\00"                ;; data.drop
+    "\0b")                     ;; end
+  "data count section required")
+
+;; passive element segment containing opcode other than ref.func or ref.null
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+
+    "\01\04\01\60\00\00"       ;; Type section
+
+    "\03\02\01\00"             ;; Function section
+
+    "\04\04\01"                ;; Table section with 1 entry
+    "\70\00\00"                ;; no max, minimum 0, funcref
+
+    "\05\03\01\00\00"          ;; Memory section
+
+    "\09\07\01"                ;; Element section with one segment
+    "\01\70"                   ;; Passive, funcref
+    "\01"                      ;; 1 element
+    "\d3\00\0b"                ;; bad opcode, index 0, end
+
+    "\0a\04\01"                ;; Code section
+
+    ;; function 0
+    "\02\00"
+    "\0b")                     ;; end
+  "invalid elem")
+
+;; passive element segment containing type other than funcref
+(assert_malformed
+  (module binary
+    "\00asm" "\01\00\00\00"
+
+    "\01\04\01\60\00\00"       ;; Type section
+
+    "\03\02\01\00"             ;; Function section
+
+    "\04\04\01"                ;; Table section with 1 entry
+    "\70\00\00"                ;; no max, minimum 0, funcref
+
+    "\05\03\01\00\00"          ;; Memory section
+
+    "\09\07\01"                ;; Element section with one segment
+    "\01\7f"                   ;; Passive, i32
+    "\01"                      ;; 1 element
+    "\d2\00\0b"                ;; ref.func, index 0, end
+
+    "\0a\04\01"                ;; Code section
+
+    ;; function 0
+    "\02\00"
+    "\0b")                     ;; end
+  "invalid element type")
+
+;; passive element segment containing opcode ref.func
+(module binary
+  "\00asm" "\01\00\00\00"
+
+  "\01\04\01\60\00\00"       ;; Type section
+
+  "\03\02\01\00"             ;; Function section
+
+  "\04\04\01"                ;; Table section with 1 entry
+  "\70\00\00"                ;; no max, minimum 0, funcref
+
+  "\05\03\01\00\00"          ;; Memory section
+
+  "\09\07\01"                ;; Element section with one segment
+  "\01\70"                   ;; Passive, funcref
+  "\01"                      ;; 1 element
+  "\d2\00\0b"                ;; ref.func, index 0, end
+
+  "\0a\04\01"                ;; Code section
+
+  ;; function 0
+  "\02\00"
+  "\0b")                     ;; end
+
+;; passive element segment containing opcode ref.null
+(module binary
+  "\00asm" "\01\00\00\00"
+
+  "\01\04\01\60\00\00"       ;; Type section
+
+  "\03\02\01\00"             ;; Function section
+
+  "\04\04\01"                ;; Table section with 1 entry
+  "\70\00\00"                ;; no max, minimum 0, funcref
+
+  "\05\03\01\00\00"          ;; Memory section
+
+  "\09\06\01"                ;; Element section with one segment
+  "\01\70"                   ;; Passive, funcref
+  "\01"                      ;; 1 element
+  "\d0\0b"                   ;; ref.null, end
+
+  "\0a\04\01"                ;; Code section
+
+  ;; function 0
+  "\02\00"
+  "\0b")                     ;; end
diff --git a/test/core/memory_copy.wast b/test/core/memory_copy.wast
new file mode 100644
index 0000000000..e9ea04a9e1
--- /dev/null
+++ b/test/core/memory_copy.wast
@@ -0,0 +1,5755 @@
+;;
+;; Generated by ../meta/generate_memory_copy.js
+;;
+
+(module
+  (memory (export "memory0") 1 1)
+  (data (i32.const 2) "\03\01\04\01")
+  (data (i32.const 12) "\07\05\02\03\06")
+  (func (export "test")
+    nop)
+  (func (export "load8_u") (param i32) (result i32)
+    (i32.load8_u (local.get 0))))
+
+(invoke "test")
+
+(assert_return (invoke "load8_u" (i32.const 0)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 1)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 2)) (i32.const 3))
+(assert_return (invoke "load8_u" (i32.const 3)) (i32.const 1))
+(assert_return (invoke "load8_u" (i32.const 4)) (i32.const 4))
+(assert_return (invoke "load8_u" (i32.const 5)) (i32.const 1))
+(assert_return (invoke "load8_u" (i32.const 6)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 7)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 8)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 9)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 10)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 11)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 12)) (i32.const 7))
+(assert_return (invoke "load8_u" (i32.const 13)) (i32.const 5))
+(assert_return (invoke "load8_u" (i32.const 14)) (i32.const 2))
+(assert_return (invoke "load8_u" (i32.const 15)) (i32.const 3))
+(assert_return (invoke "load8_u" (i32.const 16)) (i32.const 6))
+(assert_return (invoke "load8_u" (i32.const 17)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 18)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 19)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 20)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 21)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 22)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 23)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 24)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 25)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 26)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 27)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 28)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 29)) (i32.const 0))
+
+(module
+  (memory (export "memory0") 1 1)
+  (data (i32.const 2) "\03\01\04\01")
+  (data (i32.const 12) "\07\05\02\03\06")
+  (func (export "test")
+    (memory.copy (i32.const 13) (i32.const 2) (i32.const 3)))
+  (func (export "load8_u") (param i32) (result i32)
+    (i32.load8_u (local.get 0))))
+
+(invoke "test")
+
+(assert_return (invoke "load8_u" (i32.const 0)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 1)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 2)) (i32.const 3))
+(assert_return (invoke "load8_u" (i32.const 3)) (i32.const 1))
+(assert_return (invoke "load8_u" (i32.const 4)) (i32.const 4))
+(assert_return (invoke "load8_u" (i32.const 5)) (i32.const 1))
+(assert_return (invoke "load8_u" (i32.const 6)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 7)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 8)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 9)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 10)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 11)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 12)) (i32.const 7))
+(assert_return (invoke "load8_u" (i32.const 13)) (i32.const 3))
+(assert_return (invoke "load8_u" (i32.const 14)) (i32.const 1))
+(assert_return (invoke "load8_u" (i32.const 15)) (i32.const 4))
+(assert_return (invoke "load8_u" (i32.const 16)) (i32.const 6))
+(assert_return (invoke "load8_u" (i32.const 17)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 18)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 19)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 20)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 21)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 22)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 23)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 24)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 25)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 26)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 27)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 28)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 29)) (i32.const 0))
+
+(module
+  (memory (export "memory0") 1 1)
+  (data (i32.const 2) "\03\01\04\01")
+  (data (i32.const 12) "\07\05\02\03\06")
+  (func (export "test")
+    (memory.copy (i32.const 25) (i32.const 15) (i32.const 2)))
+  (func (export "load8_u") (param i32) (result i32)
+    (i32.load8_u (local.get 0))))
+
+(invoke "test")
+
+(assert_return (invoke "load8_u" (i32.const 0)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 1)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 2)) (i32.const 3))
+(assert_return (invoke "load8_u" (i32.const 3)) (i32.const 1))
+(assert_return (invoke "load8_u" (i32.const 4)) (i32.const 4))
+(assert_return (invoke "load8_u" (i32.const 5)) (i32.const 1))
+(assert_return (invoke "load8_u" (i32.const 6)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 7)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 8)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 9)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 10)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 11)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 12)) (i32.const 7))
+(assert_return (invoke "load8_u" (i32.const 13)) (i32.const 5))
+(assert_return (invoke "load8_u" (i32.const 14)) (i32.const 2))
+(assert_return (invoke "load8_u" (i32.const 15)) (i32.const 3))
+(assert_return (invoke "load8_u" (i32.const 16)) (i32.const 6))
+(assert_return (invoke "load8_u" (i32.const 17)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 18)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 19)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 20)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 21)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 22)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 23)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 24)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 25)) (i32.const 3))
+(assert_return (invoke "load8_u" (i32.const 26)) (i32.const 6))
+(assert_return (invoke "load8_u" (i32.const 27)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 28)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 29)) (i32.const 0))
+
+(module
+  (memory (export "memory0") 1 1)
+  (data (i32.const 2) "\03\01\04\01")
+  (data (i32.const 12) "\07\05\02\03\06")
+  (func (export "test")
+    (memory.copy (i32.const 13) (i32.const 25) (i32.const 3)))
+  (func (export "load8_u") (param i32) (result i32)
+    (i32.load8_u (local.get 0))))
+
+(invoke "test")
+
+(assert_return (invoke "load8_u" (i32.const 0)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 1)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 2)) (i32.const 3))
+(assert_return (invoke "load8_u" (i32.const 3)) (i32.const 1))
+(assert_return (invoke "load8_u" (i32.const 4)) (i32.const 4))
+(assert_return (invoke "load8_u" (i32.const 5)) (i32.const 1))
+(assert_return (invoke "load8_u" (i32.const 6)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 7)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 8)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 9)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 10)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 11)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 12)) (i32.const 7))
+(assert_return (invoke "load8_u" (i32.const 13)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 14)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 15)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 16)) (i32.const 6))
+(assert_return (invoke "load8_u" (i32.const 17)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 18)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 19)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 20)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 21)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 22)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 23)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 24)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 25)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 26)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 27)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 28)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 29)) (i32.const 0))
+
+(module
+  (memory (export "memory0") 1 1)
+  (data (i32.const 2) "\03\01\04\01")
+  (data (i32.const 12) "\07\05\02\03\06")
+  (func (export "test")
+    (memory.copy (i32.const 20) (i32.const 22) (i32.const 4)))
+  (func (export "load8_u") (param i32) (result i32)
+    (i32.load8_u (local.get 0))))
+
+(invoke "test")
+
+(assert_return (invoke "load8_u" (i32.const 0)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 1)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 2)) (i32.const 3))
+(assert_return (invoke "load8_u" (i32.const 3)) (i32.const 1))
+(assert_return (invoke "load8_u" (i32.const 4)) (i32.const 4))
+(assert_return (invoke "load8_u" (i32.const 5)) (i32.const 1))
+(assert_return (invoke "load8_u" (i32.const 6)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 7)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 8)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 9)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 10)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 11)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 12)) (i32.const 7))
+(assert_return (invoke "load8_u" (i32.const 13)) (i32.const 5))
+(assert_return (invoke "load8_u" (i32.const 14)) (i32.const 2))
+(assert_return (invoke "load8_u" (i32.const 15)) (i32.const 3))
+(assert_return (invoke "load8_u" (i32.const 16)) (i32.const 6))
+(assert_return (invoke "load8_u" (i32.const 17)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 18)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 19)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 20)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 21)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 22)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 23)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 24)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 25)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 26)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 27)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 28)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 29)) (i32.const 0))
+
+(module
+  (memory (export "memory0") 1 1)
+  (data (i32.const 2) "\03\01\04\01")
+  (data (i32.const 12) "\07\05\02\03\06")
+  (func (export "test")
+    (memory.copy (i32.const 25) (i32.const 1) (i32.const 3)))
+  (func (export "load8_u") (param i32) (result i32)
+    (i32.load8_u (local.get 0))))
+
+(invoke "test")
+
+(assert_return (invoke "load8_u" (i32.const 0)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 1)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 2)) (i32.const 3))
+(assert_return (invoke "load8_u" (i32.const 3)) (i32.const 1))
+(assert_return (invoke "load8_u" (i32.const 4)) (i32.const 4))
+(assert_return (invoke "load8_u" (i32.const 5)) (i32.const 1))
+(assert_return (invoke "load8_u" (i32.const 6)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 7)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 8)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 9)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 10)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 11)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 12)) (i32.const 7))
+(assert_return (invoke "load8_u" (i32.const 13)) (i32.const 5))
+(assert_return (invoke "load8_u" (i32.const 14)) (i32.const 2))
+(assert_return (invoke "load8_u" (i32.const 15)) (i32.const 3))
+(assert_return (invoke "load8_u" (i32.const 16)) (i32.const 6))
+(assert_return (invoke "load8_u" (i32.const 17)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 18)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 19)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 20)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 21)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 22)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 23)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 24)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 25)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 26)) (i32.const 3))
+(assert_return (invoke "load8_u" (i32.const 27)) (i32.const 1))
+(assert_return (invoke "load8_u" (i32.const 28)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 29)) (i32.const 0))
+
+(module
+  (memory (export "memory0") 1 1)
+  (data (i32.const 2) "\03\01\04\01")
+  (data (i32.const 12) "\07\05\02\03\06")
+  (func (export "test")
+    (memory.copy (i32.const 10) (i32.const 12) (i32.const 7)))
+  (func (export "load8_u") (param i32) (result i32)
+    (i32.load8_u (local.get 0))))
+
+(invoke "test")
+
+(assert_return (invoke "load8_u" (i32.const 0)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 1)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 2)) (i32.const 3))
+(assert_return (invoke "load8_u" (i32.const 3)) (i32.const 1))
+(assert_return (invoke "load8_u" (i32.const 4)) (i32.const 4))
+(assert_return (invoke "load8_u" (i32.const 5)) (i32.const 1))
+(assert_return (invoke "load8_u" (i32.const 6)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 7)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 8)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 9)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 10)) (i32.const 7))
+(assert_return (invoke "load8_u" (i32.const 11)) (i32.const 5))
+(assert_return (invoke "load8_u" (i32.const 12)) (i32.const 2))
+(assert_return (invoke "load8_u" (i32.const 13)) (i32.const 3))
+(assert_return (invoke "load8_u" (i32.const 14)) (i32.const 6))
+(assert_return (invoke "load8_u" (i32.const 15)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 16)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 17)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 18)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 19)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 20)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 21)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 22)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 23)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 24)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 25)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 26)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 27)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 28)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 29)) (i32.const 0))
+
+(module
+  (memory (export "memory0") 1 1)
+  (data (i32.const 2) "\03\01\04\01")
+  (data (i32.const 12) "\07\05\02\03\06")
+  (func (export "test")
+    (memory.copy (i32.const 12) (i32.const 10) (i32.const 7)))
+  (func (export "load8_u") (param i32) (result i32)
+    (i32.load8_u (local.get 0))))
+
+(invoke "test")
+
+(assert_return (invoke "load8_u" (i32.const 0)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 1)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 2)) (i32.const 3))
+(assert_return (invoke "load8_u" (i32.const 3)) (i32.const 1))
+(assert_return (invoke "load8_u" (i32.const 4)) (i32.const 4))
+(assert_return (invoke "load8_u" (i32.const 5)) (i32.const 1))
+(assert_return (invoke "load8_u" (i32.const 6)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 7)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 8)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 9)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 10)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 11)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 12)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 13)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 14)) (i32.const 7))
+(assert_return (invoke "load8_u" (i32.const 15)) (i32.const 5))
+(assert_return (invoke "load8_u" (i32.const 16)) (i32.const 2))
+(assert_return (invoke "load8_u" (i32.const 17)) (i32.const 3))
+(assert_return (invoke "load8_u" (i32.const 18)) (i32.const 6))
+(assert_return (invoke "load8_u" (i32.const 19)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 20)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 21)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 22)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 23)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 24)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 25)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 26)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 27)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 28)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 29)) (i32.const 0))
+
+(module
+  (memory (export "mem") 1 1 )
+  (data (i32.const 0) "\00\01\02\03\04\05\06\07\08\09\0a\0b\0c\0d\0e\0f\10\11\12\13")
+  (func (export "run") (param $targetOffs i32) (param $srcOffs i32) (param $len i32)
+    (memory.copy (local.get $targetOffs) (local.get $srcOffs) (local.get $len)))
+  (func (export "load8_u") (param i32) (result i32)
+    (i32.load8_u (local.get 0))))
+
+(assert_trap (invoke "run" (i32.const 65516) (i32.const 0) (i32.const 40))
+             "out of bounds")
+
+(assert_return (invoke "load8_u" (i32.const 0)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 1)) (i32.const 1))
+(assert_return (invoke "load8_u" (i32.const 2)) (i32.const 2))
+(assert_return (invoke "load8_u" (i32.const 3)) (i32.const 3))
+(assert_return (invoke "load8_u" (i32.const 4)) (i32.const 4))
+(assert_return (invoke "load8_u" (i32.const 5)) (i32.const 5))
+(assert_return (invoke "load8_u" (i32.const 6)) (i32.const 6))
+(assert_return (invoke "load8_u" (i32.const 7)) (i32.const 7))
+(assert_return (invoke "load8_u" (i32.const 8)) (i32.const 8))
+(assert_return (invoke "load8_u" (i32.const 9)) (i32.const 9))
+(assert_return (invoke "load8_u" (i32.const 10)) (i32.const 10))
+(assert_return (invoke "load8_u" (i32.const 11)) (i32.const 11))
+(assert_return (invoke "load8_u" (i32.const 12)) (i32.const 12))
+(assert_return (invoke "load8_u" (i32.const 13)) (i32.const 13))
+(assert_return (invoke "load8_u" (i32.const 14)) (i32.const 14))
+(assert_return (invoke "load8_u" (i32.const 15)) (i32.const 15))
+(assert_return (invoke "load8_u" (i32.const 16)) (i32.const 16))
+(assert_return (invoke "load8_u" (i32.const 17)) (i32.const 17))
+(assert_return (invoke "load8_u" (i32.const 18)) (i32.const 18))
+(assert_return (invoke "load8_u" (i32.const 19)) (i32.const 19))
+(assert_return (invoke "load8_u" (i32.const 218)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 417)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 616)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 815)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 1014)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 1213)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 1412)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 1611)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 1810)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 2009)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 2208)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 2407)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 2606)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 2805)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 3004)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 3203)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 3402)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 3601)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 3800)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 3999)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 4198)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 4397)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 4596)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 4795)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 4994)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 5193)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 5392)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 5591)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 5790)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 5989)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 6188)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 6387)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 6586)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 6785)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 6984)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 7183)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 7382)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 7581)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 7780)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 7979)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 8178)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 8377)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 8576)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 8775)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 8974)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 9173)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 9372)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 9571)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 9770)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 9969)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 10168)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 10367)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 10566)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 10765)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 10964)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 11163)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 11362)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 11561)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 11760)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 11959)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 12158)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 12357)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 12556)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 12755)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 12954)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 13153)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 13352)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 13551)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 13750)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 13949)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 14148)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 14347)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 14546)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 14745)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 14944)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 15143)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 15342)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 15541)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 15740)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 15939)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 16138)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 16337)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 16536)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 16735)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 16934)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 17133)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 17332)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 17531)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 17730)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 17929)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 18128)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 18327)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 18526)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 18725)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 18924)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 19123)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 19322)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 19521)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 19720)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 19919)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 20118)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 20317)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 20516)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 20715)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 20914)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 21113)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 21312)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 21511)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 21710)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 21909)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 22108)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 22307)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 22506)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 22705)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 22904)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 23103)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 23302)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 23501)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 23700)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 23899)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 24098)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 24297)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 24496)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 24695)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 24894)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 25093)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 25292)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 25491)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 25690)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 25889)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 26088)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 26287)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 26486)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 26685)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 26884)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 27083)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 27282)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 27481)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 27680)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 27879)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 28078)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 28277)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 28476)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 28675)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 28874)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 29073)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 29272)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 29471)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 29670)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 29869)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 30068)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 30267)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 30466)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 30665)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 30864)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 31063)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 31262)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 31461)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 31660)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 31859)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 32058)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 32257)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 32456)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 32655)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 32854)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 33053)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 33252)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 33451)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 33650)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 33849)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 34048)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 34247)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 34446)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 34645)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 34844)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 35043)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 35242)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 35441)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 35640)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 35839)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 36038)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 36237)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 36436)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 36635)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 36834)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 37033)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 37232)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 37431)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 37630)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 37829)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 38028)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 38227)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 38426)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 38625)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 38824)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 39023)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 39222)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 39421)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 39620)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 39819)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 40018)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 40217)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 40416)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 40615)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 40814)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 41013)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 41212)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 41411)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 41610)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 41809)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 42008)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 42207)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 42406)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 42605)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 42804)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 43003)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 43202)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 43401)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 43600)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 43799)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 43998)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 44197)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 44396)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 44595)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 44794)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 44993)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 45192)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 45391)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 45590)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 45789)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 45988)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 46187)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 46386)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 46585)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 46784)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 46983)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 47182)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 47381)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 47580)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 47779)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 47978)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 48177)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 48376)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 48575)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 48774)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 48973)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 49172)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 49371)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 49570)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 49769)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 49968)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 50167)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 50366)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 50565)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 50764)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 50963)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 51162)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 51361)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 51560)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 51759)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 51958)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 52157)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 52356)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 52555)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 52754)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 52953)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 53152)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 53351)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 53550)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 53749)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 53948)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 54147)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 54346)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 54545)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 54744)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 54943)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 55142)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 55341)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 55540)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 55739)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 55938)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 56137)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 56336)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 56535)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 56734)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 56933)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 57132)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 57331)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 57530)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 57729)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 57928)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 58127)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 58326)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 58525)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 58724)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 58923)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 59122)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 59321)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 59520)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 59719)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 59918)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 60117)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 60316)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 60515)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 60714)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 60913)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 61112)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 61311)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 61510)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 61709)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 61908)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 62107)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 62306)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 62505)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 62704)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 62903)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 63102)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 63301)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 63500)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 63699)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 63898)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 64097)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 64296)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 64495)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 64694)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 64893)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 65092)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 65291)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 65490)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 65516)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 65517)) (i32.const 1))
+(assert_return (invoke "load8_u" (i32.const 65518)) (i32.const 2))
+(assert_return (invoke "load8_u" (i32.const 65519)) (i32.const 3))
+(assert_return (invoke "load8_u" (i32.const 65520)) (i32.const 4))
+(assert_return (invoke "load8_u" (i32.const 65521)) (i32.const 5))
+(assert_return (invoke "load8_u" (i32.const 65522)) (i32.const 6))
+(assert_return (invoke "load8_u" (i32.const 65523)) (i32.const 7))
+(assert_return (invoke "load8_u" (i32.const 65524)) (i32.const 8))
+(assert_return (invoke "load8_u" (i32.const 65525)) (i32.const 9))
+(assert_return (invoke "load8_u" (i32.const 65526)) (i32.const 10))
+(assert_return (invoke "load8_u" (i32.const 65527)) (i32.const 11))
+(assert_return (invoke "load8_u" (i32.const 65528)) (i32.const 12))
+(assert_return (invoke "load8_u" (i32.const 65529)) (i32.const 13))
+(assert_return (invoke "load8_u" (i32.const 65530)) (i32.const 14))
+(assert_return (invoke "load8_u" (i32.const 65531)) (i32.const 15))
+(assert_return (invoke "load8_u" (i32.const 65532)) (i32.const 16))
+(assert_return (invoke "load8_u" (i32.const 65533)) (i32.const 17))
+(assert_return (invoke "load8_u" (i32.const 65534)) (i32.const 18))
+(assert_return (invoke "load8_u" (i32.const 65535)) (i32.const 19))
+
+(module
+  (memory (export "mem") 1 1 )
+  (data (i32.const 0) "\00\01\02\03\04\05\06\07\08\09\0a\0b\0c\0d\0e\0f\10\11\12\13\14")
+  (func (export "run") (param $targetOffs i32) (param $srcOffs i32) (param $len i32)
+    (memory.copy (local.get $targetOffs) (local.get $srcOffs) (local.get $len)))
+  (func (export "load8_u") (param i32) (result i32)
+    (i32.load8_u (local.get 0))))
+
+(assert_trap (invoke "run" (i32.const 65515) (i32.const 0) (i32.const 39))
+             "out of bounds")
+
+(assert_return (invoke "load8_u" (i32.const 0)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 1)) (i32.const 1))
+(assert_return (invoke "load8_u" (i32.const 2)) (i32.const 2))
+(assert_return (invoke "load8_u" (i32.const 3)) (i32.const 3))
+(assert_return (invoke "load8_u" (i32.const 4)) (i32.const 4))
+(assert_return (invoke "load8_u" (i32.const 5)) (i32.const 5))
+(assert_return (invoke "load8_u" (i32.const 6)) (i32.const 6))
+(assert_return (invoke "load8_u" (i32.const 7)) (i32.const 7))
+(assert_return (invoke "load8_u" (i32.const 8)) (i32.const 8))
+(assert_return (invoke "load8_u" (i32.const 9)) (i32.const 9))
+(assert_return (invoke "load8_u" (i32.const 10)) (i32.const 10))
+(assert_return (invoke "load8_u" (i32.const 11)) (i32.const 11))
+(assert_return (invoke "load8_u" (i32.const 12)) (i32.const 12))
+(assert_return (invoke "load8_u" (i32.const 13)) (i32.const 13))
+(assert_return (invoke "load8_u" (i32.const 14)) (i32.const 14))
+(assert_return (invoke "load8_u" (i32.const 15)) (i32.const 15))
+(assert_return (invoke "load8_u" (i32.const 16)) (i32.const 16))
+(assert_return (invoke "load8_u" (i32.const 17)) (i32.const 17))
+(assert_return (invoke "load8_u" (i32.const 18)) (i32.const 18))
+(assert_return (invoke "load8_u" (i32.const 19)) (i32.const 19))
+(assert_return (invoke "load8_u" (i32.const 20)) (i32.const 20))
+(assert_return (invoke "load8_u" (i32.const 219)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 418)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 617)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 816)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 1015)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 1214)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 1413)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 1612)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 1811)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 2010)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 2209)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 2408)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 2607)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 2806)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 3005)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 3204)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 3403)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 3602)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 3801)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 4000)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 4199)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 4398)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 4597)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 4796)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 4995)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 5194)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 5393)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 5592)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 5791)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 5990)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 6189)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 6388)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 6587)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 6786)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 6985)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 7184)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 7383)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 7582)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 7781)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 7980)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 8179)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 8378)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 8577)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 8776)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 8975)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 9174)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 9373)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 9572)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 9771)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 9970)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 10169)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 10368)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 10567)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 10766)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 10965)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 11164)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 11363)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 11562)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 11761)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 11960)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 12159)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 12358)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 12557)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 12756)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 12955)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 13154)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 13353)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 13552)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 13751)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 13950)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 14149)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 14348)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 14547)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 14746)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 14945)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 15144)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 15343)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 15542)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 15741)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 15940)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 16139)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 16338)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 16537)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 16736)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 16935)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 17134)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 17333)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 17532)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 17731)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 17930)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 18129)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 18328)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 18527)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 18726)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 18925)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 19124)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 19323)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 19522)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 19721)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 19920)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 20119)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 20318)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 20517)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 20716)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 20915)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 21114)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 21313)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 21512)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 21711)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 21910)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 22109)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 22308)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 22507)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 22706)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 22905)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 23104)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 23303)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 23502)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 23701)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 23900)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 24099)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 24298)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 24497)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 24696)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 24895)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 25094)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 25293)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 25492)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 25691)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 25890)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 26089)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 26288)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 26487)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 26686)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 26885)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 27084)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 27283)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 27482)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 27681)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 27880)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 28079)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 28278)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 28477)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 28676)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 28875)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 29074)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 29273)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 29472)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 29671)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 29870)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 30069)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 30268)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 30467)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 30666)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 30865)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 31064)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 31263)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 31462)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 31661)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 31860)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 32059)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 32258)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 32457)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 32656)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 32855)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 33054)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 33253)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 33452)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 33651)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 33850)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 34049)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 34248)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 34447)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 34646)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 34845)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 35044)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 35243)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 35442)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 35641)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 35840)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 36039)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 36238)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 36437)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 36636)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 36835)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 37034)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 37233)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 37432)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 37631)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 37830)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 38029)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 38228)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 38427)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 38626)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 38825)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 39024)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 39223)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 39422)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 39621)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 39820)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 40019)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 40218)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 40417)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 40616)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 40815)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 41014)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 41213)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 41412)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 41611)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 41810)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 42009)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 42208)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 42407)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 42606)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 42805)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 43004)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 43203)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 43402)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 43601)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 43800)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 43999)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 44198)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 44397)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 44596)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 44795)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 44994)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 45193)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 45392)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 45591)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 45790)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 45989)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 46188)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 46387)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 46586)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 46785)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 46984)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 47183)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 47382)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 47581)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 47780)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 47979)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 48178)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 48377)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 48576)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 48775)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 48974)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 49173)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 49372)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 49571)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 49770)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 49969)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 50168)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 50367)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 50566)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 50765)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 50964)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 51163)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 51362)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 51561)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 51760)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 51959)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 52158)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 52357)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 52556)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 52755)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 52954)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 53153)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 53352)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 53551)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 53750)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 53949)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 54148)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 54347)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 54546)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 54745)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 54944)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 55143)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 55342)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 55541)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 55740)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 55939)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 56138)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 56337)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 56536)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 56735)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 56934)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 57133)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 57332)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 57531)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 57730)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 57929)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 58128)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 58327)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 58526)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 58725)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 58924)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 59123)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 59322)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 59521)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 59720)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 59919)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 60118)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 60317)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 60516)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 60715)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 60914)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 61113)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 61312)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 61511)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 61710)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 61909)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 62108)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 62307)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 62506)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 62705)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 62904)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 63103)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 63302)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 63501)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 63700)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 63899)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 64098)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 64297)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 64496)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 64695)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 64894)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 65093)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 65292)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 65491)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 65515)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 65516)) (i32.const 1))
+(assert_return (invoke "load8_u" (i32.const 65517)) (i32.const 2))
+(assert_return (invoke "load8_u" (i32.const 65518)) (i32.const 3))
+(assert_return (invoke "load8_u" (i32.const 65519)) (i32.const 4))
+(assert_return (invoke "load8_u" (i32.const 65520)) (i32.const 5))
+(assert_return (invoke "load8_u" (i32.const 65521)) (i32.const 6))
+(assert_return (invoke "load8_u" (i32.const 65522)) (i32.const 7))
+(assert_return (invoke "load8_u" (i32.const 65523)) (i32.const 8))
+(assert_return (invoke "load8_u" (i32.const 65524)) (i32.const 9))
+(assert_return (invoke "load8_u" (i32.const 65525)) (i32.const 10))
+(assert_return (invoke "load8_u" (i32.const 65526)) (i32.const 11))
+(assert_return (invoke "load8_u" (i32.const 65527)) (i32.const 12))
+(assert_return (invoke "load8_u" (i32.const 65528)) (i32.const 13))
+(assert_return (invoke "load8_u" (i32.const 65529)) (i32.const 14))
+(assert_return (invoke "load8_u" (i32.const 65530)) (i32.const 15))
+(assert_return (invoke "load8_u" (i32.const 65531)) (i32.const 16))
+(assert_return (invoke "load8_u" (i32.const 65532)) (i32.const 17))
+(assert_return (invoke "load8_u" (i32.const 65533)) (i32.const 18))
+(assert_return (invoke "load8_u" (i32.const 65534)) (i32.const 19))
+(assert_return (invoke "load8_u" (i32.const 65535)) (i32.const 20))
+
+(module
+  (memory (export "mem") 1 1 )
+  (data (i32.const 65516) "\00\01\02\03\04\05\06\07\08\09\0a\0b\0c\0d\0e\0f\10\11\12\13")
+  (func (export "run") (param $targetOffs i32) (param $srcOffs i32) (param $len i32)
+    (memory.copy (local.get $targetOffs) (local.get $srcOffs) (local.get $len)))
+  (func (export "load8_u") (param i32) (result i32)
+    (i32.load8_u (local.get 0))))
+
+(assert_trap (invoke "run" (i32.const 0) (i32.const 65516) (i32.const 40))
+             "out of bounds")
+
+(assert_return (invoke "load8_u" (i32.const 0)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 1)) (i32.const 1))
+(assert_return (invoke "load8_u" (i32.const 2)) (i32.const 2))
+(assert_return (invoke "load8_u" (i32.const 3)) (i32.const 3))
+(assert_return (invoke "load8_u" (i32.const 4)) (i32.const 4))
+(assert_return (invoke "load8_u" (i32.const 5)) (i32.const 5))
+(assert_return (invoke "load8_u" (i32.const 6)) (i32.const 6))
+(assert_return (invoke "load8_u" (i32.const 7)) (i32.const 7))
+(assert_return (invoke "load8_u" (i32.const 8)) (i32.const 8))
+(assert_return (invoke "load8_u" (i32.const 9)) (i32.const 9))
+(assert_return (invoke "load8_u" (i32.const 10)) (i32.const 10))
+(assert_return (invoke "load8_u" (i32.const 11)) (i32.const 11))
+(assert_return (invoke "load8_u" (i32.const 12)) (i32.const 12))
+(assert_return (invoke "load8_u" (i32.const 13)) (i32.const 13))
+(assert_return (invoke "load8_u" (i32.const 14)) (i32.const 14))
+(assert_return (invoke "load8_u" (i32.const 15)) (i32.const 15))
+(assert_return (invoke "load8_u" (i32.const 16)) (i32.const 16))
+(assert_return (invoke "load8_u" (i32.const 17)) (i32.const 17))
+(assert_return (invoke "load8_u" (i32.const 18)) (i32.const 18))
+(assert_return (invoke "load8_u" (i32.const 19)) (i32.const 19))
+(assert_return (invoke "load8_u" (i32.const 218)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 417)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 616)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 815)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 1014)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 1213)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 1412)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 1611)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 1810)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 2009)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 2208)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 2407)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 2606)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 2805)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 3004)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 3203)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 3402)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 3601)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 3800)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 3999)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 4198)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 4397)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 4596)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 4795)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 4994)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 5193)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 5392)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 5591)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 5790)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 5989)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 6188)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 6387)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 6586)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 6785)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 6984)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 7183)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 7382)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 7581)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 7780)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 7979)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 8178)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 8377)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 8576)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 8775)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 8974)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 9173)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 9372)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 9571)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 9770)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 9969)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 10168)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 10367)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 10566)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 10765)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 10964)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 11163)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 11362)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 11561)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 11760)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 11959)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 12158)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 12357)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 12556)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 12755)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 12954)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 13153)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 13352)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 13551)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 13750)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 13949)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 14148)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 14347)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 14546)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 14745)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 14944)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 15143)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 15342)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 15541)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 15740)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 15939)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 16138)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 16337)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 16536)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 16735)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 16934)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 17133)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 17332)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 17531)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 17730)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 17929)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 18128)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 18327)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 18526)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 18725)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 18924)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 19123)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 19322)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 19521)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 19720)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 19919)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 20118)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 20317)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 20516)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 20715)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 20914)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 21113)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 21312)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 21511)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 21710)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 21909)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 22108)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 22307)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 22506)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 22705)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 22904)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 23103)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 23302)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 23501)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 23700)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 23899)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 24098)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 24297)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 24496)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 24695)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 24894)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 25093)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 25292)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 25491)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 25690)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 25889)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 26088)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 26287)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 26486)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 26685)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 26884)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 27083)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 27282)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 27481)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 27680)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 27879)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 28078)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 28277)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 28476)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 28675)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 28874)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 29073)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 29272)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 29471)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 29670)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 29869)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 30068)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 30267)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 30466)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 30665)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 30864)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 31063)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 31262)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 31461)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 31660)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 31859)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 32058)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 32257)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 32456)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 32655)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 32854)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 33053)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 33252)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 33451)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 33650)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 33849)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 34048)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 34247)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 34446)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 34645)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 34844)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 35043)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 35242)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 35441)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 35640)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 35839)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 36038)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 36237)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 36436)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 36635)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 36834)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 37033)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 37232)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 37431)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 37630)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 37829)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 38028)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 38227)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 38426)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 38625)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 38824)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 39023)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 39222)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 39421)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 39620)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 39819)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 40018)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 40217)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 40416)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 40615)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 40814)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 41013)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 41212)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 41411)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 41610)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 41809)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 42008)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 42207)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 42406)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 42605)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 42804)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 43003)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 43202)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 43401)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 43600)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 43799)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 43998)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 44197)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 44396)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 44595)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 44794)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 44993)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 45192)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 45391)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 45590)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 45789)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 45988)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 46187)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 46386)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 46585)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 46784)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 46983)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 47182)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 47381)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 47580)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 47779)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 47978)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 48177)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 48376)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 48575)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 48774)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 48973)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 49172)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 49371)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 49570)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 49769)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 49968)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 50167)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 50366)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 50565)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 50764)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 50963)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 51162)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 51361)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 51560)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 51759)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 51958)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 52157)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 52356)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 52555)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 52754)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 52953)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 53152)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 53351)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 53550)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 53749)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 53948)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 54147)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 54346)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 54545)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 54744)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 54943)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 55142)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 55341)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 55540)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 55739)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 55938)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 56137)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 56336)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 56535)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 56734)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 56933)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 57132)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 57331)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 57530)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 57729)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 57928)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 58127)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 58326)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 58525)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 58724)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 58923)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 59122)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 59321)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 59520)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 59719)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 59918)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 60117)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 60316)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 60515)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 60714)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 60913)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 61112)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 61311)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 61510)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 61709)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 61908)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 62107)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 62306)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 62505)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 62704)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 62903)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 63102)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 63301)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 63500)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 63699)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 63898)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 64097)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 64296)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 64495)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 64694)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 64893)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 65092)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 65291)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 65490)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 65516)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 65517)) (i32.const 1))
+(assert_return (invoke "load8_u" (i32.const 65518)) (i32.const 2))
+(assert_return (invoke "load8_u" (i32.const 65519)) (i32.const 3))
+(assert_return (invoke "load8_u" (i32.const 65520)) (i32.const 4))
+(assert_return (invoke "load8_u" (i32.const 65521)) (i32.const 5))
+(assert_return (invoke "load8_u" (i32.const 65522)) (i32.const 6))
+(assert_return (invoke "load8_u" (i32.const 65523)) (i32.const 7))
+(assert_return (invoke "load8_u" (i32.const 65524)) (i32.const 8))
+(assert_return (invoke "load8_u" (i32.const 65525)) (i32.const 9))
+(assert_return (invoke "load8_u" (i32.const 65526)) (i32.const 10))
+(assert_return (invoke "load8_u" (i32.const 65527)) (i32.const 11))
+(assert_return (invoke "load8_u" (i32.const 65528)) (i32.const 12))
+(assert_return (invoke "load8_u" (i32.const 65529)) (i32.const 13))
+(assert_return (invoke "load8_u" (i32.const 65530)) (i32.const 14))
+(assert_return (invoke "load8_u" (i32.const 65531)) (i32.const 15))
+(assert_return (invoke "load8_u" (i32.const 65532)) (i32.const 16))
+(assert_return (invoke "load8_u" (i32.const 65533)) (i32.const 17))
+(assert_return (invoke "load8_u" (i32.const 65534)) (i32.const 18))
+(assert_return (invoke "load8_u" (i32.const 65535)) (i32.const 19))
+
+(module
+  (memory (export "mem") 1 1 )
+  (data (i32.const 65515) "\00\01\02\03\04\05\06\07\08\09\0a\0b\0c\0d\0e\0f\10\11\12\13\14")
+  (func (export "run") (param $targetOffs i32) (param $srcOffs i32) (param $len i32)
+    (memory.copy (local.get $targetOffs) (local.get $srcOffs) (local.get $len)))
+  (func (export "load8_u") (param i32) (result i32)
+    (i32.load8_u (local.get 0))))
+
+(assert_trap (invoke "run" (i32.const 0) (i32.const 65515) (i32.const 39))
+             "out of bounds")
+
+(assert_return (invoke "load8_u" (i32.const 0)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 1)) (i32.const 1))
+(assert_return (invoke "load8_u" (i32.const 2)) (i32.const 2))
+(assert_return (invoke "load8_u" (i32.const 3)) (i32.const 3))
+(assert_return (invoke "load8_u" (i32.const 4)) (i32.const 4))
+(assert_return (invoke "load8_u" (i32.const 5)) (i32.const 5))
+(assert_return (invoke "load8_u" (i32.const 6)) (i32.const 6))
+(assert_return (invoke "load8_u" (i32.const 7)) (i32.const 7))
+(assert_return (invoke "load8_u" (i32.const 8)) (i32.const 8))
+(assert_return (invoke "load8_u" (i32.const 9)) (i32.const 9))
+(assert_return (invoke "load8_u" (i32.const 10)) (i32.const 10))
+(assert_return (invoke "load8_u" (i32.const 11)) (i32.const 11))
+(assert_return (invoke "load8_u" (i32.const 12)) (i32.const 12))
+(assert_return (invoke "load8_u" (i32.const 13)) (i32.const 13))
+(assert_return (invoke "load8_u" (i32.const 14)) (i32.const 14))
+(assert_return (invoke "load8_u" (i32.const 15)) (i32.const 15))
+(assert_return (invoke "load8_u" (i32.const 16)) (i32.const 16))
+(assert_return (invoke "load8_u" (i32.const 17)) (i32.const 17))
+(assert_return (invoke "load8_u" (i32.const 18)) (i32.const 18))
+(assert_return (invoke "load8_u" (i32.const 19)) (i32.const 19))
+(assert_return (invoke "load8_u" (i32.const 20)) (i32.const 20))
+(assert_return (invoke "load8_u" (i32.const 219)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 418)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 617)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 816)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 1015)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 1214)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 1413)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 1612)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 1811)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 2010)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 2209)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 2408)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 2607)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 2806)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 3005)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 3204)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 3403)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 3602)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 3801)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 4000)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 4199)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 4398)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 4597)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 4796)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 4995)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 5194)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 5393)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 5592)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 5791)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 5990)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 6189)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 6388)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 6587)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 6786)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 6985)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 7184)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 7383)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 7582)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 7781)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 7980)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 8179)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 8378)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 8577)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 8776)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 8975)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 9174)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 9373)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 9572)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 9771)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 9970)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 10169)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 10368)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 10567)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 10766)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 10965)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 11164)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 11363)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 11562)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 11761)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 11960)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 12159)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 12358)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 12557)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 12756)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 12955)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 13154)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 13353)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 13552)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 13751)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 13950)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 14149)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 14348)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 14547)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 14746)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 14945)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 15144)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 15343)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 15542)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 15741)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 15940)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 16139)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 16338)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 16537)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 16736)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 16935)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 17134)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 17333)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 17532)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 17731)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 17930)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 18129)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 18328)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 18527)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 18726)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 18925)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 19124)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 19323)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 19522)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 19721)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 19920)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 20119)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 20318)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 20517)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 20716)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 20915)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 21114)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 21313)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 21512)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 21711)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 21910)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 22109)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 22308)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 22507)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 22706)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 22905)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 23104)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 23303)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 23502)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 23701)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 23900)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 24099)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 24298)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 24497)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 24696)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 24895)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 25094)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 25293)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 25492)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 25691)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 25890)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 26089)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 26288)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 26487)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 26686)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 26885)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 27084)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 27283)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 27482)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 27681)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 27880)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 28079)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 28278)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 28477)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 28676)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 28875)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 29074)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 29273)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 29472)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 29671)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 29870)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 30069)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 30268)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 30467)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 30666)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 30865)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 31064)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 31263)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 31462)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 31661)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 31860)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 32059)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 32258)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 32457)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 32656)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 32855)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 33054)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 33253)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 33452)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 33651)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 33850)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 34049)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 34248)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 34447)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 34646)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 34845)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 35044)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 35243)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 35442)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 35641)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 35840)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 36039)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 36238)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 36437)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 36636)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 36835)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 37034)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 37233)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 37432)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 37631)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 37830)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 38029)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 38228)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 38427)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 38626)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 38825)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 39024)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 39223)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 39422)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 39621)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 39820)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 40019)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 40218)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 40417)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 40616)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 40815)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 41014)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 41213)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 41412)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 41611)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 41810)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 42009)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 42208)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 42407)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 42606)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 42805)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 43004)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 43203)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 43402)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 43601)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 43800)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 43999)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 44198)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 44397)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 44596)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 44795)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 44994)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 45193)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 45392)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 45591)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 45790)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 45989)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 46188)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 46387)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 46586)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 46785)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 46984)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 47183)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 47382)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 47581)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 47780)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 47979)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 48178)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 48377)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 48576)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 48775)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 48974)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 49173)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 49372)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 49571)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 49770)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 49969)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 50168)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 50367)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 50566)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 50765)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 50964)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 51163)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 51362)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 51561)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 51760)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 51959)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 52158)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 52357)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 52556)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 52755)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 52954)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 53153)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 53352)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 53551)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 53750)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 53949)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 54148)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 54347)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 54546)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 54745)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 54944)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 55143)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 55342)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 55541)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 55740)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 55939)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 56138)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 56337)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 56536)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 56735)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 56934)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 57133)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 57332)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 57531)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 57730)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 57929)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 58128)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 58327)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 58526)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 58725)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 58924)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 59123)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 59322)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 59521)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 59720)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 59919)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 60118)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 60317)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 60516)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 60715)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 60914)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 61113)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 61312)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 61511)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 61710)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 61909)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 62108)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 62307)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 62506)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 62705)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 62904)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 63103)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 63302)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 63501)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 63700)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 63899)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 64098)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 64297)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 64496)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 64695)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 64894)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 65093)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 65292)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 65491)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 65515)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 65516)) (i32.const 1))
+(assert_return (invoke "load8_u" (i32.const 65517)) (i32.const 2))
+(assert_return (invoke "load8_u" (i32.const 65518)) (i32.const 3))
+(assert_return (invoke "load8_u" (i32.const 65519)) (i32.const 4))
+(assert_return (invoke "load8_u" (i32.const 65520)) (i32.const 5))
+(assert_return (invoke "load8_u" (i32.const 65521)) (i32.const 6))
+(assert_return (invoke "load8_u" (i32.const 65522)) (i32.const 7))
+(assert_return (invoke "load8_u" (i32.const 65523)) (i32.const 8))
+(assert_return (invoke "load8_u" (i32.const 65524)) (i32.const 9))
+(assert_return (invoke "load8_u" (i32.const 65525)) (i32.const 10))
+(assert_return (invoke "load8_u" (i32.const 65526)) (i32.const 11))
+(assert_return (invoke "load8_u" (i32.const 65527)) (i32.const 12))
+(assert_return (invoke "load8_u" (i32.const 65528)) (i32.const 13))
+(assert_return (invoke "load8_u" (i32.const 65529)) (i32.const 14))
+(assert_return (invoke "load8_u" (i32.const 65530)) (i32.const 15))
+(assert_return (invoke "load8_u" (i32.const 65531)) (i32.const 16))
+(assert_return (invoke "load8_u" (i32.const 65532)) (i32.const 17))
+(assert_return (invoke "load8_u" (i32.const 65533)) (i32.const 18))
+(assert_return (invoke "load8_u" (i32.const 65534)) (i32.const 19))
+(assert_return (invoke "load8_u" (i32.const 65535)) (i32.const 20))
+
+(module
+  (memory (export "mem") 1 1 )
+  (data (i32.const 65486) "\00\01\02\03\04\05\06\07\08\09\0a\0b\0c\0d\0e\0f\10\11\12\13")
+  (func (export "run") (param $targetOffs i32) (param $srcOffs i32) (param $len i32)
+    (memory.copy (local.get $targetOffs) (local.get $srcOffs) (local.get $len)))
+  (func (export "load8_u") (param i32) (result i32)
+    (i32.load8_u (local.get 0))))
+
+(assert_trap (invoke "run" (i32.const 65516) (i32.const 65486) (i32.const 40))
+             "out of bounds")
+
+(assert_return (invoke "load8_u" (i32.const 198)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 397)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 596)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 795)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 994)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 1193)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 1392)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 1591)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 1790)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 1989)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 2188)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 2387)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 2586)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 2785)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 2984)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 3183)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 3382)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 3581)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 3780)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 3979)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 4178)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 4377)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 4576)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 4775)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 4974)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 5173)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 5372)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 5571)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 5770)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 5969)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 6168)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 6367)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 6566)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 6765)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 6964)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 7163)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 7362)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 7561)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 7760)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 7959)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 8158)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 8357)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 8556)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 8755)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 8954)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 9153)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 9352)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 9551)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 9750)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 9949)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 10148)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 10347)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 10546)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 10745)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 10944)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 11143)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 11342)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 11541)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 11740)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 11939)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 12138)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 12337)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 12536)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 12735)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 12934)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 13133)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 13332)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 13531)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 13730)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 13929)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 14128)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 14327)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 14526)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 14725)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 14924)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 15123)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 15322)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 15521)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 15720)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 15919)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 16118)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 16317)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 16516)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 16715)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 16914)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 17113)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 17312)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 17511)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 17710)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 17909)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 18108)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 18307)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 18506)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 18705)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 18904)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 19103)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 19302)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 19501)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 19700)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 19899)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 20098)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 20297)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 20496)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 20695)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 20894)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 21093)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 21292)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 21491)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 21690)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 21889)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 22088)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 22287)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 22486)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 22685)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 22884)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 23083)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 23282)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 23481)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 23680)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 23879)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 24078)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 24277)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 24476)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 24675)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 24874)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 25073)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 25272)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 25471)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 25670)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 25869)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 26068)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 26267)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 26466)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 26665)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 26864)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 27063)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 27262)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 27461)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 27660)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 27859)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 28058)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 28257)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 28456)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 28655)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 28854)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 29053)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 29252)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 29451)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 29650)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 29849)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 30048)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 30247)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 30446)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 30645)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 30844)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 31043)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 31242)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 31441)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 31640)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 31839)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 32038)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 32237)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 32436)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 32635)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 32834)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 33033)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 33232)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 33431)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 33630)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 33829)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 34028)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 34227)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 34426)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 34625)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 34824)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 35023)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 35222)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 35421)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 35620)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 35819)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 36018)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 36217)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 36416)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 36615)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 36814)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 37013)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 37212)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 37411)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 37610)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 37809)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 38008)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 38207)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 38406)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 38605)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 38804)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 39003)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 39202)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 39401)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 39600)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 39799)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 39998)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 40197)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 40396)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 40595)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 40794)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 40993)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 41192)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 41391)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 41590)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 41789)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 41988)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 42187)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 42386)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 42585)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 42784)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 42983)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 43182)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 43381)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 43580)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 43779)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 43978)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 44177)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 44376)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 44575)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 44774)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 44973)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 45172)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 45371)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 45570)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 45769)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 45968)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 46167)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 46366)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 46565)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 46764)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 46963)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 47162)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 47361)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 47560)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 47759)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 47958)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 48157)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 48356)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 48555)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 48754)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 48953)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 49152)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 49351)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 49550)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 49749)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 49948)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 50147)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 50346)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 50545)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 50744)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 50943)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 51142)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 51341)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 51540)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 51739)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 51938)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 52137)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 52336)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 52535)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 52734)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 52933)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 53132)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 53331)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 53530)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 53729)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 53928)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 54127)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 54326)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 54525)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 54724)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 54923)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 55122)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 55321)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 55520)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 55719)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 55918)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 56117)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 56316)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 56515)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 56714)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 56913)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 57112)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 57311)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 57510)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 57709)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 57908)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 58107)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 58306)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 58505)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 58704)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 58903)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 59102)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 59301)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 59500)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 59699)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 59898)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 60097)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 60296)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 60495)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 60694)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 60893)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 61092)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 61291)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 61490)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 61689)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 61888)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 62087)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 62286)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 62485)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 62684)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 62883)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 63082)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 63281)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 63480)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 63679)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 63878)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 64077)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 64276)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 64475)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 64674)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 64873)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 65072)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 65271)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 65470)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 65486)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 65487)) (i32.const 1))
+(assert_return (invoke "load8_u" (i32.const 65488)) (i32.const 2))
+(assert_return (invoke "load8_u" (i32.const 65489)) (i32.const 3))
+(assert_return (invoke "load8_u" (i32.const 65490)) (i32.const 4))
+(assert_return (invoke "load8_u" (i32.const 65491)) (i32.const 5))
+(assert_return (invoke "load8_u" (i32.const 65492)) (i32.const 6))
+(assert_return (invoke "load8_u" (i32.const 65493)) (i32.const 7))
+(assert_return (invoke "load8_u" (i32.const 65494)) (i32.const 8))
+(assert_return (invoke "load8_u" (i32.const 65495)) (i32.const 9))
+(assert_return (invoke "load8_u" (i32.const 65496)) (i32.const 10))
+(assert_return (invoke "load8_u" (i32.const 65497)) (i32.const 11))
+(assert_return (invoke "load8_u" (i32.const 65498)) (i32.const 12))
+(assert_return (invoke "load8_u" (i32.const 65499)) (i32.const 13))
+(assert_return (invoke "load8_u" (i32.const 65500)) (i32.const 14))
+(assert_return (invoke "load8_u" (i32.const 65501)) (i32.const 15))
+(assert_return (invoke "load8_u" (i32.const 65502)) (i32.const 16))
+(assert_return (invoke "load8_u" (i32.const 65503)) (i32.const 17))
+(assert_return (invoke "load8_u" (i32.const 65504)) (i32.const 18))
+(assert_return (invoke "load8_u" (i32.const 65505)) (i32.const 19))
+
+(module
+  (memory (export "mem") 1 1 )
+  (data (i32.const 65516) "\00\01\02\03\04\05\06\07\08\09\0a\0b\0c\0d\0e\0f\10\11\12\13")
+  (func (export "run") (param $targetOffs i32) (param $srcOffs i32) (param $len i32)
+    (memory.copy (local.get $targetOffs) (local.get $srcOffs) (local.get $len)))
+  (func (export "load8_u") (param i32) (result i32)
+    (i32.load8_u (local.get 0))))
+
+(assert_trap (invoke "run" (i32.const 65486) (i32.const 65516) (i32.const 40))
+             "out of bounds")
+
+(assert_return (invoke "load8_u" (i32.const 198)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 397)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 596)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 795)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 994)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 1193)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 1392)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 1591)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 1790)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 1989)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 2188)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 2387)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 2586)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 2785)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 2984)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 3183)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 3382)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 3581)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 3780)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 3979)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 4178)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 4377)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 4576)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 4775)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 4974)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 5173)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 5372)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 5571)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 5770)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 5969)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 6168)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 6367)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 6566)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 6765)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 6964)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 7163)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 7362)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 7561)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 7760)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 7959)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 8158)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 8357)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 8556)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 8755)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 8954)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 9153)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 9352)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 9551)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 9750)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 9949)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 10148)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 10347)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 10546)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 10745)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 10944)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 11143)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 11342)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 11541)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 11740)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 11939)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 12138)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 12337)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 12536)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 12735)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 12934)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 13133)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 13332)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 13531)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 13730)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 13929)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 14128)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 14327)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 14526)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 14725)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 14924)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 15123)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 15322)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 15521)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 15720)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 15919)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 16118)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 16317)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 16516)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 16715)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 16914)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 17113)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 17312)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 17511)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 17710)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 17909)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 18108)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 18307)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 18506)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 18705)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 18904)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 19103)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 19302)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 19501)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 19700)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 19899)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 20098)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 20297)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 20496)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 20695)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 20894)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 21093)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 21292)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 21491)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 21690)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 21889)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 22088)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 22287)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 22486)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 22685)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 22884)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 23083)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 23282)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 23481)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 23680)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 23879)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 24078)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 24277)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 24476)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 24675)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 24874)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 25073)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 25272)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 25471)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 25670)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 25869)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 26068)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 26267)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 26466)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 26665)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 26864)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 27063)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 27262)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 27461)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 27660)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 27859)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 28058)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 28257)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 28456)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 28655)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 28854)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 29053)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 29252)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 29451)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 29650)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 29849)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 30048)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 30247)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 30446)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 30645)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 30844)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 31043)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 31242)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 31441)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 31640)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 31839)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 32038)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 32237)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 32436)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 32635)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 32834)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 33033)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 33232)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 33431)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 33630)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 33829)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 34028)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 34227)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 34426)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 34625)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 34824)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 35023)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 35222)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 35421)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 35620)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 35819)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 36018)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 36217)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 36416)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 36615)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 36814)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 37013)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 37212)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 37411)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 37610)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 37809)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 38008)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 38207)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 38406)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 38605)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 38804)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 39003)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 39202)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 39401)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 39600)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 39799)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 39998)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 40197)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 40396)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 40595)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 40794)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 40993)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 41192)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 41391)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 41590)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 41789)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 41988)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 42187)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 42386)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 42585)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 42784)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 42983)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 43182)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 43381)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 43580)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 43779)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 43978)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 44177)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 44376)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 44575)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 44774)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 44973)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 45172)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 45371)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 45570)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 45769)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 45968)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 46167)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 46366)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 46565)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 46764)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 46963)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 47162)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 47361)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 47560)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 47759)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 47958)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 48157)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 48356)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 48555)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 48754)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 48953)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 49152)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 49351)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 49550)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 49749)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 49948)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 50147)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 50346)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 50545)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 50744)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 50943)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 51142)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 51341)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 51540)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 51739)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 51938)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 52137)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 52336)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 52535)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 52734)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 52933)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 53132)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 53331)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 53530)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 53729)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 53928)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 54127)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 54326)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 54525)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 54724)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 54923)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 55122)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 55321)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 55520)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 55719)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 55918)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 56117)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 56316)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 56515)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 56714)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 56913)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 57112)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 57311)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 57510)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 57709)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 57908)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 58107)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 58306)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 58505)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 58704)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 58903)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 59102)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 59301)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 59500)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 59699)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 59898)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 60097)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 60296)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 60495)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 60694)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 60893)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 61092)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 61291)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 61490)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 61689)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 61888)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 62087)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 62286)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 62485)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 62684)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 62883)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 63082)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 63281)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 63480)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 63679)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 63878)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 64077)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 64276)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 64475)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 64674)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 64873)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 65072)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 65271)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 65470)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 65486)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 65487)) (i32.const 1))
+(assert_return (invoke "load8_u" (i32.const 65488)) (i32.const 2))
+(assert_return (invoke "load8_u" (i32.const 65489)) (i32.const 3))
+(assert_return (invoke "load8_u" (i32.const 65490)) (i32.const 4))
+(assert_return (invoke "load8_u" (i32.const 65491)) (i32.const 5))
+(assert_return (invoke "load8_u" (i32.const 65492)) (i32.const 6))
+(assert_return (invoke "load8_u" (i32.const 65493)) (i32.const 7))
+(assert_return (invoke "load8_u" (i32.const 65494)) (i32.const 8))
+(assert_return (invoke "load8_u" (i32.const 65495)) (i32.const 9))
+(assert_return (invoke "load8_u" (i32.const 65496)) (i32.const 10))
+(assert_return (invoke "load8_u" (i32.const 65497)) (i32.const 11))
+(assert_return (invoke "load8_u" (i32.const 65498)) (i32.const 12))
+(assert_return (invoke "load8_u" (i32.const 65499)) (i32.const 13))
+(assert_return (invoke "load8_u" (i32.const 65500)) (i32.const 14))
+(assert_return (invoke "load8_u" (i32.const 65501)) (i32.const 15))
+(assert_return (invoke "load8_u" (i32.const 65502)) (i32.const 16))
+(assert_return (invoke "load8_u" (i32.const 65503)) (i32.const 17))
+(assert_return (invoke "load8_u" (i32.const 65504)) (i32.const 18))
+(assert_return (invoke "load8_u" (i32.const 65505)) (i32.const 19))
+(assert_return (invoke "load8_u" (i32.const 65516)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 65517)) (i32.const 1))
+(assert_return (invoke "load8_u" (i32.const 65518)) (i32.const 2))
+(assert_return (invoke "load8_u" (i32.const 65519)) (i32.const 3))
+(assert_return (invoke "load8_u" (i32.const 65520)) (i32.const 4))
+(assert_return (invoke "load8_u" (i32.const 65521)) (i32.const 5))
+(assert_return (invoke "load8_u" (i32.const 65522)) (i32.const 6))
+(assert_return (invoke "load8_u" (i32.const 65523)) (i32.const 7))
+(assert_return (invoke "load8_u" (i32.const 65524)) (i32.const 8))
+(assert_return (invoke "load8_u" (i32.const 65525)) (i32.const 9))
+(assert_return (invoke "load8_u" (i32.const 65526)) (i32.const 10))
+(assert_return (invoke "load8_u" (i32.const 65527)) (i32.const 11))
+(assert_return (invoke "load8_u" (i32.const 65528)) (i32.const 12))
+(assert_return (invoke "load8_u" (i32.const 65529)) (i32.const 13))
+(assert_return (invoke "load8_u" (i32.const 65530)) (i32.const 14))
+(assert_return (invoke "load8_u" (i32.const 65531)) (i32.const 15))
+(assert_return (invoke "load8_u" (i32.const 65532)) (i32.const 16))
+(assert_return (invoke "load8_u" (i32.const 65533)) (i32.const 17))
+(assert_return (invoke "load8_u" (i32.const 65534)) (i32.const 18))
+(assert_return (invoke "load8_u" (i32.const 65535)) (i32.const 19))
+
+(module
+  (memory (export "mem") 1 1 )
+  (data (i32.const 65506) "\00\01\02\03\04\05\06\07\08\09\0a\0b\0c\0d\0e\0f\10\11\12\13")
+  (func (export "run") (param $targetOffs i32) (param $srcOffs i32) (param $len i32)
+    (memory.copy (local.get $targetOffs) (local.get $srcOffs) (local.get $len)))
+  (func (export "load8_u") (param i32) (result i32)
+    (i32.load8_u (local.get 0))))
+
+(assert_trap (invoke "run" (i32.const 65516) (i32.const 65506) (i32.const 40))
+             "out of bounds")
+
+(assert_return (invoke "load8_u" (i32.const 198)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 397)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 596)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 795)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 994)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 1193)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 1392)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 1591)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 1790)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 1989)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 2188)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 2387)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 2586)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 2785)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 2984)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 3183)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 3382)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 3581)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 3780)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 3979)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 4178)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 4377)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 4576)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 4775)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 4974)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 5173)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 5372)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 5571)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 5770)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 5969)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 6168)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 6367)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 6566)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 6765)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 6964)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 7163)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 7362)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 7561)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 7760)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 7959)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 8158)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 8357)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 8556)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 8755)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 8954)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 9153)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 9352)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 9551)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 9750)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 9949)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 10148)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 10347)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 10546)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 10745)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 10944)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 11143)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 11342)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 11541)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 11740)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 11939)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 12138)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 12337)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 12536)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 12735)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 12934)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 13133)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 13332)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 13531)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 13730)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 13929)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 14128)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 14327)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 14526)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 14725)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 14924)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 15123)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 15322)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 15521)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 15720)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 15919)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 16118)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 16317)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 16516)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 16715)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 16914)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 17113)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 17312)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 17511)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 17710)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 17909)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 18108)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 18307)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 18506)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 18705)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 18904)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 19103)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 19302)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 19501)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 19700)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 19899)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 20098)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 20297)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 20496)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 20695)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 20894)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 21093)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 21292)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 21491)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 21690)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 21889)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 22088)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 22287)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 22486)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 22685)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 22884)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 23083)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 23282)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 23481)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 23680)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 23879)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 24078)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 24277)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 24476)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 24675)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 24874)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 25073)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 25272)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 25471)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 25670)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 25869)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 26068)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 26267)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 26466)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 26665)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 26864)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 27063)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 27262)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 27461)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 27660)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 27859)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 28058)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 28257)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 28456)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 28655)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 28854)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 29053)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 29252)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 29451)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 29650)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 29849)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 30048)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 30247)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 30446)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 30645)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 30844)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 31043)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 31242)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 31441)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 31640)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 31839)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 32038)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 32237)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 32436)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 32635)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 32834)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 33033)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 33232)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 33431)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 33630)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 33829)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 34028)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 34227)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 34426)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 34625)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 34824)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 35023)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 35222)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 35421)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 35620)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 35819)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 36018)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 36217)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 36416)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 36615)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 36814)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 37013)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 37212)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 37411)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 37610)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 37809)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 38008)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 38207)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 38406)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 38605)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 38804)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 39003)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 39202)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 39401)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 39600)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 39799)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 39998)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 40197)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 40396)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 40595)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 40794)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 40993)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 41192)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 41391)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 41590)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 41789)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 41988)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 42187)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 42386)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 42585)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 42784)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 42983)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 43182)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 43381)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 43580)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 43779)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 43978)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 44177)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 44376)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 44575)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 44774)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 44973)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 45172)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 45371)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 45570)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 45769)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 45968)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 46167)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 46366)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 46565)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 46764)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 46963)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 47162)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 47361)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 47560)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 47759)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 47958)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 48157)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 48356)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 48555)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 48754)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 48953)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 49152)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 49351)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 49550)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 49749)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 49948)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 50147)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 50346)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 50545)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 50744)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 50943)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 51142)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 51341)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 51540)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 51739)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 51938)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 52137)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 52336)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 52535)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 52734)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 52933)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 53132)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 53331)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 53530)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 53729)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 53928)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 54127)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 54326)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 54525)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 54724)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 54923)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 55122)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 55321)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 55520)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 55719)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 55918)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 56117)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 56316)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 56515)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 56714)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 56913)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 57112)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 57311)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 57510)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 57709)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 57908)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 58107)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 58306)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 58505)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 58704)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 58903)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 59102)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 59301)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 59500)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 59699)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 59898)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 60097)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 60296)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 60495)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 60694)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 60893)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 61092)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 61291)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 61490)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 61689)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 61888)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 62087)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 62286)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 62485)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 62684)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 62883)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 63082)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 63281)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 63480)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 63679)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 63878)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 64077)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 64276)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 64475)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 64674)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 64873)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 65072)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 65271)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 65470)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 65506)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 65507)) (i32.const 1))
+(assert_return (invoke "load8_u" (i32.const 65508)) (i32.const 2))
+(assert_return (invoke "load8_u" (i32.const 65509)) (i32.const 3))
+(assert_return (invoke "load8_u" (i32.const 65510)) (i32.const 4))
+(assert_return (invoke "load8_u" (i32.const 65511)) (i32.const 5))
+(assert_return (invoke "load8_u" (i32.const 65512)) (i32.const 6))
+(assert_return (invoke "load8_u" (i32.const 65513)) (i32.const 7))
+(assert_return (invoke "load8_u" (i32.const 65514)) (i32.const 8))
+(assert_return (invoke "load8_u" (i32.const 65515)) (i32.const 9))
+(assert_return (invoke "load8_u" (i32.const 65516)) (i32.const 10))
+(assert_return (invoke "load8_u" (i32.const 65517)) (i32.const 11))
+(assert_return (invoke "load8_u" (i32.const 65518)) (i32.const 12))
+(assert_return (invoke "load8_u" (i32.const 65519)) (i32.const 13))
+(assert_return (invoke "load8_u" (i32.const 65520)) (i32.const 14))
+(assert_return (invoke "load8_u" (i32.const 65521)) (i32.const 15))
+(assert_return (invoke "load8_u" (i32.const 65522)) (i32.const 16))
+(assert_return (invoke "load8_u" (i32.const 65523)) (i32.const 17))
+(assert_return (invoke "load8_u" (i32.const 65524)) (i32.const 18))
+(assert_return (invoke "load8_u" (i32.const 65525)) (i32.const 19))
+
+(module
+  (memory (export "mem") 1 1 )
+  (data (i32.const 65516) "\00\01\02\03\04\05\06\07\08\09\0a\0b\0c\0d\0e\0f\10\11\12\13")
+  (func (export "run") (param $targetOffs i32) (param $srcOffs i32) (param $len i32)
+    (memory.copy (local.get $targetOffs) (local.get $srcOffs) (local.get $len)))
+  (func (export "load8_u") (param i32) (result i32)
+    (i32.load8_u (local.get 0))))
+
+(assert_trap (invoke "run" (i32.const 65506) (i32.const 65516) (i32.const 40))
+             "out of bounds")
+
+(assert_return (invoke "load8_u" (i32.const 198)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 397)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 596)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 795)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 994)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 1193)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 1392)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 1591)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 1790)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 1989)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 2188)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 2387)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 2586)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 2785)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 2984)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 3183)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 3382)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 3581)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 3780)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 3979)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 4178)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 4377)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 4576)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 4775)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 4974)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 5173)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 5372)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 5571)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 5770)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 5969)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 6168)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 6367)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 6566)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 6765)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 6964)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 7163)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 7362)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 7561)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 7760)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 7959)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 8158)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 8357)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 8556)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 8755)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 8954)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 9153)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 9352)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 9551)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 9750)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 9949)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 10148)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 10347)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 10546)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 10745)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 10944)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 11143)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 11342)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 11541)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 11740)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 11939)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 12138)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 12337)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 12536)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 12735)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 12934)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 13133)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 13332)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 13531)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 13730)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 13929)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 14128)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 14327)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 14526)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 14725)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 14924)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 15123)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 15322)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 15521)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 15720)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 15919)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 16118)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 16317)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 16516)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 16715)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 16914)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 17113)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 17312)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 17511)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 17710)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 17909)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 18108)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 18307)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 18506)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 18705)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 18904)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 19103)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 19302)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 19501)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 19700)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 19899)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 20098)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 20297)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 20496)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 20695)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 20894)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 21093)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 21292)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 21491)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 21690)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 21889)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 22088)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 22287)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 22486)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 22685)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 22884)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 23083)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 23282)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 23481)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 23680)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 23879)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 24078)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 24277)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 24476)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 24675)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 24874)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 25073)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 25272)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 25471)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 25670)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 25869)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 26068)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 26267)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 26466)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 26665)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 26864)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 27063)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 27262)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 27461)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 27660)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 27859)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 28058)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 28257)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 28456)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 28655)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 28854)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 29053)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 29252)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 29451)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 29650)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 29849)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 30048)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 30247)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 30446)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 30645)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 30844)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 31043)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 31242)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 31441)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 31640)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 31839)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 32038)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 32237)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 32436)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 32635)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 32834)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 33033)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 33232)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 33431)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 33630)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 33829)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 34028)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 34227)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 34426)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 34625)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 34824)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 35023)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 35222)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 35421)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 35620)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 35819)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 36018)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 36217)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 36416)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 36615)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 36814)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 37013)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 37212)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 37411)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 37610)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 37809)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 38008)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 38207)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 38406)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 38605)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 38804)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 39003)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 39202)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 39401)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 39600)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 39799)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 39998)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 40197)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 40396)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 40595)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 40794)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 40993)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 41192)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 41391)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 41590)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 41789)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 41988)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 42187)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 42386)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 42585)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 42784)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 42983)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 43182)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 43381)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 43580)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 43779)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 43978)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 44177)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 44376)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 44575)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 44774)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 44973)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 45172)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 45371)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 45570)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 45769)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 45968)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 46167)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 46366)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 46565)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 46764)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 46963)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 47162)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 47361)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 47560)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 47759)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 47958)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 48157)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 48356)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 48555)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 48754)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 48953)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 49152)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 49351)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 49550)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 49749)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 49948)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 50147)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 50346)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 50545)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 50744)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 50943)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 51142)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 51341)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 51540)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 51739)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 51938)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 52137)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 52336)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 52535)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 52734)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 52933)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 53132)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 53331)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 53530)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 53729)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 53928)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 54127)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 54326)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 54525)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 54724)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 54923)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 55122)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 55321)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 55520)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 55719)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 55918)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 56117)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 56316)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 56515)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 56714)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 56913)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 57112)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 57311)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 57510)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 57709)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 57908)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 58107)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 58306)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 58505)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 58704)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 58903)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 59102)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 59301)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 59500)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 59699)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 59898)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 60097)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 60296)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 60495)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 60694)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 60893)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 61092)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 61291)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 61490)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 61689)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 61888)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 62087)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 62286)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 62485)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 62684)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 62883)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 63082)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 63281)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 63480)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 63679)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 63878)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 64077)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 64276)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 64475)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 64674)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 64873)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 65072)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 65271)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 65470)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 65506)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 65507)) (i32.const 1))
+(assert_return (invoke "load8_u" (i32.const 65508)) (i32.const 2))
+(assert_return (invoke "load8_u" (i32.const 65509)) (i32.const 3))
+(assert_return (invoke "load8_u" (i32.const 65510)) (i32.const 4))
+(assert_return (invoke "load8_u" (i32.const 65511)) (i32.const 5))
+(assert_return (invoke "load8_u" (i32.const 65512)) (i32.const 6))
+(assert_return (invoke "load8_u" (i32.const 65513)) (i32.const 7))
+(assert_return (invoke "load8_u" (i32.const 65514)) (i32.const 8))
+(assert_return (invoke "load8_u" (i32.const 65515)) (i32.const 9))
+(assert_return (invoke "load8_u" (i32.const 65516)) (i32.const 10))
+(assert_return (invoke "load8_u" (i32.const 65517)) (i32.const 11))
+(assert_return (invoke "load8_u" (i32.const 65518)) (i32.const 12))
+(assert_return (invoke "load8_u" (i32.const 65519)) (i32.const 13))
+(assert_return (invoke "load8_u" (i32.const 65520)) (i32.const 14))
+(assert_return (invoke "load8_u" (i32.const 65521)) (i32.const 15))
+(assert_return (invoke "load8_u" (i32.const 65522)) (i32.const 16))
+(assert_return (invoke "load8_u" (i32.const 65523)) (i32.const 17))
+(assert_return (invoke "load8_u" (i32.const 65524)) (i32.const 18))
+(assert_return (invoke "load8_u" (i32.const 65525)) (i32.const 19))
+(assert_return (invoke "load8_u" (i32.const 65526)) (i32.const 10))
+(assert_return (invoke "load8_u" (i32.const 65527)) (i32.const 11))
+(assert_return (invoke "load8_u" (i32.const 65528)) (i32.const 12))
+(assert_return (invoke "load8_u" (i32.const 65529)) (i32.const 13))
+(assert_return (invoke "load8_u" (i32.const 65530)) (i32.const 14))
+(assert_return (invoke "load8_u" (i32.const 65531)) (i32.const 15))
+(assert_return (invoke "load8_u" (i32.const 65532)) (i32.const 16))
+(assert_return (invoke "load8_u" (i32.const 65533)) (i32.const 17))
+(assert_return (invoke "load8_u" (i32.const 65534)) (i32.const 18))
+(assert_return (invoke "load8_u" (i32.const 65535)) (i32.const 19))
+
+(module
+  (memory (export "mem") 1 1 )
+  (data (i32.const 65516) "\00\01\02\03\04\05\06\07\08\09\0a\0b\0c\0d\0e\0f\10\11\12\13")
+  (func (export "run") (param $targetOffs i32) (param $srcOffs i32) (param $len i32)
+    (memory.copy (local.get $targetOffs) (local.get $srcOffs) (local.get $len)))
+  (func (export "load8_u") (param i32) (result i32)
+    (i32.load8_u (local.get 0))))
+
+(assert_trap (invoke "run" (i32.const 65516) (i32.const 65516) (i32.const 40))
+             "out of bounds")
+
+(assert_return (invoke "load8_u" (i32.const 198)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 397)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 596)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 795)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 994)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 1193)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 1392)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 1591)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 1790)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 1989)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 2188)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 2387)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 2586)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 2785)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 2984)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 3183)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 3382)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 3581)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 3780)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 3979)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 4178)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 4377)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 4576)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 4775)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 4974)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 5173)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 5372)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 5571)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 5770)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 5969)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 6168)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 6367)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 6566)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 6765)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 6964)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 7163)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 7362)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 7561)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 7760)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 7959)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 8158)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 8357)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 8556)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 8755)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 8954)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 9153)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 9352)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 9551)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 9750)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 9949)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 10148)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 10347)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 10546)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 10745)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 10944)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 11143)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 11342)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 11541)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 11740)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 11939)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 12138)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 12337)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 12536)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 12735)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 12934)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 13133)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 13332)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 13531)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 13730)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 13929)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 14128)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 14327)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 14526)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 14725)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 14924)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 15123)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 15322)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 15521)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 15720)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 15919)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 16118)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 16317)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 16516)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 16715)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 16914)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 17113)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 17312)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 17511)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 17710)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 17909)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 18108)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 18307)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 18506)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 18705)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 18904)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 19103)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 19302)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 19501)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 19700)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 19899)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 20098)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 20297)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 20496)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 20695)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 20894)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 21093)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 21292)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 21491)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 21690)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 21889)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 22088)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 22287)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 22486)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 22685)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 22884)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 23083)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 23282)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 23481)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 23680)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 23879)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 24078)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 24277)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 24476)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 24675)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 24874)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 25073)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 25272)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 25471)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 25670)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 25869)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 26068)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 26267)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 26466)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 26665)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 26864)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 27063)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 27262)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 27461)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 27660)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 27859)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 28058)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 28257)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 28456)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 28655)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 28854)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 29053)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 29252)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 29451)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 29650)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 29849)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 30048)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 30247)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 30446)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 30645)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 30844)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 31043)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 31242)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 31441)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 31640)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 31839)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 32038)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 32237)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 32436)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 32635)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 32834)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 33033)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 33232)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 33431)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 33630)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 33829)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 34028)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 34227)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 34426)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 34625)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 34824)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 35023)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 35222)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 35421)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 35620)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 35819)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 36018)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 36217)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 36416)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 36615)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 36814)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 37013)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 37212)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 37411)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 37610)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 37809)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 38008)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 38207)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 38406)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 38605)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 38804)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 39003)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 39202)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 39401)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 39600)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 39799)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 39998)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 40197)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 40396)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 40595)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 40794)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 40993)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 41192)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 41391)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 41590)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 41789)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 41988)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 42187)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 42386)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 42585)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 42784)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 42983)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 43182)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 43381)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 43580)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 43779)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 43978)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 44177)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 44376)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 44575)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 44774)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 44973)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 45172)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 45371)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 45570)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 45769)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 45968)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 46167)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 46366)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 46565)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 46764)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 46963)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 47162)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 47361)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 47560)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 47759)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 47958)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 48157)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 48356)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 48555)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 48754)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 48953)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 49152)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 49351)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 49550)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 49749)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 49948)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 50147)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 50346)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 50545)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 50744)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 50943)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 51142)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 51341)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 51540)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 51739)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 51938)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 52137)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 52336)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 52535)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 52734)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 52933)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 53132)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 53331)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 53530)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 53729)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 53928)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 54127)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 54326)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 54525)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 54724)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 54923)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 55122)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 55321)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 55520)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 55719)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 55918)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 56117)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 56316)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 56515)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 56714)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 56913)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 57112)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 57311)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 57510)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 57709)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 57908)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 58107)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 58306)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 58505)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 58704)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 58903)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 59102)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 59301)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 59500)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 59699)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 59898)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 60097)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 60296)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 60495)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 60694)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 60893)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 61092)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 61291)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 61490)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 61689)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 61888)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 62087)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 62286)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 62485)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 62684)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 62883)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 63082)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 63281)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 63480)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 63679)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 63878)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 64077)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 64276)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 64475)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 64674)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 64873)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 65072)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 65271)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 65470)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 65516)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 65517)) (i32.const 1))
+(assert_return (invoke "load8_u" (i32.const 65518)) (i32.const 2))
+(assert_return (invoke "load8_u" (i32.const 65519)) (i32.const 3))
+(assert_return (invoke "load8_u" (i32.const 65520)) (i32.const 4))
+(assert_return (invoke "load8_u" (i32.const 65521)) (i32.const 5))
+(assert_return (invoke "load8_u" (i32.const 65522)) (i32.const 6))
+(assert_return (invoke "load8_u" (i32.const 65523)) (i32.const 7))
+(assert_return (invoke "load8_u" (i32.const 65524)) (i32.const 8))
+(assert_return (invoke "load8_u" (i32.const 65525)) (i32.const 9))
+(assert_return (invoke "load8_u" (i32.const 65526)) (i32.const 10))
+(assert_return (invoke "load8_u" (i32.const 65527)) (i32.const 11))
+(assert_return (invoke "load8_u" (i32.const 65528)) (i32.const 12))
+(assert_return (invoke "load8_u" (i32.const 65529)) (i32.const 13))
+(assert_return (invoke "load8_u" (i32.const 65530)) (i32.const 14))
+(assert_return (invoke "load8_u" (i32.const 65531)) (i32.const 15))
+(assert_return (invoke "load8_u" (i32.const 65532)) (i32.const 16))
+(assert_return (invoke "load8_u" (i32.const 65533)) (i32.const 17))
+(assert_return (invoke "load8_u" (i32.const 65534)) (i32.const 18))
+(assert_return (invoke "load8_u" (i32.const 65535)) (i32.const 19))
+
+(module
+  (memory (export "mem") 1  )
+  (data (i32.const 65516) "\00\01\02\03\04\05\06\07\08\09\0a\0b\0c\0d\0e\0f\10\11\12\13")
+  (func (export "run") (param $targetOffs i32) (param $srcOffs i32) (param $len i32)
+    (memory.copy (local.get $targetOffs) (local.get $srcOffs) (local.get $len)))
+  (func (export "load8_u") (param i32) (result i32)
+    (i32.load8_u (local.get 0))))
+
+(assert_trap (invoke "run" (i32.const 0) (i32.const 65516) (i32.const 4294963200))
+             "out of bounds")
+
+(assert_return (invoke "load8_u" (i32.const 0)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 1)) (i32.const 1))
+(assert_return (invoke "load8_u" (i32.const 2)) (i32.const 2))
+(assert_return (invoke "load8_u" (i32.const 3)) (i32.const 3))
+(assert_return (invoke "load8_u" (i32.const 4)) (i32.const 4))
+(assert_return (invoke "load8_u" (i32.const 5)) (i32.const 5))
+(assert_return (invoke "load8_u" (i32.const 6)) (i32.const 6))
+(assert_return (invoke "load8_u" (i32.const 7)) (i32.const 7))
+(assert_return (invoke "load8_u" (i32.const 8)) (i32.const 8))
+(assert_return (invoke "load8_u" (i32.const 9)) (i32.const 9))
+(assert_return (invoke "load8_u" (i32.const 10)) (i32.const 10))
+(assert_return (invoke "load8_u" (i32.const 11)) (i32.const 11))
+(assert_return (invoke "load8_u" (i32.const 12)) (i32.const 12))
+(assert_return (invoke "load8_u" (i32.const 13)) (i32.const 13))
+(assert_return (invoke "load8_u" (i32.const 14)) (i32.const 14))
+(assert_return (invoke "load8_u" (i32.const 15)) (i32.const 15))
+(assert_return (invoke "load8_u" (i32.const 16)) (i32.const 16))
+(assert_return (invoke "load8_u" (i32.const 17)) (i32.const 17))
+(assert_return (invoke "load8_u" (i32.const 18)) (i32.const 18))
+(assert_return (invoke "load8_u" (i32.const 19)) (i32.const 19))
+(assert_return (invoke "load8_u" (i32.const 218)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 417)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 616)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 815)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 1014)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 1213)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 1412)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 1611)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 1810)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 2009)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 2208)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 2407)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 2606)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 2805)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 3004)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 3203)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 3402)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 3601)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 3800)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 3999)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 4198)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 4397)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 4596)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 4795)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 4994)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 5193)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 5392)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 5591)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 5790)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 5989)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 6188)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 6387)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 6586)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 6785)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 6984)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 7183)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 7382)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 7581)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 7780)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 7979)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 8178)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 8377)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 8576)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 8775)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 8974)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 9173)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 9372)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 9571)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 9770)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 9969)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 10168)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 10367)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 10566)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 10765)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 10964)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 11163)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 11362)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 11561)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 11760)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 11959)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 12158)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 12357)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 12556)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 12755)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 12954)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 13153)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 13352)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 13551)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 13750)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 13949)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 14148)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 14347)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 14546)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 14745)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 14944)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 15143)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 15342)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 15541)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 15740)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 15939)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 16138)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 16337)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 16536)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 16735)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 16934)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 17133)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 17332)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 17531)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 17730)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 17929)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 18128)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 18327)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 18526)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 18725)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 18924)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 19123)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 19322)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 19521)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 19720)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 19919)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 20118)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 20317)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 20516)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 20715)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 20914)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 21113)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 21312)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 21511)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 21710)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 21909)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 22108)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 22307)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 22506)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 22705)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 22904)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 23103)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 23302)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 23501)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 23700)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 23899)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 24098)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 24297)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 24496)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 24695)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 24894)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 25093)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 25292)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 25491)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 25690)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 25889)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 26088)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 26287)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 26486)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 26685)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 26884)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 27083)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 27282)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 27481)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 27680)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 27879)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 28078)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 28277)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 28476)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 28675)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 28874)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 29073)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 29272)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 29471)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 29670)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 29869)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 30068)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 30267)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 30466)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 30665)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 30864)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 31063)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 31262)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 31461)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 31660)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 31859)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 32058)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 32257)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 32456)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 32655)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 32854)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 33053)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 33252)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 33451)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 33650)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 33849)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 34048)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 34247)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 34446)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 34645)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 34844)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 35043)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 35242)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 35441)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 35640)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 35839)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 36038)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 36237)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 36436)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 36635)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 36834)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 37033)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 37232)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 37431)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 37630)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 37829)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 38028)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 38227)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 38426)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 38625)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 38824)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 39023)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 39222)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 39421)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 39620)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 39819)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 40018)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 40217)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 40416)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 40615)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 40814)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 41013)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 41212)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 41411)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 41610)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 41809)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 42008)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 42207)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 42406)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 42605)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 42804)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 43003)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 43202)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 43401)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 43600)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 43799)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 43998)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 44197)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 44396)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 44595)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 44794)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 44993)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 45192)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 45391)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 45590)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 45789)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 45988)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 46187)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 46386)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 46585)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 46784)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 46983)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 47182)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 47381)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 47580)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 47779)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 47978)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 48177)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 48376)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 48575)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 48774)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 48973)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 49172)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 49371)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 49570)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 49769)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 49968)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 50167)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 50366)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 50565)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 50764)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 50963)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 51162)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 51361)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 51560)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 51759)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 51958)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 52157)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 52356)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 52555)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 52754)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 52953)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 53152)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 53351)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 53550)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 53749)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 53948)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 54147)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 54346)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 54545)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 54744)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 54943)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 55142)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 55341)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 55540)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 55739)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 55938)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 56137)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 56336)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 56535)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 56734)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 56933)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 57132)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 57331)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 57530)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 57729)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 57928)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 58127)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 58326)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 58525)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 58724)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 58923)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 59122)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 59321)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 59520)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 59719)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 59918)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 60117)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 60316)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 60515)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 60714)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 60913)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 61112)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 61311)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 61510)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 61709)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 61908)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 62107)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 62306)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 62505)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 62704)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 62903)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 63102)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 63301)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 63500)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 63699)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 63898)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 64097)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 64296)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 64495)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 64694)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 64893)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 65092)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 65291)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 65490)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 65516)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 65517)) (i32.const 1))
+(assert_return (invoke "load8_u" (i32.const 65518)) (i32.const 2))
+(assert_return (invoke "load8_u" (i32.const 65519)) (i32.const 3))
+(assert_return (invoke "load8_u" (i32.const 65520)) (i32.const 4))
+(assert_return (invoke "load8_u" (i32.const 65521)) (i32.const 5))
+(assert_return (invoke "load8_u" (i32.const 65522)) (i32.const 6))
+(assert_return (invoke "load8_u" (i32.const 65523)) (i32.const 7))
+(assert_return (invoke "load8_u" (i32.const 65524)) (i32.const 8))
+(assert_return (invoke "load8_u" (i32.const 65525)) (i32.const 9))
+(assert_return (invoke "load8_u" (i32.const 65526)) (i32.const 10))
+(assert_return (invoke "load8_u" (i32.const 65527)) (i32.const 11))
+(assert_return (invoke "load8_u" (i32.const 65528)) (i32.const 12))
+(assert_return (invoke "load8_u" (i32.const 65529)) (i32.const 13))
+(assert_return (invoke "load8_u" (i32.const 65530)) (i32.const 14))
+(assert_return (invoke "load8_u" (i32.const 65531)) (i32.const 15))
+(assert_return (invoke "load8_u" (i32.const 65532)) (i32.const 16))
+(assert_return (invoke "load8_u" (i32.const 65533)) (i32.const 17))
+(assert_return (invoke "load8_u" (i32.const 65534)) (i32.const 18))
+(assert_return (invoke "load8_u" (i32.const 65535)) (i32.const 19))
+
+(module
+  (memory (export "mem") 1 1 )
+  (data (i32.const 61440) "\00\01\02\03\04\05\06\07\08\09\0a\0b\0c\0d\0e\0f\10\11\12\13")
+  (func (export "run") (param $targetOffs i32) (param $srcOffs i32) (param $len i32)
+    (memory.copy (local.get $targetOffs) (local.get $srcOffs) (local.get $len)))
+  (func (export "load8_u") (param i32) (result i32)
+    (i32.load8_u (local.get 0))))
+
+(assert_trap (invoke "run" (i32.const 65516) (i32.const 61440) (i32.const 4294967040))
+             "out of bounds")
+
+(assert_return (invoke "load8_u" (i32.const 198)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 397)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 596)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 795)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 994)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 1193)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 1392)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 1591)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 1790)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 1989)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 2188)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 2387)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 2586)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 2785)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 2984)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 3183)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 3382)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 3581)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 3780)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 3979)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 4178)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 4377)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 4576)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 4775)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 4974)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 5173)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 5372)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 5571)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 5770)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 5969)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 6168)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 6367)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 6566)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 6765)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 6964)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 7163)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 7362)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 7561)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 7760)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 7959)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 8158)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 8357)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 8556)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 8755)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 8954)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 9153)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 9352)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 9551)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 9750)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 9949)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 10148)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 10347)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 10546)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 10745)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 10944)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 11143)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 11342)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 11541)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 11740)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 11939)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 12138)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 12337)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 12536)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 12735)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 12934)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 13133)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 13332)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 13531)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 13730)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 13929)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 14128)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 14327)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 14526)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 14725)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 14924)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 15123)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 15322)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 15521)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 15720)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 15919)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 16118)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 16317)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 16516)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 16715)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 16914)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 17113)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 17312)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 17511)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 17710)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 17909)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 18108)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 18307)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 18506)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 18705)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 18904)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 19103)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 19302)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 19501)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 19700)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 19899)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 20098)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 20297)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 20496)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 20695)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 20894)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 21093)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 21292)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 21491)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 21690)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 21889)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 22088)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 22287)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 22486)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 22685)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 22884)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 23083)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 23282)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 23481)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 23680)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 23879)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 24078)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 24277)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 24476)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 24675)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 24874)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 25073)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 25272)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 25471)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 25670)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 25869)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 26068)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 26267)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 26466)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 26665)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 26864)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 27063)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 27262)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 27461)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 27660)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 27859)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 28058)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 28257)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 28456)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 28655)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 28854)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 29053)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 29252)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 29451)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 29650)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 29849)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 30048)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 30247)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 30446)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 30645)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 30844)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 31043)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 31242)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 31441)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 31640)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 31839)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 32038)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 32237)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 32436)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 32635)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 32834)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 33033)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 33232)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 33431)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 33630)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 33829)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 34028)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 34227)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 34426)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 34625)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 34824)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 35023)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 35222)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 35421)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 35620)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 35819)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 36018)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 36217)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 36416)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 36615)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 36814)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 37013)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 37212)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 37411)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 37610)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 37809)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 38008)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 38207)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 38406)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 38605)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 38804)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 39003)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 39202)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 39401)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 39600)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 39799)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 39998)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 40197)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 40396)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 40595)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 40794)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 40993)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 41192)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 41391)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 41590)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 41789)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 41988)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 42187)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 42386)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 42585)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 42784)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 42983)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 43182)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 43381)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 43580)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 43779)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 43978)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 44177)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 44376)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 44575)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 44774)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 44973)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 45172)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 45371)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 45570)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 45769)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 45968)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 46167)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 46366)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 46565)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 46764)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 46963)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 47162)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 47361)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 47560)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 47759)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 47958)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 48157)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 48356)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 48555)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 48754)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 48953)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 49152)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 49351)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 49550)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 49749)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 49948)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 50147)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 50346)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 50545)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 50744)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 50943)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 51142)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 51341)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 51540)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 51739)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 51938)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 52137)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 52336)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 52535)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 52734)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 52933)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 53132)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 53331)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 53530)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 53729)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 53928)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 54127)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 54326)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 54525)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 54724)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 54923)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 55122)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 55321)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 55520)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 55719)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 55918)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 56117)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 56316)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 56515)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 56714)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 56913)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 57112)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 57311)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 57510)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 57709)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 57908)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 58107)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 58306)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 58505)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 58704)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 58903)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 59102)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 59301)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 59500)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 59699)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 59898)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 60097)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 60296)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 60495)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 60694)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 60893)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 61092)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 61291)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 61440)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 61441)) (i32.const 1))
+(assert_return (invoke "load8_u" (i32.const 61442)) (i32.const 2))
+(assert_return (invoke "load8_u" (i32.const 61443)) (i32.const 3))
+(assert_return (invoke "load8_u" (i32.const 61444)) (i32.const 4))
+(assert_return (invoke "load8_u" (i32.const 61445)) (i32.const 5))
+(assert_return (invoke "load8_u" (i32.const 61446)) (i32.const 6))
+(assert_return (invoke "load8_u" (i32.const 61447)) (i32.const 7))
+(assert_return (invoke "load8_u" (i32.const 61448)) (i32.const 8))
+(assert_return (invoke "load8_u" (i32.const 61449)) (i32.const 9))
+(assert_return (invoke "load8_u" (i32.const 61450)) (i32.const 10))
+(assert_return (invoke "load8_u" (i32.const 61451)) (i32.const 11))
+(assert_return (invoke "load8_u" (i32.const 61452)) (i32.const 12))
+(assert_return (invoke "load8_u" (i32.const 61453)) (i32.const 13))
+(assert_return (invoke "load8_u" (i32.const 61454)) (i32.const 14))
+(assert_return (invoke "load8_u" (i32.const 61455)) (i32.const 15))
+(assert_return (invoke "load8_u" (i32.const 61456)) (i32.const 16))
+(assert_return (invoke "load8_u" (i32.const 61457)) (i32.const 17))
+(assert_return (invoke "load8_u" (i32.const 61458)) (i32.const 18))
+(assert_return (invoke "load8_u" (i32.const 61459)) (i32.const 19))
+(assert_return (invoke "load8_u" (i32.const 61510)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 61709)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 61908)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 62107)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 62306)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 62505)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 62704)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 62903)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 63102)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 63301)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 63500)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 63699)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 63898)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 64097)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 64296)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 64495)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 64694)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 64893)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 65092)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 65291)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 65490)) (i32.const 0))
+
+(assert_invalid
+  (module
+    (func (export "testfn")
+      (memory.copy (i32.const 10) (i32.const 20) (i32.const 30))))
+  "unknown memory 0")
+
+
+(assert_invalid
+  (module
+    (memory 1 1)
+    (func (export "testfn")
+      (memory.copy (i32.const 10) (i32.const 20) (f32.const 30))))
+  "type mismatch")
+
+
+(assert_invalid
+  (module
+    (memory 1 1)
+    (func (export "testfn")
+      (memory.copy (i32.const 10) (i32.const 20) (i64.const 30))))
+  "type mismatch")
+
+
+(assert_invalid
+  (module
+    (memory 1 1)
+    (func (export "testfn")
+      (memory.copy (i32.const 10) (i32.const 20) (f64.const 30))))
+  "type mismatch")
+
+
+(assert_invalid
+  (module
+    (memory 1 1)
+    (func (export "testfn")
+      (memory.copy (i32.const 10) (f32.const 20) (i32.const 30))))
+  "type mismatch")
+
+
+(assert_invalid
+  (module
+    (memory 1 1)
+    (func (export "testfn")
+      (memory.copy (i32.const 10) (f32.const 20) (f32.const 30))))
+  "type mismatch")
+
+
+(assert_invalid
+  (module
+    (memory 1 1)
+    (func (export "testfn")
+      (memory.copy (i32.const 10) (f32.const 20) (i64.const 30))))
+  "type mismatch")
+
+
+(assert_invalid
+  (module
+    (memory 1 1)
+    (func (export "testfn")
+      (memory.copy (i32.const 10) (f32.const 20) (f64.const 30))))
+  "type mismatch")
+
+
+(assert_invalid
+  (module
+    (memory 1 1)
+    (func (export "testfn")
+      (memory.copy (i32.const 10) (i64.const 20) (i32.const 30))))
+  "type mismatch")
+
+
+(assert_invalid
+  (module
+    (memory 1 1)
+    (func (export "testfn")
+      (memory.copy (i32.const 10) (i64.const 20) (f32.const 30))))
+  "type mismatch")
+
+
+(assert_invalid
+  (module
+    (memory 1 1)
+    (func (export "testfn")
+      (memory.copy (i32.const 10) (i64.const 20) (i64.const 30))))
+  "type mismatch")
+
+
+(assert_invalid
+  (module
+    (memory 1 1)
+    (func (export "testfn")
+      (memory.copy (i32.const 10) (i64.const 20) (f64.const 30))))
+  "type mismatch")
+
+
+(assert_invalid
+  (module
+    (memory 1 1)
+    (func (export "testfn")
+      (memory.copy (i32.const 10) (f64.const 20) (i32.const 30))))
+  "type mismatch")
+
+
+(assert_invalid
+  (module
+    (memory 1 1)
+    (func (export "testfn")
+      (memory.copy (i32.const 10) (f64.const 20) (f32.const 30))))
+  "type mismatch")
+
+
+(assert_invalid
+  (module
+    (memory 1 1)
+    (func (export "testfn")
+      (memory.copy (i32.const 10) (f64.const 20) (i64.const 30))))
+  "type mismatch")
+
+
+(assert_invalid
+  (module
+    (memory 1 1)
+    (func (export "testfn")
+      (memory.copy (i32.const 10) (f64.const 20) (f64.const 30))))
+  "type mismatch")
+
+
+(assert_invalid
+  (module
+    (memory 1 1)
+    (func (export "testfn")
+      (memory.copy (f32.const 10) (i32.const 20) (i32.const 30))))
+  "type mismatch")
+
+
+(assert_invalid
+  (module
+    (memory 1 1)
+    (func (export "testfn")
+      (memory.copy (f32.const 10) (i32.const 20) (f32.const 30))))
+  "type mismatch")
+
+
+(assert_invalid
+  (module
+    (memory 1 1)
+    (func (export "testfn")
+      (memory.copy (f32.const 10) (i32.const 20) (i64.const 30))))
+  "type mismatch")
+
+
+(assert_invalid
+  (module
+    (memory 1 1)
+    (func (export "testfn")
+      (memory.copy (f32.const 10) (i32.const 20) (f64.const 30))))
+  "type mismatch")
+
+
+(assert_invalid
+  (module
+    (memory 1 1)
+    (func (export "testfn")
+      (memory.copy (f32.const 10) (f32.const 20) (i32.const 30))))
+  "type mismatch")
+
+
+(assert_invalid
+  (module
+    (memory 1 1)
+    (func (export "testfn")
+      (memory.copy (f32.const 10) (f32.const 20) (f32.const 30))))
+  "type mismatch")
+
+
+(assert_invalid
+  (module
+    (memory 1 1)
+    (func (export "testfn")
+      (memory.copy (f32.const 10) (f32.const 20) (i64.const 30))))
+  "type mismatch")
+
+
+(assert_invalid
+  (module
+    (memory 1 1)
+    (func (export "testfn")
+      (memory.copy (f32.const 10) (f32.const 20) (f64.const 30))))
+  "type mismatch")
+
+
+(assert_invalid
+  (module
+    (memory 1 1)
+    (func (export "testfn")
+      (memory.copy (f32.const 10) (i64.const 20) (i32.const 30))))
+  "type mismatch")
+
+
+(assert_invalid
+  (module
+    (memory 1 1)
+    (func (export "testfn")
+      (memory.copy (f32.const 10) (i64.const 20) (f32.const 30))))
+  "type mismatch")
+
+
+(assert_invalid
+  (module
+    (memory 1 1)
+    (func (export "testfn")
+      (memory.copy (f32.const 10) (i64.const 20) (i64.const 30))))
+  "type mismatch")
+
+
+(assert_invalid
+  (module
+    (memory 1 1)
+    (func (export "testfn")
+      (memory.copy (f32.const 10) (i64.const 20) (f64.const 30))))
+  "type mismatch")
+
+
+(assert_invalid
+  (module
+    (memory 1 1)
+    (func (export "testfn")
+      (memory.copy (f32.const 10) (f64.const 20) (i32.const 30))))
+  "type mismatch")
+
+
+(assert_invalid
+  (module
+    (memory 1 1)
+    (func (export "testfn")
+      (memory.copy (f32.const 10) (f64.const 20) (f32.const 30))))
+  "type mismatch")
+
+
+(assert_invalid
+  (module
+    (memory 1 1)
+    (func (export "testfn")
+      (memory.copy (f32.const 10) (f64.const 20) (i64.const 30))))
+  "type mismatch")
+
+
+(assert_invalid
+  (module
+    (memory 1 1)
+    (func (export "testfn")
+      (memory.copy (f32.const 10) (f64.const 20) (f64.const 30))))
+  "type mismatch")
+
+
+(assert_invalid
+  (module
+    (memory 1 1)
+    (func (export "testfn")
+      (memory.copy (i64.const 10) (i32.const 20) (i32.const 30))))
+  "type mismatch")
+
+
+(assert_invalid
+  (module
+    (memory 1 1)
+    (func (export "testfn")
+      (memory.copy (i64.const 10) (i32.const 20) (f32.const 30))))
+  "type mismatch")
+
+
+(assert_invalid
+  (module
+    (memory 1 1)
+    (func (export "testfn")
+      (memory.copy (i64.const 10) (i32.const 20) (i64.const 30))))
+  "type mismatch")
+
+
+(assert_invalid
+  (module
+    (memory 1 1)
+    (func (export "testfn")
+      (memory.copy (i64.const 10) (i32.const 20) (f64.const 30))))
+  "type mismatch")
+
+
+(assert_invalid
+  (module
+    (memory 1 1)
+    (func (export "testfn")
+      (memory.copy (i64.const 10) (f32.const 20) (i32.const 30))))
+  "type mismatch")
+
+
+(assert_invalid
+  (module
+    (memory 1 1)
+    (func (export "testfn")
+      (memory.copy (i64.const 10) (f32.const 20) (f32.const 30))))
+  "type mismatch")
+
+
+(assert_invalid
+  (module
+    (memory 1 1)
+    (func (export "testfn")
+      (memory.copy (i64.const 10) (f32.const 20) (i64.const 30))))
+  "type mismatch")
+
+
+(assert_invalid
+  (module
+    (memory 1 1)
+    (func (export "testfn")
+      (memory.copy (i64.const 10) (f32.const 20) (f64.const 30))))
+  "type mismatch")
+
+
+(assert_invalid
+  (module
+    (memory 1 1)
+    (func (export "testfn")
+      (memory.copy (i64.const 10) (i64.const 20) (i32.const 30))))
+  "type mismatch")
+
+
+(assert_invalid
+  (module
+    (memory 1 1)
+    (func (export "testfn")
+      (memory.copy (i64.const 10) (i64.const 20) (f32.const 30))))
+  "type mismatch")
+
+
+(assert_invalid
+  (module
+    (memory 1 1)
+    (func (export "testfn")
+      (memory.copy (i64.const 10) (i64.const 20) (i64.const 30))))
+  "type mismatch")
+
+
+(assert_invalid
+  (module
+    (memory 1 1)
+    (func (export "testfn")
+      (memory.copy (i64.const 10) (i64.const 20) (f64.const 30))))
+  "type mismatch")
+
+
+(assert_invalid
+  (module
+    (memory 1 1)
+    (func (export "testfn")
+      (memory.copy (i64.const 10) (f64.const 20) (i32.const 30))))
+  "type mismatch")
+
+
+(assert_invalid
+  (module
+    (memory 1 1)
+    (func (export "testfn")
+      (memory.copy (i64.const 10) (f64.const 20) (f32.const 30))))
+  "type mismatch")
+
+
+(assert_invalid
+  (module
+    (memory 1 1)
+    (func (export "testfn")
+      (memory.copy (i64.const 10) (f64.const 20) (i64.const 30))))
+  "type mismatch")
+
+
+(assert_invalid
+  (module
+    (memory 1 1)
+    (func (export "testfn")
+      (memory.copy (i64.const 10) (f64.const 20) (f64.const 30))))
+  "type mismatch")
+
+
+(assert_invalid
+  (module
+    (memory 1 1)
+    (func (export "testfn")
+      (memory.copy (f64.const 10) (i32.const 20) (i32.const 30))))
+  "type mismatch")
+
+
+(assert_invalid
+  (module
+    (memory 1 1)
+    (func (export "testfn")
+      (memory.copy (f64.const 10) (i32.const 20) (f32.const 30))))
+  "type mismatch")
+
+
+(assert_invalid
+  (module
+    (memory 1 1)
+    (func (export "testfn")
+      (memory.copy (f64.const 10) (i32.const 20) (i64.const 30))))
+  "type mismatch")
+
+
+(assert_invalid
+  (module
+    (memory 1 1)
+    (func (export "testfn")
+      (memory.copy (f64.const 10) (i32.const 20) (f64.const 30))))
+  "type mismatch")
+
+
+(assert_invalid
+  (module
+    (memory 1 1)
+    (func (export "testfn")
+      (memory.copy (f64.const 10) (f32.const 20) (i32.const 30))))
+  "type mismatch")
+
+
+(assert_invalid
+  (module
+    (memory 1 1)
+    (func (export "testfn")
+      (memory.copy (f64.const 10) (f32.const 20) (f32.const 30))))
+  "type mismatch")
+
+
+(assert_invalid
+  (module
+    (memory 1 1)
+    (func (export "testfn")
+      (memory.copy (f64.const 10) (f32.const 20) (i64.const 30))))
+  "type mismatch")
+
+
+(assert_invalid
+  (module
+    (memory 1 1)
+    (func (export "testfn")
+      (memory.copy (f64.const 10) (f32.const 20) (f64.const 30))))
+  "type mismatch")
+
+
+(assert_invalid
+  (module
+    (memory 1 1)
+    (func (export "testfn")
+      (memory.copy (f64.const 10) (i64.const 20) (i32.const 30))))
+  "type mismatch")
+
+
+(assert_invalid
+  (module
+    (memory 1 1)
+    (func (export "testfn")
+      (memory.copy (f64.const 10) (i64.const 20) (f32.const 30))))
+  "type mismatch")
+
+
+(assert_invalid
+  (module
+    (memory 1 1)
+    (func (export "testfn")
+      (memory.copy (f64.const 10) (i64.const 20) (i64.const 30))))
+  "type mismatch")
+
+
+(assert_invalid
+  (module
+    (memory 1 1)
+    (func (export "testfn")
+      (memory.copy (f64.const 10) (i64.const 20) (f64.const 30))))
+  "type mismatch")
+
+
+(assert_invalid
+  (module
+    (memory 1 1)
+    (func (export "testfn")
+      (memory.copy (f64.const 10) (f64.const 20) (i32.const 30))))
+  "type mismatch")
+
+
+(assert_invalid
+  (module
+    (memory 1 1)
+    (func (export "testfn")
+      (memory.copy (f64.const 10) (f64.const 20) (f32.const 30))))
+  "type mismatch")
+
+
+(assert_invalid
+  (module
+    (memory 1 1)
+    (func (export "testfn")
+      (memory.copy (f64.const 10) (f64.const 20) (i64.const 30))))
+  "type mismatch")
+
+
+(assert_invalid
+  (module
+    (memory 1 1)
+    (func (export "testfn")
+      (memory.copy (f64.const 10) (f64.const 20) (f64.const 30))))
+  "type mismatch")
+
+
+(module
+  (memory 1 1)
+  (func (export "test")
+    (memory.fill (i32.const 10) (i32.const 0x55) (i32.const 10))
+    (memory.copy (i32.const 9) (i32.const 10) (i32.const 5)))
+  
+  (func (export "checkRange") (param $from i32) (param $to i32) (param $expected i32) (result i32)
+   (loop $cont
+     (if (i32.eq (local.get $from) (local.get $to))
+         (then
+           (return (i32.const -1))))
+     (if (i32.eq (i32.load8_u (local.get $from)) (local.get $expected))
+         (then
+           (local.set $from (i32.add (local.get $from) (i32.const 1)))
+           (br $cont))))
+   (return (local.get $from)))
+)
+(invoke "test")
+
+(assert_return (invoke "checkRange" (i32.const 0) (i32.const 9) (i32.const 0))
+               (i32.const -1))
+(assert_return (invoke "checkRange" (i32.const 9) (i32.const 20) (i32.const 85))
+               (i32.const -1))
+(assert_return (invoke "checkRange" (i32.const 20) (i32.const 65536) (i32.const 0))
+               (i32.const -1))
+
+(module
+  (memory 1 1)
+  (func (export "test")
+    (memory.fill (i32.const 10) (i32.const 0x55) (i32.const 10))
+    (memory.copy (i32.const 16) (i32.const 15) (i32.const 5)))
+  
+  (func (export "checkRange") (param $from i32) (param $to i32) (param $expected i32) (result i32)
+   (loop $cont
+     (if (i32.eq (local.get $from) (local.get $to))
+         (then
+           (return (i32.const -1))))
+     (if (i32.eq (i32.load8_u (local.get $from)) (local.get $expected))
+         (then
+           (local.set $from (i32.add (local.get $from) (i32.const 1)))
+           (br $cont))))
+   (return (local.get $from)))
+)
+(invoke "test")
+
+(assert_return (invoke "checkRange" (i32.const 0) (i32.const 10) (i32.const 0))
+               (i32.const -1))
+(assert_return (invoke "checkRange" (i32.const 10) (i32.const 21) (i32.const 85))
+               (i32.const -1))
+(assert_return (invoke "checkRange" (i32.const 21) (i32.const 65536) (i32.const 0))
+               (i32.const -1))
+
+(module
+  (memory 1 1)
+  (func (export "test")
+    (memory.copy (i32.const 0xFF00) (i32.const 0x8000) (i32.const 257))))
+(assert_trap (invoke "test") "out of bounds")
+
+
+(module
+  (memory 1 1)
+  (func (export "test")
+    (memory.copy (i32.const 0xFFFFFF00) (i32.const 0x4000) (i32.const 257))))
+(assert_trap (invoke "test") "out of bounds")
+
+
+(module
+  (memory 1 1)
+  (func (export "test")
+    (memory.copy (i32.const 0x8000) (i32.const 0xFF00) (i32.const 257))))
+(assert_trap (invoke "test") "out of bounds")
+
+
+(module
+ (memory 1 1)
+ (func (export "test")
+   (memory.copy (i32.const 0x4000) (i32.const 0xFFFFFF00) (i32.const 257))))
+(assert_trap (invoke "test") "out of bounds")
+
+
+(module
+  (memory 1 1)
+  (func (export "test")
+    (memory.fill (i32.const 0x0000) (i32.const 0x55) (i32.const 0x8000))
+    (memory.fill (i32.const 0x8000) (i32.const 0xAA) (i32.const 0x8000))
+    (memory.copy (i32.const 0x9000) (i32.const 0x7000) (i32.const 0)))
+  
+  (func (export "checkRange") (param $from i32) (param $to i32) (param $expected i32) (result i32)
+   (loop $cont
+     (if (i32.eq (local.get $from) (local.get $to))
+         (then
+           (return (i32.const -1))))
+     (if (i32.eq (i32.load8_u (local.get $from)) (local.get $expected))
+         (then
+           (local.set $from (i32.add (local.get $from) (i32.const 1)))
+           (br $cont))))
+   (return (local.get $from)))
+)
+(invoke "test")
+
+(assert_return (invoke "checkRange" (i32.const 0) (i32.const 32768) (i32.const 85))
+               (i32.const -1))
+(assert_return (invoke "checkRange" (i32.const 32768) (i32.const 65536) (i32.const 170))
+               (i32.const -1))
+
+(module
+  (memory 1 1)
+  (func (export "test")
+    (memory.copy (i32.const 0x10000) (i32.const 0x7000) (i32.const 0))))
+(invoke "test")
+
+
+(module
+  (memory 1 1)
+  (func (export "test")
+    (memory.copy (i32.const 0x9000) (i32.const 0x10000) (i32.const 0))))
+(invoke "test")
+
+
+(module
+       (memory 1 1)
+       (func (export "test")
+         (memory.fill (i32.const 17767) (i32.const 1) (i32.const 1344))
+         (memory.fill (i32.const 39017) (i32.const 2) (i32.const 1055))
+         (memory.fill (i32.const 56401) (i32.const 3) (i32.const 988))
+         (memory.fill (i32.const 37962) (i32.const 4) (i32.const 322))
+         (memory.fill (i32.const 7977) (i32.const 5) (i32.const 1994))
+         (memory.fill (i32.const 22714) (i32.const 6) (i32.const 3036))
+         (memory.fill (i32.const 16882) (i32.const 7) (i32.const 2372))
+         (memory.fill (i32.const 43491) (i32.const 8) (i32.const 835))
+         (memory.fill (i32.const 124) (i32.const 9) (i32.const 1393))
+         (memory.fill (i32.const 2132) (i32.const 10) (i32.const 2758))
+         (memory.fill (i32.const 8987) (i32.const 11) (i32.const 3098))
+         (memory.fill (i32.const 52711) (i32.const 12) (i32.const 741))
+         (memory.fill (i32.const 3958) (i32.const 13) (i32.const 2823))
+         (memory.fill (i32.const 49715) (i32.const 14) (i32.const 1280))
+         (memory.fill (i32.const 50377) (i32.const 15) (i32.const 1466))
+         (memory.fill (i32.const 20493) (i32.const 16) (i32.const 3158))
+         (memory.fill (i32.const 47665) (i32.const 17) (i32.const 544))
+         (memory.fill (i32.const 12451) (i32.const 18) (i32.const 2669))
+         (memory.fill (i32.const 24869) (i32.const 19) (i32.const 2651))
+         (memory.fill (i32.const 45317) (i32.const 20) (i32.const 1570))
+         (memory.fill (i32.const 43096) (i32.const 21) (i32.const 1691))
+         (memory.fill (i32.const 33886) (i32.const 22) (i32.const 646))
+         (memory.fill (i32.const 48555) (i32.const 23) (i32.const 1858))
+         (memory.fill (i32.const 53453) (i32.const 24) (i32.const 2657))
+         (memory.fill (i32.const 30363) (i32.const 25) (i32.const 981))
+         (memory.fill (i32.const 9300) (i32.const 26) (i32.const 1807))
+         (memory.fill (i32.const 50190) (i32.const 27) (i32.const 487))
+         (memory.fill (i32.const 62753) (i32.const 28) (i32.const 530))
+         (memory.fill (i32.const 36316) (i32.const 29) (i32.const 943))
+         (memory.fill (i32.const 6768) (i32.const 30) (i32.const 381))
+         (memory.fill (i32.const 51262) (i32.const 31) (i32.const 3089))
+         (memory.fill (i32.const 49729) (i32.const 32) (i32.const 658))
+         (memory.fill (i32.const 44540) (i32.const 33) (i32.const 1702))
+         (memory.fill (i32.const 33342) (i32.const 34) (i32.const 1092))
+         (memory.fill (i32.const 50814) (i32.const 35) (i32.const 1410))
+         (memory.fill (i32.const 47594) (i32.const 36) (i32.const 2204))
+         (memory.fill (i32.const 54123) (i32.const 37) (i32.const 2394))
+         (memory.fill (i32.const 55183) (i32.const 38) (i32.const 250))
+         (memory.fill (i32.const 22620) (i32.const 39) (i32.const 2097))
+         (memory.fill (i32.const 17132) (i32.const 40) (i32.const 3264))
+         (memory.fill (i32.const 54331) (i32.const 41) (i32.const 3299))
+         (memory.fill (i32.const 39474) (i32.const 42) (i32.const 2796))
+         (memory.fill (i32.const 36156) (i32.const 43) (i32.const 2070))
+         (memory.fill (i32.const 35308) (i32.const 44) (i32.const 2763))
+         (memory.fill (i32.const 32731) (i32.const 45) (i32.const 312))
+         (memory.fill (i32.const 63746) (i32.const 46) (i32.const 192))
+         (memory.fill (i32.const 30974) (i32.const 47) (i32.const 596))
+         (memory.fill (i32.const 16635) (i32.const 48) (i32.const 501))
+         (memory.fill (i32.const 57002) (i32.const 49) (i32.const 686))
+         (memory.fill (i32.const 34299) (i32.const 50) (i32.const 385))
+         (memory.fill (i32.const 60881) (i32.const 51) (i32.const 903))
+         (memory.fill (i32.const 61445) (i32.const 52) (i32.const 2390))
+         (memory.fill (i32.const 46972) (i32.const 53) (i32.const 1441))
+         (memory.fill (i32.const 25973) (i32.const 54) (i32.const 3162))
+         (memory.fill (i32.const 5566) (i32.const 55) (i32.const 2135))
+         (memory.fill (i32.const 35977) (i32.const 56) (i32.const 519))
+         (memory.fill (i32.const 44892) (i32.const 57) (i32.const 3280))
+         (memory.fill (i32.const 46760) (i32.const 58) (i32.const 1678))
+         (memory.fill (i32.const 46607) (i32.const 59) (i32.const 3168))
+         (memory.fill (i32.const 22449) (i32.const 60) (i32.const 1441))
+         (memory.fill (i32.const 58609) (i32.const 61) (i32.const 663))
+         (memory.fill (i32.const 32261) (i32.const 62) (i32.const 1671))
+         (memory.fill (i32.const 3063) (i32.const 63) (i32.const 721))
+         (memory.fill (i32.const 34025) (i32.const 64) (i32.const 84))
+         (memory.fill (i32.const 33338) (i32.const 65) (i32.const 2029))
+         (memory.fill (i32.const 36810) (i32.const 66) (i32.const 29))
+         (memory.fill (i32.const 19147) (i32.const 67) (i32.const 3034))
+         (memory.fill (i32.const 12616) (i32.const 68) (i32.const 1043))
+         (memory.fill (i32.const 18276) (i32.const 69) (i32.const 3324))
+         (memory.fill (i32.const 4639) (i32.const 70) (i32.const 1091))
+         (memory.fill (i32.const 16158) (i32.const 71) (i32.const 1997))
+         (memory.fill (i32.const 18204) (i32.const 72) (i32.const 2259))
+         (memory.fill (i32.const 50532) (i32.const 73) (i32.const 3189))
+         (memory.fill (i32.const 11028) (i32.const 74) (i32.const 1968))
+         (memory.fill (i32.const 15962) (i32.const 75) (i32.const 1455))
+         (memory.fill (i32.const 45406) (i32.const 76) (i32.const 1177))
+         (memory.fill (i32.const 54137) (i32.const 77) (i32.const 1568))
+         (memory.fill (i32.const 33083) (i32.const 78) (i32.const 1642))
+         (memory.fill (i32.const 61028) (i32.const 79) (i32.const 3284))
+         (memory.fill (i32.const 51729) (i32.const 80) (i32.const 223))
+         (memory.fill (i32.const 4361) (i32.const 81) (i32.const 2171))
+         (memory.fill (i32.const 57514) (i32.const 82) (i32.const 1322))
+         (memory.fill (i32.const 55724) (i32.const 83) (i32.const 2648))
+         (memory.fill (i32.const 24091) (i32.const 84) (i32.const 1045))
+         (memory.fill (i32.const 43183) (i32.const 85) (i32.const 3097))
+         (memory.fill (i32.const 32307) (i32.const 86) (i32.const 2796))
+         (memory.fill (i32.const 3811) (i32.const 87) (i32.const 2010))
+         (memory.fill (i32.const 54856) (i32.const 88) (i32.const 0))
+         (memory.fill (i32.const 49941) (i32.const 89) (i32.const 2069))
+         (memory.fill (i32.const 20411) (i32.const 90) (i32.const 2896))
+         (memory.fill (i32.const 33826) (i32.const 91) (i32.const 192))
+         (memory.fill (i32.const 9402) (i32.const 92) (i32.const 2195))
+         (memory.fill (i32.const 12413) (i32.const 93) (i32.const 24))
+         (memory.fill (i32.const 14091) (i32.const 94) (i32.const 577))
+         (memory.fill (i32.const 44058) (i32.const 95) (i32.const 2089))
+         (memory.fill (i32.const 36735) (i32.const 96) (i32.const 3436))
+         (memory.fill (i32.const 23288) (i32.const 97) (i32.const 2765))
+         (memory.fill (i32.const 6392) (i32.const 98) (i32.const 830))
+         (memory.fill (i32.const 33307) (i32.const 99) (i32.const 1938))
+         (memory.fill (i32.const 21941) (i32.const 100) (i32.const 2750))
+         (memory.copy (i32.const 59214) (i32.const 54248) (i32.const 2098))
+         (memory.copy (i32.const 63026) (i32.const 39224) (i32.const 230))
+         (memory.copy (i32.const 51833) (i32.const 23629) (i32.const 2300))
+         (memory.copy (i32.const 6708) (i32.const 23996) (i32.const 639))
+         (memory.copy (i32.const 6990) (i32.const 33399) (i32.const 1097))
+         (memory.copy (i32.const 19403) (i32.const 10348) (i32.const 3197))
+         (memory.copy (i32.const 27308) (i32.const 54406) (i32.const 100))
+         (memory.copy (i32.const 27221) (i32.const 43682) (i32.const 1717))
+         (memory.copy (i32.const 60528) (i32.const 8629) (i32.const 119))
+         (memory.copy (i32.const 5947) (i32.const 2308) (i32.const 658))
+         (memory.copy (i32.const 4787) (i32.const 51631) (i32.const 2269))
+         (memory.copy (i32.const 12617) (i32.const 19197) (i32.const 833))
+         (memory.copy (i32.const 11854) (i32.const 46505) (i32.const 3300))
+         (memory.copy (i32.const 11376) (i32.const 45012) (i32.const 2281))
+         (memory.copy (i32.const 34186) (i32.const 6697) (i32.const 2572))
+         (memory.copy (i32.const 4936) (i32.const 1690) (i32.const 1328))
+         (memory.copy (i32.const 63164) (i32.const 7637) (i32.const 1670))
+         (memory.copy (i32.const 44568) (i32.const 18344) (i32.const 33))
+         (memory.copy (i32.const 43918) (i32.const 22348) (i32.const 1427))
+         (memory.copy (i32.const 46637) (i32.const 49819) (i32.const 1434))
+         (memory.copy (i32.const 63684) (i32.const 8755) (i32.const 834))
+         (memory.copy (i32.const 33485) (i32.const 20131) (i32.const 3317))
+         (memory.copy (i32.const 40575) (i32.const 54317) (i32.const 3201))
+         (memory.copy (i32.const 25812) (i32.const 59254) (i32.const 2452))
+         (memory.copy (i32.const 19678) (i32.const 56882) (i32.const 346))
+         (memory.copy (i32.const 15852) (i32.const 35914) (i32.const 2430))
+         (memory.copy (i32.const 11824) (i32.const 35574) (i32.const 300))
+         (memory.copy (i32.const 59427) (i32.const 13957) (i32.const 3153))
+         (memory.copy (i32.const 34299) (i32.const 60594) (i32.const 1281))
+         (memory.copy (i32.const 8964) (i32.const 12276) (i32.const 943))
+         (memory.copy (i32.const 2827) (i32.const 10425) (i32.const 1887))
+         (memory.copy (i32.const 43194) (i32.const 43910) (i32.const 738))
+         (memory.copy (i32.const 63038) (i32.const 18949) (i32.const 122))
+         (memory.copy (i32.const 24044) (i32.const 44761) (i32.const 1755))
+         (memory.copy (i32.const 22608) (i32.const 14755) (i32.const 702))
+         (memory.copy (i32.const 11284) (i32.const 26579) (i32.const 1830))
+         (memory.copy (i32.const 23092) (i32.const 20471) (i32.const 1064))
+         (memory.copy (i32.const 57248) (i32.const 54770) (i32.const 2631))
+         (memory.copy (i32.const 25492) (i32.const 1025) (i32.const 3113))
+         (memory.copy (i32.const 49588) (i32.const 44220) (i32.const 975))
+         (memory.copy (i32.const 28280) (i32.const 41722) (i32.const 2336))
+         (memory.copy (i32.const 61289) (i32.const 230) (i32.const 2872))
+         (memory.copy (i32.const 22480) (i32.const 52506) (i32.const 2197))
+         (memory.copy (i32.const 40553) (i32.const 9578) (i32.const 1958))
+         (memory.copy (i32.const 29004) (i32.const 20862) (i32.const 2186))
+         (memory.copy (i32.const 53029) (i32.const 43955) (i32.const 1037))
+         (memory.copy (i32.const 25476) (i32.const 35667) (i32.const 1650))
+         (memory.copy (i32.const 58516) (i32.const 45819) (i32.const 1986))
+         (memory.copy (i32.const 38297) (i32.const 5776) (i32.const 1955))
+         (memory.copy (i32.const 28503) (i32.const 55364) (i32.const 2368))
+         (memory.copy (i32.const 62619) (i32.const 18108) (i32.const 1356))
+         (memory.copy (i32.const 50149) (i32.const 13861) (i32.const 382))
+         (memory.copy (i32.const 16904) (i32.const 36341) (i32.const 1900))
+         (memory.copy (i32.const 48098) (i32.const 11358) (i32.const 2807))
+         (memory.copy (i32.const 28512) (i32.const 40362) (i32.const 323))
+         (memory.copy (i32.const 35506) (i32.const 27856) (i32.const 1670))
+         (memory.copy (i32.const 62970) (i32.const 53332) (i32.const 1341))
+         (memory.copy (i32.const 14133) (i32.const 46312) (i32.const 644))
+         (memory.copy (i32.const 29030) (i32.const 19074) (i32.const 496))
+         (memory.copy (i32.const 44952) (i32.const 47577) (i32.const 2784))
+         (memory.copy (i32.const 39559) (i32.const 44661) (i32.const 1350))
+         (memory.copy (i32.const 10352) (i32.const 29274) (i32.const 1475))
+         (memory.copy (i32.const 46911) (i32.const 46178) (i32.const 1467))
+         (memory.copy (i32.const 4905) (i32.const 28740) (i32.const 1895))
+         (memory.copy (i32.const 38012) (i32.const 57253) (i32.const 1751))
+         (memory.copy (i32.const 26446) (i32.const 27223) (i32.const 1127))
+         (memory.copy (i32.const 58835) (i32.const 24657) (i32.const 1063))
+         (memory.copy (i32.const 61356) (i32.const 38790) (i32.const 766))
+         (memory.copy (i32.const 44160) (i32.const 2284) (i32.const 1520))
+         (memory.copy (i32.const 32740) (i32.const 47237) (i32.const 3014))
+         (memory.copy (i32.const 11148) (i32.const 21260) (i32.const 1011))
+         (memory.copy (i32.const 7665) (i32.const 31612) (i32.const 3034))
+         (memory.copy (i32.const 18044) (i32.const 12987) (i32.const 3320))
+         (memory.copy (i32.const 57306) (i32.const 55905) (i32.const 308))
+         (memory.copy (i32.const 24675) (i32.const 16815) (i32.const 1155))
+         (memory.copy (i32.const 19900) (i32.const 10115) (i32.const 722))
+         (memory.copy (i32.const 2921) (i32.const 5935) (i32.const 2370))
+         (memory.copy (i32.const 32255) (i32.const 50095) (i32.const 2926))
+         (memory.copy (i32.const 15126) (i32.const 17299) (i32.const 2607))
+         (memory.copy (i32.const 45575) (i32.const 28447) (i32.const 2045))
+         (memory.copy (i32.const 55149) (i32.const 36113) (i32.const 2596))
+         (memory.copy (i32.const 28461) (i32.const 54157) (i32.const 1168))
+         (memory.copy (i32.const 47951) (i32.const 53385) (i32.const 3137))
+         (memory.copy (i32.const 30646) (i32.const 45155) (i32.const 2649))
+         (memory.copy (i32.const 5057) (i32.const 4295) (i32.const 52))
+         (memory.copy (i32.const 6692) (i32.const 24195) (i32.const 441))
+         (memory.copy (i32.const 32984) (i32.const 27117) (i32.const 3445))
+         (memory.copy (i32.const 32530) (i32.const 59372) (i32.const 2785))
+         (memory.copy (i32.const 34361) (i32.const 8962) (i32.const 2406))
+         (memory.copy (i32.const 17893) (i32.const 54538) (i32.const 3381))
+         (memory.copy (i32.const 22685) (i32.const 44151) (i32.const 136))
+         (memory.copy (i32.const 59089) (i32.const 7077) (i32.const 1045))
+         (memory.copy (i32.const 42945) (i32.const 55028) (i32.const 2389))
+         (memory.copy (i32.const 44693) (i32.const 20138) (i32.const 877))
+         (memory.copy (i32.const 36810) (i32.const 25196) (i32.const 3447))
+         (memory.copy (i32.const 45742) (i32.const 31888) (i32.const 854))
+         (memory.copy (i32.const 24236) (i32.const 31866) (i32.const 1377))
+         (memory.copy (i32.const 33778) (i32.const 692) (i32.const 1594))
+         (memory.copy (i32.const 60618) (i32.const 18585) (i32.const 2987))
+         (memory.copy (i32.const 50370) (i32.const 41271) (i32.const 1406))
+       )
+  
+  (func (export "checkRange") (param $from i32) (param $to i32) (param $expected i32) (result i32)
+   (loop $cont
+     (if (i32.eq (local.get $from) (local.get $to))
+         (then
+           (return (i32.const -1))))
+     (if (i32.eq (i32.load8_u (local.get $from)) (local.get $expected))
+         (then
+           (local.set $from (i32.add (local.get $from) (i32.const 1)))
+           (br $cont))))
+   (return (local.get $from)))
+)
+(invoke "test")
+
+(assert_return (invoke "checkRange" (i32.const 0) (i32.const 124) (i32.const 0))
+               (i32.const -1))
+(assert_return (invoke "checkRange" (i32.const 124) (i32.const 1517) (i32.const 9))
+               (i32.const -1))
+(assert_return (invoke "checkRange" (i32.const 1517) (i32.const 2132) (i32.const 0))
+               (i32.const -1))
+(assert_return (invoke "checkRange" (i32.const 2132) (i32.const 2827) (i32.const 10))
+               (i32.const -1))
+(assert_return (invoke "checkRange" (i32.const 2827) (i32.const 2921) (i32.const 92))
+               (i32.const -1))
+(assert_return (invoke "checkRange" (i32.const 2921) (i32.const 3538) (i32.const 83))
+               (i32.const -1))
+(assert_return (invoke "checkRange" (i32.const 3538) (i32.const 3786) (i32.const 77))
+               (i32.const -1))
+(assert_return (invoke "checkRange" (i32.const 3786) (i32.const 4042) (i32.const 97))
+               (i32.const -1))
+(assert_return (invoke "checkRange" (i32.const 4042) (i32.const 4651) (i32.const 99))
+               (i32.const -1))
+(assert_return (invoke "checkRange" (i32.const 4651) (i32.const 5057) (i32.const 0))
+               (i32.const -1))
+(assert_return (invoke "checkRange" (i32.const 5057) (i32.const 5109) (i32.const 99))
+               (i32.const -1))
+(assert_return (invoke "checkRange" (i32.const 5109) (i32.const 5291) (i32.const 0))
+               (i32.const -1))
+(assert_return (invoke "checkRange" (i32.const 5291) (i32.const 5524) (i32.const 72))
+               (i32.const -1))
+(assert_return (invoke "checkRange" (i32.const 5524) (i32.const 5691) (i32.const 92))
+               (i32.const -1))
+(assert_return (invoke "checkRange" (i32.const 5691) (i32.const 6552) (i32.const 83))
+               (i32.const -1))
+(assert_return (invoke "checkRange" (i32.const 6552) (i32.const 7133) (i32.const 77))
+               (i32.const -1))
+(assert_return (invoke "checkRange" (i32.const 7133) (i32.const 7665) (i32.const 99))
+               (i32.const -1))
+(assert_return (invoke "checkRange" (i32.const 7665) (i32.const 8314) (i32.const 0))
+               (i32.const -1))
+(assert_return (invoke "checkRange" (i32.const 8314) (i32.const 8360) (i32.const 62))
+               (i32.const -1))
+(assert_return (invoke "checkRange" (i32.const 8360) (i32.const 8793) (i32.const 86))
+               (i32.const -1))
+(assert_return (invoke "checkRange" (i32.const 8793) (i32.const 8979) (i32.const 83))
+               (i32.const -1))
+(assert_return (invoke "checkRange" (i32.const 8979) (i32.const 9373) (i32.const 79))
+               (i32.const -1))
+(assert_return (invoke "checkRange" (i32.const 9373) (i32.const 9518) (i32.const 95))
+               (i32.const -1))
+(assert_return (invoke "checkRange" (i32.const 9518) (i32.const 9934) (i32.const 59))
+               (i32.const -1))
+(assert_return (invoke "checkRange" (i32.const 9934) (i32.const 10087) (i32.const 77))
+               (i32.const -1))
+(assert_return (invoke "checkRange" (i32.const 10087) (i32.const 10206) (i32.const 5))
+               (i32.const -1))
+(assert_return (invoke "checkRange" (i32.const 10206) (i32.const 10230) (i32.const 77))
+               (i32.const -1))
+(assert_return (invoke "checkRange" (i32.const 10230) (i32.const 10249) (i32.const 41))
+               (i32.const -1))
+(assert_return (invoke "checkRange" (i32.const 10249) (i32.const 11148) (i32.const 83))
+               (i32.const -1))
+(assert_return (invoke "checkRange" (i32.const 11148) (i32.const 11356) (i32.const 74))
+               (i32.const -1))
+(assert_return (invoke "checkRange" (i32.const 11356) (i32.const 11380) (i32.const 93))
+               (i32.const -1))
+(assert_return (invoke "checkRange" (i32.const 11380) (i32.const 11939) (i32.const 74))
+               (i32.const -1))
+(assert_return (invoke "checkRange" (i32.const 11939) (i32.const 12159) (i32.const 68))
+               (i32.const -1))
+(assert_return (invoke "checkRange" (i32.const 12159) (i32.const 12575) (i32.const 83))
+               (i32.const -1))
+(assert_return (invoke "checkRange" (i32.const 12575) (i32.const 12969) (i32.const 79))
+               (i32.const -1))
+(assert_return (invoke "checkRange" (i32.const 12969) (i32.const 13114) (i32.const 95))
+               (i32.const -1))
+(assert_return (invoke "checkRange" (i32.const 13114) (i32.const 14133) (i32.const 59))
+               (i32.const -1))
+(assert_return (invoke "checkRange" (i32.const 14133) (i32.const 14404) (i32.const 76))
+               (i32.const -1))
+(assert_return (invoke "checkRange" (i32.const 14404) (i32.const 14428) (i32.const 57))
+               (i32.const -1))
+(assert_return (invoke "checkRange" (i32.const 14428) (i32.const 14458) (i32.const 59))
+               (i32.const -1))
+(assert_return (invoke "checkRange" (i32.const 14458) (i32.const 14580) (i32.const 32))
+               (i32.const -1))
+(assert_return (invoke "checkRange" (i32.const 14580) (i32.const 14777) (i32.const 89))
+               (i32.const -1))
+(assert_return (invoke "checkRange" (i32.const 14777) (i32.const 15124) (i32.const 59))
+               (i32.const -1))
+(assert_return (invoke "checkRange" (i32.const 15124) (i32.const 15126) (i32.const 36))
+               (i32.const -1))
+(assert_return (invoke "checkRange" (i32.const 15126) (i32.const 15192) (i32.const 100))
+               (i32.const -1))
+(assert_return (invoke "checkRange" (i32.const 15192) (i32.const 15871) (i32.const 96))
+               (i32.const -1))
+(assert_return (invoke "checkRange" (i32.const 15871) (i32.const 15998) (i32.const 95))
+               (i32.const -1))
+(assert_return (invoke "checkRange" (i32.const 15998) (i32.const 17017) (i32.const 59))
+               (i32.const -1))
+(assert_return (invoke "checkRange" (i32.const 17017) (i32.const 17288) (i32.const 76))
+               (i32.const -1))
+(assert_return (invoke "checkRange" (i32.const 17288) (i32.const 17312) (i32.const 57))
+               (i32.const -1))
+(assert_return (invoke "checkRange" (i32.const 17312) (i32.const 17342) (i32.const 59))
+               (i32.const -1))
+(assert_return (invoke "checkRange" (i32.const 17342) (i32.const 17464) (i32.const 32))
+               (i32.const -1))
+(assert_return (invoke "checkRange" (i32.const 17464) (i32.const 17661) (i32.const 89))
+               (i32.const -1))
+(assert_return (invoke "checkRange" (i32.const 17661) (i32.const 17727) (i32.const 59))
+               (i32.const -1))
+(assert_return (invoke "checkRange" (i32.const 17727) (i32.const 17733) (i32.const 5))
+               (i32.const -1))
+(assert_return (invoke "checkRange" (i32.const 17733) (i32.const 17893) (i32.const 96))
+               (i32.const -1))
+(assert_return (invoke "checkRange" (i32.const 17893) (i32.const 18553) (i32.const 77))
+               (i32.const -1))
+(assert_return (invoke "checkRange" (i32.const 18553) (i32.const 18744) (i32.const 42))
+               (i32.const -1))
+(assert_return (invoke "checkRange" (i32.const 18744) (i32.const 18801) (i32.const 76))
+               (i32.const -1))
+(assert_return (invoke "checkRange" (i32.const 18801) (i32.const 18825) (i32.const 57))
+               (i32.const -1))
+(assert_return (invoke "checkRange" (i32.const 18825) (i32.const 18876) (i32.const 59))
+               (i32.const -1))
+(assert_return (invoke "checkRange" (i32.const 18876) (i32.const 18885) (i32.const 77))
+               (i32.const -1))
+(assert_return (invoke "checkRange" (i32.const 18885) (i32.const 18904) (i32.const 41))
+               (i32.const -1))
+(assert_return (invoke "checkRange" (i32.const 18904) (i32.const 19567) (i32.const 83))
+               (i32.const -1))
+(assert_return (invoke "checkRange" (i32.const 19567) (i32.const 20403) (i32.const 96))
+               (i32.const -1))
+(assert_return (invoke "checkRange" (i32.const 20403) (i32.const 21274) (i32.const 77))
+               (i32.const -1))
+(assert_return (invoke "checkRange" (i32.const 21274) (i32.const 21364) (i32.const 100))
+               (i32.const -1))
+(assert_return (invoke "checkRange" (i32.const 21364) (i32.const 21468) (i32.const 74))
+               (i32.const -1))
+(assert_return (invoke "checkRange" (i32.const 21468) (i32.const 21492) (i32.const 93))
+               (i32.const -1))
+(assert_return (invoke "checkRange" (i32.const 21492) (i32.const 22051) (i32.const 74))
+               (i32.const -1))
+(assert_return (invoke "checkRange" (i32.const 22051) (i32.const 22480) (i32.const 68))
+               (i32.const -1))
+(assert_return (invoke "checkRange" (i32.const 22480) (i32.const 22685) (i32.const 100))
+               (i32.const -1))
+(assert_return (invoke "checkRange" (i32.const 22685) (i32.const 22694) (i32.const 68))
+               (i32.const -1))
+(assert_return (invoke "checkRange" (i32.const 22694) (i32.const 22821) (i32.const 10))
+               (i32.const -1))
+(assert_return (invoke "checkRange" (i32.const 22821) (i32.const 22869) (i32.const 100))
+               (i32.const -1))
+(assert_return (invoke "checkRange" (i32.const 22869) (i32.const 24107) (i32.const 97))
+               (i32.const -1))
+(assert_return (invoke "checkRange" (i32.const 24107) (i32.const 24111) (i32.const 37))
+               (i32.const -1))
+(assert_return (invoke "checkRange" (i32.const 24111) (i32.const 24236) (i32.const 77))
+               (i32.const -1))
+(assert_return (invoke "checkRange" (i32.const 24236) (i32.const 24348) (i32.const 72))
+               (i32.const -1))
+(assert_return (invoke "checkRange" (i32.const 24348) (i32.const 24515) (i32.const 92))
+               (i32.const -1))
+(assert_return (invoke "checkRange" (i32.const 24515) (i32.const 24900) (i32.const 83))
+               (i32.const -1))
+(assert_return (invoke "checkRange" (i32.const 24900) (i32.const 25136) (i32.const 95))
+               (i32.const -1))
+(assert_return (invoke "checkRange" (i32.const 25136) (i32.const 25182) (i32.const 85))
+               (i32.const -1))
+(assert_return (invoke "checkRange" (i32.const 25182) (i32.const 25426) (i32.const 68))
+               (i32.const -1))
+(assert_return (invoke "checkRange" (i32.const 25426) (i32.const 25613) (i32.const 89))
+               (i32.const -1))
+(assert_return (invoke "checkRange" (i32.const 25613) (i32.const 25830) (i32.const 96))
+               (i32.const -1))
+(assert_return (invoke "checkRange" (i32.const 25830) (i32.const 26446) (i32.const 100))
+               (i32.const -1))
+(assert_return (invoke "checkRange" (i32.const 26446) (i32.const 26517) (i32.const 10))
+               (i32.const -1))
+(assert_return (invoke "checkRange" (i32.const 26517) (i32.const 27468) (i32.const 92))
+               (i32.const -1))
+(assert_return (invoke "checkRange" (i32.const 27468) (i32.const 27503) (i32.const 95))
+               (i32.const -1))
+(assert_return (invoke "checkRange" (i32.const 27503) (i32.const 27573) (i32.const 77))
+               (i32.const -1))
+(assert_return (invoke "checkRange" (i32.const 27573) (i32.const 28245) (i32.const 92))
+               (i32.const -1))
+(assert_return (invoke "checkRange" (i32.const 28245) (i32.const 28280) (i32.const 95))
+               (i32.const -1))
+(assert_return (invoke "checkRange" (i32.const 28280) (i32.const 29502) (i32.const 77))
+               (i32.const -1))
+(assert_return (invoke "checkRange" (i32.const 29502) (i32.const 29629) (i32.const 42))
+               (i32.const -1))
+(assert_return (invoke "checkRange" (i32.const 29629) (i32.const 30387) (i32.const 83))
+               (i32.const -1))
+(assert_return (invoke "checkRange" (i32.const 30387) (i32.const 30646) (i32.const 77))
+               (i32.const -1))
+(assert_return (invoke "checkRange" (i32.const 30646) (i32.const 31066) (i32.const 92))
+               (i32.const -1))
+(assert_return (invoke "checkRange" (i32.const 31066) (i32.const 31131) (i32.const 77))
+               (i32.const -1))
+(assert_return (invoke "checkRange" (i32.const 31131) (i32.const 31322) (i32.const 42))
+               (i32.const -1))
+(assert_return (invoke "checkRange" (i32.const 31322) (i32.const 31379) (i32.const 76))
+               (i32.const -1))
+(assert_return (invoke "checkRange" (i32.const 31379) (i32.const 31403) (i32.const 57))
+               (i32.const -1))
+(assert_return (invoke "checkRange" (i32.const 31403) (i32.const 31454) (i32.const 59))
+               (i32.const -1))
+(assert_return (invoke "checkRange" (i32.const 31454) (i32.const 31463) (i32.const 77))
+               (i32.const -1))
+(assert_return (invoke "checkRange" (i32.const 31463) (i32.const 31482) (i32.const 41))
+               (i32.const -1))
+(assert_return (invoke "checkRange" (i32.const 31482) (i32.const 31649) (i32.const 83))
+               (i32.const -1))
+(assert_return (invoke "checkRange" (i32.const 31649) (i32.const 31978) (i32.const 72))
+               (i32.const -1))
+(assert_return (invoke "checkRange" (i32.const 31978) (i32.const 32145) (i32.const 92))
+               (i32.const -1))
+(assert_return (invoke "checkRange" (i32.const 32145) (i32.const 32530) (i32.const 83))
+               (i32.const -1))
+(assert_return (invoke "checkRange" (i32.const 32530) (i32.const 32766) (i32.const 95))
+               (i32.const -1))
+(assert_return (invoke "checkRange" (i32.const 32766) (i32.const 32812) (i32.const 85))
+               (i32.const -1))
+(assert_return (invoke "checkRange" (i32.const 32812) (i32.const 33056) (i32.const 68))
+               (i32.const -1))
+(assert_return (invoke "checkRange" (i32.const 33056) (i32.const 33660) (i32.const 89))
+               (i32.const -1))
+(assert_return (invoke "checkRange" (i32.const 33660) (i32.const 33752) (i32.const 59))
+               (i32.const -1))
+(assert_return (invoke "checkRange" (i32.const 33752) (i32.const 33775) (i32.const 36))
+               (i32.const -1))
+(assert_return (invoke "checkRange" (i32.const 33775) (i32.const 33778) (i32.const 32))
+               (i32.const -1))
+(assert_return (invoke "checkRange" (i32.const 33778) (i32.const 34603) (i32.const 9))
+               (i32.const -1))
+(assert_return (invoke "checkRange" (i32.const 34603) (i32.const 35218) (i32.const 0))
+               (i32.const -1))
+(assert_return (invoke "checkRange" (i32.const 35218) (i32.const 35372) (i32.const 10))
+               (i32.const -1))
+(assert_return (invoke "checkRange" (i32.const 35372) (i32.const 35486) (i32.const 77))
+               (i32.const -1))
+(assert_return (invoke "checkRange" (i32.const 35486) (i32.const 35605) (i32.const 5))
+               (i32.const -1))
+(assert_return (invoke "checkRange" (i32.const 35605) (i32.const 35629) (i32.const 77))
+               (i32.const -1))
+(assert_return (invoke "checkRange" (i32.const 35629) (i32.const 35648) (i32.const 41))
+               (i32.const -1))
+(assert_return (invoke "checkRange" (i32.const 35648) (i32.const 36547) (i32.const 83))
+               (i32.const -1))
+(assert_return (invoke "checkRange" (i32.const 36547) (i32.const 36755) (i32.const 74))
+               (i32.const -1))
+(assert_return (invoke "checkRange" (i32.const 36755) (i32.const 36767) (i32.const 93))
+               (i32.const -1))
+(assert_return (invoke "checkRange" (i32.const 36767) (i32.const 36810) (i32.const 83))
+               (i32.const -1))
+(assert_return (invoke "checkRange" (i32.const 36810) (i32.const 36839) (i32.const 100))
+               (i32.const -1))
+(assert_return (invoke "checkRange" (i32.const 36839) (i32.const 37444) (i32.const 96))
+               (i32.const -1))
+(assert_return (invoke "checkRange" (i32.const 37444) (i32.const 38060) (i32.const 100))
+               (i32.const -1))
+(assert_return (invoke "checkRange" (i32.const 38060) (i32.const 38131) (i32.const 10))
+               (i32.const -1))
+(assert_return (invoke "checkRange" (i32.const 38131) (i32.const 39082) (i32.const 92))
+               (i32.const -1))
+(assert_return (invoke "checkRange" (i32.const 39082) (i32.const 39117) (i32.const 95))
+               (i32.const -1))
+(assert_return (invoke "checkRange" (i32.const 39117) (i32.const 39187) (i32.const 77))
+               (i32.const -1))
+(assert_return (invoke "checkRange" (i32.const 39187) (i32.const 39859) (i32.const 92))
+               (i32.const -1))
+(assert_return (invoke "checkRange" (i32.const 39859) (i32.const 39894) (i32.const 95))
+               (i32.const -1))
+(assert_return (invoke "checkRange" (i32.const 39894) (i32.const 40257) (i32.const 77))
+               (i32.const -1))
+(assert_return (invoke "checkRange" (i32.const 40257) (i32.const 40344) (i32.const 89))
+               (i32.const -1))
+(assert_return (invoke "checkRange" (i32.const 40344) (i32.const 40371) (i32.const 59))
+               (i32.const -1))
+(assert_return (invoke "checkRange" (i32.const 40371) (i32.const 40804) (i32.const 77))
+               (i32.const -1))
+(assert_return (invoke "checkRange" (i32.const 40804) (i32.const 40909) (i32.const 5))
+               (i32.const -1))
+(assert_return (invoke "checkRange" (i32.const 40909) (i32.const 42259) (i32.const 92))
+               (i32.const -1))
+(assert_return (invoke "checkRange" (i32.const 42259) (i32.const 42511) (i32.const 77))
+               (i32.const -1))
+(assert_return (invoke "checkRange" (i32.const 42511) (i32.const 42945) (i32.const 83))
+               (i32.const -1))
+(assert_return (invoke "checkRange" (i32.const 42945) (i32.const 43115) (i32.const 77))
+               (i32.const -1))
+(assert_return (invoke "checkRange" (i32.const 43115) (i32.const 43306) (i32.const 42))
+               (i32.const -1))
+(assert_return (invoke "checkRange" (i32.const 43306) (i32.const 43363) (i32.const 76))
+               (i32.const -1))
+(assert_return (invoke "checkRange" (i32.const 43363) (i32.const 43387) (i32.const 57))
+               (i32.const -1))
+(assert_return (invoke "checkRange" (i32.const 43387) (i32.const 43438) (i32.const 59))
+               (i32.const -1))
+(assert_return (invoke "checkRange" (i32.const 43438) (i32.const 43447) (i32.const 77))
+               (i32.const -1))
+(assert_return (invoke "checkRange" (i32.const 43447) (i32.const 43466) (i32.const 41))
+               (i32.const -1))
+(assert_return (invoke "checkRange" (i32.const 43466) (i32.const 44129) (i32.const 83))
+               (i32.const -1))
+(assert_return (invoke "checkRange" (i32.const 44129) (i32.const 44958) (i32.const 96))
+               (i32.const -1))
+(assert_return (invoke "checkRange" (i32.const 44958) (i32.const 45570) (i32.const 77))
+               (i32.const -1))
+(assert_return (invoke "checkRange" (i32.const 45570) (i32.const 45575) (i32.const 92))
+               (i32.const -1))
+(assert_return (invoke "checkRange" (i32.const 45575) (i32.const 45640) (i32.const 77))
+               (i32.const -1))
+(assert_return (invoke "checkRange" (i32.const 45640) (i32.const 45742) (i32.const 42))
+               (i32.const -1))
+(assert_return (invoke "checkRange" (i32.const 45742) (i32.const 45832) (i32.const 72))
+               (i32.const -1))
+(assert_return (invoke "checkRange" (i32.const 45832) (i32.const 45999) (i32.const 92))
+               (i32.const -1))
+(assert_return (invoke "checkRange" (i32.const 45999) (i32.const 46384) (i32.const 83))
+               (i32.const -1))
+(assert_return (invoke "checkRange" (i32.const 46384) (i32.const 46596) (i32.const 95))
+               (i32.const -1))
+(assert_return (invoke "checkRange" (i32.const 46596) (i32.const 46654) (i32.const 92))
+               (i32.const -1))
+(assert_return (invoke "checkRange" (i32.const 46654) (i32.const 47515) (i32.const 83))
+               (i32.const -1))
+(assert_return (invoke "checkRange" (i32.const 47515) (i32.const 47620) (i32.const 77))
+               (i32.const -1))
+(assert_return (invoke "checkRange" (i32.const 47620) (i32.const 47817) (i32.const 79))
+               (i32.const -1))
+(assert_return (invoke "checkRange" (i32.const 47817) (i32.const 47951) (i32.const 95))
+               (i32.const -1))
+(assert_return (invoke "checkRange" (i32.const 47951) (i32.const 48632) (i32.const 100))
+               (i32.const -1))
+(assert_return (invoke "checkRange" (i32.const 48632) (i32.const 48699) (i32.const 97))
+               (i32.const -1))
+(assert_return (invoke "checkRange" (i32.const 48699) (i32.const 48703) (i32.const 37))
+               (i32.const -1))
+(assert_return (invoke "checkRange" (i32.const 48703) (i32.const 49764) (i32.const 77))
+               (i32.const -1))
+(assert_return (invoke "checkRange" (i32.const 49764) (i32.const 49955) (i32.const 42))
+               (i32.const -1))
+(assert_return (invoke "checkRange" (i32.const 49955) (i32.const 50012) (i32.const 76))
+               (i32.const -1))
+(assert_return (invoke "checkRange" (i32.const 50012) (i32.const 50036) (i32.const 57))
+               (i32.const -1))
+(assert_return (invoke "checkRange" (i32.const 50036) (i32.const 50087) (i32.const 59))
+               (i32.const -1))
+(assert_return (invoke "checkRange" (i32.const 50087) (i32.const 50096) (i32.const 77))
+               (i32.const -1))
+(assert_return (invoke "checkRange" (i32.const 50096) (i32.const 50115) (i32.const 41))
+               (i32.const -1))
+(assert_return (invoke "checkRange" (i32.const 50115) (i32.const 50370) (i32.const 83))
+               (i32.const -1))
+(assert_return (invoke "checkRange" (i32.const 50370) (i32.const 51358) (i32.const 92))
+               (i32.const -1))
+(assert_return (invoke "checkRange" (i32.const 51358) (i32.const 51610) (i32.const 77))
+               (i32.const -1))
+(assert_return (invoke "checkRange" (i32.const 51610) (i32.const 51776) (i32.const 83))
+               (i32.const -1))
+(assert_return (invoke "checkRange" (i32.const 51776) (i32.const 51833) (i32.const 89))
+               (i32.const -1))
+(assert_return (invoke "checkRange" (i32.const 51833) (i32.const 52895) (i32.const 100))
+               (i32.const -1))
+(assert_return (invoke "checkRange" (i32.const 52895) (i32.const 53029) (i32.const 97))
+               (i32.const -1))
+(assert_return (invoke "checkRange" (i32.const 53029) (i32.const 53244) (i32.const 68))
+               (i32.const -1))
+(assert_return (invoke "checkRange" (i32.const 53244) (i32.const 54066) (i32.const 100))
+               (i32.const -1))
+(assert_return (invoke "checkRange" (i32.const 54066) (i32.const 54133) (i32.const 97))
+               (i32.const -1))
+(assert_return (invoke "checkRange" (i32.const 54133) (i32.const 54137) (i32.const 37))
+               (i32.const -1))
+(assert_return (invoke "checkRange" (i32.const 54137) (i32.const 55198) (i32.const 77))
+               (i32.const -1))
+(assert_return (invoke "checkRange" (i32.const 55198) (i32.const 55389) (i32.const 42))
+               (i32.const -1))
+(assert_return (invoke "checkRange" (i32.const 55389) (i32.const 55446) (i32.const 76))
+               (i32.const -1))
+(assert_return (invoke "checkRange" (i32.const 55446) (i32.const 55470) (i32.const 57))
+               (i32.const -1))
+(assert_return (invoke "checkRange" (i32.const 55470) (i32.const 55521) (i32.const 59))
+               (i32.const -1))
+(assert_return (invoke "checkRange" (i32.const 55521) (i32.const 55530) (i32.const 77))
+               (i32.const -1))
+(assert_return (invoke "checkRange" (i32.const 55530) (i32.const 55549) (i32.const 41))
+               (i32.const -1))
+(assert_return (invoke "checkRange" (i32.const 55549) (i32.const 56212) (i32.const 83))
+               (i32.const -1))
+(assert_return (invoke "checkRange" (i32.const 56212) (i32.const 57048) (i32.const 96))
+               (i32.const -1))
+(assert_return (invoke "checkRange" (i32.const 57048) (i32.const 58183) (i32.const 77))
+               (i32.const -1))
+(assert_return (invoke "checkRange" (i32.const 58183) (i32.const 58202) (i32.const 41))
+               (i32.const -1))
+(assert_return (invoke "checkRange" (i32.const 58202) (i32.const 58516) (i32.const 83))
+               (i32.const -1))
+(assert_return (invoke "checkRange" (i32.const 58516) (i32.const 58835) (i32.const 95))
+               (i32.const -1))
+(assert_return (invoke "checkRange" (i32.const 58835) (i32.const 58855) (i32.const 77))
+               (i32.const -1))
+(assert_return (invoke "checkRange" (i32.const 58855) (i32.const 59089) (i32.const 95))
+               (i32.const -1))
+(assert_return (invoke "checkRange" (i32.const 59089) (i32.const 59145) (i32.const 77))
+               (i32.const -1))
+(assert_return (invoke "checkRange" (i32.const 59145) (i32.const 59677) (i32.const 99))
+               (i32.const -1))
+(assert_return (invoke "checkRange" (i32.const 59677) (i32.const 60134) (i32.const 0))
+               (i32.const -1))
+(assert_return (invoke "checkRange" (i32.const 60134) (i32.const 60502) (i32.const 89))
+               (i32.const -1))
+(assert_return (invoke "checkRange" (i32.const 60502) (i32.const 60594) (i32.const 59))
+               (i32.const -1))
+(assert_return (invoke "checkRange" (i32.const 60594) (i32.const 60617) (i32.const 36))
+               (i32.const -1))
+(assert_return (invoke "checkRange" (i32.const 60617) (i32.const 60618) (i32.const 32))
+               (i32.const -1))
+(assert_return (invoke "checkRange" (i32.const 60618) (i32.const 60777) (i32.const 42))
+               (i32.const -1))
+(assert_return (invoke "checkRange" (i32.const 60777) (i32.const 60834) (i32.const 76))
+               (i32.const -1))
+(assert_return (invoke "checkRange" (i32.const 60834) (i32.const 60858) (i32.const 57))
+               (i32.const -1))
+(assert_return (invoke "checkRange" (i32.const 60858) (i32.const 60909) (i32.const 59))
+               (i32.const -1))
+(assert_return (invoke "checkRange" (i32.const 60909) (i32.const 60918) (i32.const 77))
+               (i32.const -1))
+(assert_return (invoke "checkRange" (i32.const 60918) (i32.const 60937) (i32.const 41))
+               (i32.const -1))
+(assert_return (invoke "checkRange" (i32.const 60937) (i32.const 61600) (i32.const 83))
+               (i32.const -1))
+(assert_return (invoke "checkRange" (i32.const 61600) (i32.const 62436) (i32.const 96))
+               (i32.const -1))
+(assert_return (invoke "checkRange" (i32.const 62436) (i32.const 63307) (i32.const 77))
+               (i32.const -1))
+(assert_return (invoke "checkRange" (i32.const 63307) (i32.const 63397) (i32.const 100))
+               (i32.const -1))
+(assert_return (invoke "checkRange" (i32.const 63397) (i32.const 63501) (i32.const 74))
+               (i32.const -1))
+(assert_return (invoke "checkRange" (i32.const 63501) (i32.const 63525) (i32.const 93))
+               (i32.const -1))
+(assert_return (invoke "checkRange" (i32.const 63525) (i32.const 63605) (i32.const 74))
+               (i32.const -1))
+(assert_return (invoke "checkRange" (i32.const 63605) (i32.const 63704) (i32.const 100))
+               (i32.const -1))
+(assert_return (invoke "checkRange" (i32.const 63704) (i32.const 63771) (i32.const 97))
+               (i32.const -1))
+(assert_return (invoke "checkRange" (i32.const 63771) (i32.const 63775) (i32.const 37))
+               (i32.const -1))
+(assert_return (invoke "checkRange" (i32.const 63775) (i32.const 64311) (i32.const 77))
+               (i32.const -1))
+(assert_return (invoke "checkRange" (i32.const 64311) (i32.const 64331) (i32.const 26))
+               (i32.const -1))
+(assert_return (invoke "checkRange" (i32.const 64331) (i32.const 64518) (i32.const 92))
+               (i32.const -1))
+(assert_return (invoke "checkRange" (i32.const 64518) (i32.const 64827) (i32.const 11))
+               (i32.const -1))
+(assert_return (invoke "checkRange" (i32.const 64827) (i32.const 64834) (i32.const 26))
+               (i32.const -1))
+(assert_return (invoke "checkRange" (i32.const 64834) (i32.const 65536) (i32.const 0))
+               (i32.const -1))
diff --git a/test/core/memory_fill.wast b/test/core/memory_fill.wast
new file mode 100644
index 0000000000..efa68ea23e
--- /dev/null
+++ b/test/core/memory_fill.wast
@@ -0,0 +1,749 @@
+;;
+;; Generated by ../meta/generate_memory_fill.js
+;;
+
+(module
+  
+  (memory 1 1)
+  
+  (func (export "checkRange") (param $from i32) (param $to i32) (param $expected i32) (result i32)
+   (loop $cont
+     (if (i32.eq (local.get $from) (local.get $to))
+         (then
+           (return (i32.const -1))))
+     (if (i32.eq (i32.load8_u (local.get $from)) (local.get $expected))
+         (then
+           (local.set $from (i32.add (local.get $from) (i32.const 1)))
+           (br $cont))))
+   (return (local.get $from)))
+
+  (func (export "test")
+    (memory.fill (i32.const 0xFF00) (i32.const 0x55) (i32.const 256))))
+(invoke "test")
+
+(assert_return (invoke "checkRange" (i32.const 0) (i32.const 65280) (i32.const 0))
+               (i32.const -1))
+(assert_return (invoke "checkRange" (i32.const 65280) (i32.const 65536) (i32.const 85))
+               (i32.const -1))
+
+(module
+  
+  (memory 1 1)
+  
+  (func (export "checkRange") (param $from i32) (param $to i32) (param $expected i32) (result i32)
+   (loop $cont
+     (if (i32.eq (local.get $from) (local.get $to))
+         (then
+           (return (i32.const -1))))
+     (if (i32.eq (i32.load8_u (local.get $from)) (local.get $expected))
+         (then
+           (local.set $from (i32.add (local.get $from) (i32.const 1)))
+           (br $cont))))
+   (return (local.get $from)))
+
+  (func (export "test")
+    (memory.fill (i32.const 0xFF00) (i32.const 0x55) (i32.const 257))))
+(assert_trap (invoke "test") "out of bounds memory access")
+
+
+(module
+  
+  (memory 1 1)
+  
+  (func (export "checkRange") (param $from i32) (param $to i32) (param $expected i32) (result i32)
+   (loop $cont
+     (if (i32.eq (local.get $from) (local.get $to))
+         (then
+           (return (i32.const -1))))
+     (if (i32.eq (i32.load8_u (local.get $from)) (local.get $expected))
+         (then
+           (local.set $from (i32.add (local.get $from) (i32.const 1)))
+           (br $cont))))
+   (return (local.get $from)))
+
+  (func (export "test")
+    (memory.fill (i32.const 0xFFFFFF00) (i32.const 0x55) (i32.const 257))))
+(assert_trap (invoke "test") "out of bounds memory access")
+
+
+(module
+  
+  (memory 1 1)
+  
+  (func (export "checkRange") (param $from i32) (param $to i32) (param $expected i32) (result i32)
+   (loop $cont
+     (if (i32.eq (local.get $from) (local.get $to))
+         (then
+           (return (i32.const -1))))
+     (if (i32.eq (i32.load8_u (local.get $from)) (local.get $expected))
+         (then
+           (local.set $from (i32.add (local.get $from) (i32.const 1)))
+           (br $cont))))
+   (return (local.get $from)))
+
+  (func (export "test")
+    (memory.fill (i32.const 0x12) (i32.const 0x55) (i32.const 0))))
+(invoke "test")
+
+(assert_return (invoke "checkRange" (i32.const 0) (i32.const 65536) (i32.const 0))
+               (i32.const -1))
+
+(module
+  
+  (memory 1 1)
+  
+  (func (export "checkRange") (param $from i32) (param $to i32) (param $expected i32) (result i32)
+   (loop $cont
+     (if (i32.eq (local.get $from) (local.get $to))
+         (then
+           (return (i32.const -1))))
+     (if (i32.eq (i32.load8_u (local.get $from)) (local.get $expected))
+         (then
+           (local.set $from (i32.add (local.get $from) (i32.const 1)))
+           (br $cont))))
+   (return (local.get $from)))
+
+  (func (export "test")
+    (memory.fill (i32.const 0x10000) (i32.const 0x55) (i32.const 0))))
+(invoke "test")
+
+
+(module
+  
+  (memory 1 1)
+  
+  (func (export "checkRange") (param $from i32) (param $to i32) (param $expected i32) (result i32)
+   (loop $cont
+     (if (i32.eq (local.get $from) (local.get $to))
+         (then
+           (return (i32.const -1))))
+     (if (i32.eq (i32.load8_u (local.get $from)) (local.get $expected))
+         (then
+           (local.set $from (i32.add (local.get $from) (i32.const 1)))
+           (br $cont))))
+   (return (local.get $from)))
+
+  (func (export "test")
+    (memory.fill (i32.const 0x1) (i32.const 0xAA) (i32.const 0xFFFE))))
+(invoke "test")
+
+(assert_return (invoke "checkRange" (i32.const 0) (i32.const 1) (i32.const 0))
+               (i32.const -1))
+(assert_return (invoke "checkRange" (i32.const 1) (i32.const 65535) (i32.const 170))
+               (i32.const -1))
+(assert_return (invoke "checkRange" (i32.const 65535) (i32.const 65536) (i32.const 0))
+               (i32.const -1))
+
+(module
+  
+  (memory 1 1)
+  
+  (func (export "checkRange") (param $from i32) (param $to i32) (param $expected i32) (result i32)
+   (loop $cont
+     (if (i32.eq (local.get $from) (local.get $to))
+         (then
+           (return (i32.const -1))))
+     (if (i32.eq (i32.load8_u (local.get $from)) (local.get $expected))
+         (then
+           (local.set $from (i32.add (local.get $from) (i32.const 1)))
+           (br $cont))))
+   (return (local.get $from)))
+
+  (func (export "test")
+     (memory.fill (i32.const 0x12) (i32.const 0x55) (i32.const 10))
+     (memory.fill (i32.const 0x15) (i32.const 0xAA) (i32.const 4))))
+(invoke "test")
+
+(assert_return (invoke "checkRange" (i32.const 0) (i32.const 18) (i32.const 0))
+               (i32.const -1))
+(assert_return (invoke "checkRange" (i32.const 18) (i32.const 21) (i32.const 85))
+               (i32.const -1))
+(assert_return (invoke "checkRange" (i32.const 21) (i32.const 25) (i32.const 170))
+               (i32.const -1))
+(assert_return (invoke "checkRange" (i32.const 25) (i32.const 28) (i32.const 85))
+               (i32.const -1))
+(assert_return (invoke "checkRange" (i32.const 28) (i32.const 65536) (i32.const 0))
+               (i32.const -1))
+
+(assert_invalid
+  (module
+    (func (export "testfn")
+      (memory.fill (i32.const 10) (i32.const 20) (i32.const 30))))
+  "unknown memory 0")
+
+
+(assert_invalid
+  (module
+    (memory 1 1)
+    (func (export "testfn")
+      (memory.fill (i32.const 10) (i32.const 20) (f32.const 30))))
+  "type mismatch")
+
+
+(assert_invalid
+  (module
+    (memory 1 1)
+    (func (export "testfn")
+      (memory.fill (i32.const 10) (i32.const 20) (i64.const 30))))
+  "type mismatch")
+
+
+(assert_invalid
+  (module
+    (memory 1 1)
+    (func (export "testfn")
+      (memory.fill (i32.const 10) (i32.const 20) (f64.const 30))))
+  "type mismatch")
+
+
+(assert_invalid
+  (module
+    (memory 1 1)
+    (func (export "testfn")
+      (memory.fill (i32.const 10) (f32.const 20) (i32.const 30))))
+  "type mismatch")
+
+
+(assert_invalid
+  (module
+    (memory 1 1)
+    (func (export "testfn")
+      (memory.fill (i32.const 10) (f32.const 20) (f32.const 30))))
+  "type mismatch")
+
+
+(assert_invalid
+  (module
+    (memory 1 1)
+    (func (export "testfn")
+      (memory.fill (i32.const 10) (f32.const 20) (i64.const 30))))
+  "type mismatch")
+
+
+(assert_invalid
+  (module
+    (memory 1 1)
+    (func (export "testfn")
+      (memory.fill (i32.const 10) (f32.const 20) (f64.const 30))))
+  "type mismatch")
+
+
+(assert_invalid
+  (module
+    (memory 1 1)
+    (func (export "testfn")
+      (memory.fill (i32.const 10) (i64.const 20) (i32.const 30))))
+  "type mismatch")
+
+
+(assert_invalid
+  (module
+    (memory 1 1)
+    (func (export "testfn")
+      (memory.fill (i32.const 10) (i64.const 20) (f32.const 30))))
+  "type mismatch")
+
+
+(assert_invalid
+  (module
+    (memory 1 1)
+    (func (export "testfn")
+      (memory.fill (i32.const 10) (i64.const 20) (i64.const 30))))
+  "type mismatch")
+
+
+(assert_invalid
+  (module
+    (memory 1 1)
+    (func (export "testfn")
+      (memory.fill (i32.const 10) (i64.const 20) (f64.const 30))))
+  "type mismatch")
+
+
+(assert_invalid
+  (module
+    (memory 1 1)
+    (func (export "testfn")
+      (memory.fill (i32.const 10) (f64.const 20) (i32.const 30))))
+  "type mismatch")
+
+
+(assert_invalid
+  (module
+    (memory 1 1)
+    (func (export "testfn")
+      (memory.fill (i32.const 10) (f64.const 20) (f32.const 30))))
+  "type mismatch")
+
+
+(assert_invalid
+  (module
+    (memory 1 1)
+    (func (export "testfn")
+      (memory.fill (i32.const 10) (f64.const 20) (i64.const 30))))
+  "type mismatch")
+
+
+(assert_invalid
+  (module
+    (memory 1 1)
+    (func (export "testfn")
+      (memory.fill (i32.const 10) (f64.const 20) (f64.const 30))))
+  "type mismatch")
+
+
+(assert_invalid
+  (module
+    (memory 1 1)
+    (func (export "testfn")
+      (memory.fill (f32.const 10) (i32.const 20) (i32.const 30))))
+  "type mismatch")
+
+
+(assert_invalid
+  (module
+    (memory 1 1)
+    (func (export "testfn")
+      (memory.fill (f32.const 10) (i32.const 20) (f32.const 30))))
+  "type mismatch")
+
+
+(assert_invalid
+  (module
+    (memory 1 1)
+    (func (export "testfn")
+      (memory.fill (f32.const 10) (i32.const 20) (i64.const 30))))
+  "type mismatch")
+
+
+(assert_invalid
+  (module
+    (memory 1 1)
+    (func (export "testfn")
+      (memory.fill (f32.const 10) (i32.const 20) (f64.const 30))))
+  "type mismatch")
+
+
+(assert_invalid
+  (module
+    (memory 1 1)
+    (func (export "testfn")
+      (memory.fill (f32.const 10) (f32.const 20) (i32.const 30))))
+  "type mismatch")
+
+
+(assert_invalid
+  (module
+    (memory 1 1)
+    (func (export "testfn")
+      (memory.fill (f32.const 10) (f32.const 20) (f32.const 30))))
+  "type mismatch")
+
+
+(assert_invalid
+  (module
+    (memory 1 1)
+    (func (export "testfn")
+      (memory.fill (f32.const 10) (f32.const 20) (i64.const 30))))
+  "type mismatch")
+
+
+(assert_invalid
+  (module
+    (memory 1 1)
+    (func (export "testfn")
+      (memory.fill (f32.const 10) (f32.const 20) (f64.const 30))))
+  "type mismatch")
+
+
+(assert_invalid
+  (module
+    (memory 1 1)
+    (func (export "testfn")
+      (memory.fill (f32.const 10) (i64.const 20) (i32.const 30))))
+  "type mismatch")
+
+
+(assert_invalid
+  (module
+    (memory 1 1)
+    (func (export "testfn")
+      (memory.fill (f32.const 10) (i64.const 20) (f32.const 30))))
+  "type mismatch")
+
+
+(assert_invalid
+  (module
+    (memory 1 1)
+    (func (export "testfn")
+      (memory.fill (f32.const 10) (i64.const 20) (i64.const 30))))
+  "type mismatch")
+
+
+(assert_invalid
+  (module
+    (memory 1 1)
+    (func (export "testfn")
+      (memory.fill (f32.const 10) (i64.const 20) (f64.const 30))))
+  "type mismatch")
+
+
+(assert_invalid
+  (module
+    (memory 1 1)
+    (func (export "testfn")
+      (memory.fill (f32.const 10) (f64.const 20) (i32.const 30))))
+  "type mismatch")
+
+
+(assert_invalid
+  (module
+    (memory 1 1)
+    (func (export "testfn")
+      (memory.fill (f32.const 10) (f64.const 20) (f32.const 30))))
+  "type mismatch")
+
+
+(assert_invalid
+  (module
+    (memory 1 1)
+    (func (export "testfn")
+      (memory.fill (f32.const 10) (f64.const 20) (i64.const 30))))
+  "type mismatch")
+
+
+(assert_invalid
+  (module
+    (memory 1 1)
+    (func (export "testfn")
+      (memory.fill (f32.const 10) (f64.const 20) (f64.const 30))))
+  "type mismatch")
+
+
+(assert_invalid
+  (module
+    (memory 1 1)
+    (func (export "testfn")
+      (memory.fill (i64.const 10) (i32.const 20) (i32.const 30))))
+  "type mismatch")
+
+
+(assert_invalid
+  (module
+    (memory 1 1)
+    (func (export "testfn")
+      (memory.fill (i64.const 10) (i32.const 20) (f32.const 30))))
+  "type mismatch")
+
+
+(assert_invalid
+  (module
+    (memory 1 1)
+    (func (export "testfn")
+      (memory.fill (i64.const 10) (i32.const 20) (i64.const 30))))
+  "type mismatch")
+
+
+(assert_invalid
+  (module
+    (memory 1 1)
+    (func (export "testfn")
+      (memory.fill (i64.const 10) (i32.const 20) (f64.const 30))))
+  "type mismatch")
+
+
+(assert_invalid
+  (module
+    (memory 1 1)
+    (func (export "testfn")
+      (memory.fill (i64.const 10) (f32.const 20) (i32.const 30))))
+  "type mismatch")
+
+
+(assert_invalid
+  (module
+    (memory 1 1)
+    (func (export "testfn")
+      (memory.fill (i64.const 10) (f32.const 20) (f32.const 30))))
+  "type mismatch")
+
+
+(assert_invalid
+  (module
+    (memory 1 1)
+    (func (export "testfn")
+      (memory.fill (i64.const 10) (f32.const 20) (i64.const 30))))
+  "type mismatch")
+
+
+(assert_invalid
+  (module
+    (memory 1 1)
+    (func (export "testfn")
+      (memory.fill (i64.const 10) (f32.const 20) (f64.const 30))))
+  "type mismatch")
+
+
+(assert_invalid
+  (module
+    (memory 1 1)
+    (func (export "testfn")
+      (memory.fill (i64.const 10) (i64.const 20) (i32.const 30))))
+  "type mismatch")
+
+
+(assert_invalid
+  (module
+    (memory 1 1)
+    (func (export "testfn")
+      (memory.fill (i64.const 10) (i64.const 20) (f32.const 30))))
+  "type mismatch")
+
+
+(assert_invalid
+  (module
+    (memory 1 1)
+    (func (export "testfn")
+      (memory.fill (i64.const 10) (i64.const 20) (i64.const 30))))
+  "type mismatch")
+
+
+(assert_invalid
+  (module
+    (memory 1 1)
+    (func (export "testfn")
+      (memory.fill (i64.const 10) (i64.const 20) (f64.const 30))))
+  "type mismatch")
+
+
+(assert_invalid
+  (module
+    (memory 1 1)
+    (func (export "testfn")
+      (memory.fill (i64.const 10) (f64.const 20) (i32.const 30))))
+  "type mismatch")
+
+
+(assert_invalid
+  (module
+    (memory 1 1)
+    (func (export "testfn")
+      (memory.fill (i64.const 10) (f64.const 20) (f32.const 30))))
+  "type mismatch")
+
+
+(assert_invalid
+  (module
+    (memory 1 1)
+    (func (export "testfn")
+      (memory.fill (i64.const 10) (f64.const 20) (i64.const 30))))
+  "type mismatch")
+
+
+(assert_invalid
+  (module
+    (memory 1 1)
+    (func (export "testfn")
+      (memory.fill (i64.const 10) (f64.const 20) (f64.const 30))))
+  "type mismatch")
+
+
+(assert_invalid
+  (module
+    (memory 1 1)
+    (func (export "testfn")
+      (memory.fill (f64.const 10) (i32.const 20) (i32.const 30))))
+  "type mismatch")
+
+
+(assert_invalid
+  (module
+    (memory 1 1)
+    (func (export "testfn")
+      (memory.fill (f64.const 10) (i32.const 20) (f32.const 30))))
+  "type mismatch")
+
+
+(assert_invalid
+  (module
+    (memory 1 1)
+    (func (export "testfn")
+      (memory.fill (f64.const 10) (i32.const 20) (i64.const 30))))
+  "type mismatch")
+
+
+(assert_invalid
+  (module
+    (memory 1 1)
+    (func (export "testfn")
+      (memory.fill (f64.const 10) (i32.const 20) (f64.const 30))))
+  "type mismatch")
+
+
+(assert_invalid
+  (module
+    (memory 1 1)
+    (func (export "testfn")
+      (memory.fill (f64.const 10) (f32.const 20) (i32.const 30))))
+  "type mismatch")
+
+
+(assert_invalid
+  (module
+    (memory 1 1)
+    (func (export "testfn")
+      (memory.fill (f64.const 10) (f32.const 20) (f32.const 30))))
+  "type mismatch")
+
+
+(assert_invalid
+  (module
+    (memory 1 1)
+    (func (export "testfn")
+      (memory.fill (f64.const 10) (f32.const 20) (i64.const 30))))
+  "type mismatch")
+
+
+(assert_invalid
+  (module
+    (memory 1 1)
+    (func (export "testfn")
+      (memory.fill (f64.const 10) (f32.const 20) (f64.const 30))))
+  "type mismatch")
+
+
+(assert_invalid
+  (module
+    (memory 1 1)
+    (func (export "testfn")
+      (memory.fill (f64.const 10) (i64.const 20) (i32.const 30))))
+  "type mismatch")
+
+
+(assert_invalid
+  (module
+    (memory 1 1)
+    (func (export "testfn")
+      (memory.fill (f64.const 10) (i64.const 20) (f32.const 30))))
+  "type mismatch")
+
+
+(assert_invalid
+  (module
+    (memory 1 1)
+    (func (export "testfn")
+      (memory.fill (f64.const 10) (i64.const 20) (i64.const 30))))
+  "type mismatch")
+
+
+(assert_invalid
+  (module
+    (memory 1 1)
+    (func (export "testfn")
+      (memory.fill (f64.const 10) (i64.const 20) (f64.const 30))))
+  "type mismatch")
+
+
+(assert_invalid
+  (module
+    (memory 1 1)
+    (func (export "testfn")
+      (memory.fill (f64.const 10) (f64.const 20) (i32.const 30))))
+  "type mismatch")
+
+
+(assert_invalid
+  (module
+    (memory 1 1)
+    (func (export "testfn")
+      (memory.fill (f64.const 10) (f64.const 20) (f32.const 30))))
+  "type mismatch")
+
+
+(assert_invalid
+  (module
+    (memory 1 1)
+    (func (export "testfn")
+      (memory.fill (f64.const 10) (f64.const 20) (i64.const 30))))
+  "type mismatch")
+
+
+(assert_invalid
+  (module
+    (memory 1 1)
+    (func (export "testfn")
+      (memory.fill (f64.const 10) (f64.const 20) (f64.const 30))))
+  "type mismatch")
+
+(module
+  (memory 1 1 )
+  
+  (func (export "checkRange") (param $from i32) (param $to i32) (param $expected i32) (result i32)
+   (loop $cont
+     (if (i32.eq (local.get $from) (local.get $to))
+         (then
+           (return (i32.const -1))))
+     (if (i32.eq (i32.load8_u (local.get $from)) (local.get $expected))
+         (then
+           (local.set $from (i32.add (local.get $from) (i32.const 1)))
+           (br $cont))))
+   (return (local.get $from)))
+
+  (func (export "run") (param $offs i32) (param $val i32) (param $len i32)
+    (memory.fill (local.get $offs) (local.get $val) (local.get $len))))
+
+(assert_trap (invoke "run" (i32.const 65280) (i32.const 37) (i32.const 512))
+              "out of bounds")
+
+(assert_return (invoke "checkRange" (i32.const 65280) (i32.const 65536) (i32.const 37))
+               (i32.const -1))
+(assert_return (invoke "checkRange" (i32.const 0) (i32.const 65280) (i32.const 0))
+               (i32.const -1))
+(module
+  (memory 1 1 )
+  
+  (func (export "checkRange") (param $from i32) (param $to i32) (param $expected i32) (result i32)
+   (loop $cont
+     (if (i32.eq (local.get $from) (local.get $to))
+         (then
+           (return (i32.const -1))))
+     (if (i32.eq (i32.load8_u (local.get $from)) (local.get $expected))
+         (then
+           (local.set $from (i32.add (local.get $from) (i32.const 1)))
+           (br $cont))))
+   (return (local.get $from)))
+
+  (func (export "run") (param $offs i32) (param $val i32) (param $len i32)
+    (memory.fill (local.get $offs) (local.get $val) (local.get $len))))
+
+(assert_trap (invoke "run" (i32.const 65279) (i32.const 37) (i32.const 514))
+              "out of bounds")
+
+(assert_return (invoke "checkRange" (i32.const 65279) (i32.const 65536) (i32.const 37))
+               (i32.const -1))
+(assert_return (invoke "checkRange" (i32.const 0) (i32.const 65279) (i32.const 0))
+               (i32.const -1))
+(module
+  (memory 1 1 )
+  
+  (func (export "checkRange") (param $from i32) (param $to i32) (param $expected i32) (result i32)
+   (loop $cont
+     (if (i32.eq (local.get $from) (local.get $to))
+         (then
+           (return (i32.const -1))))
+     (if (i32.eq (i32.load8_u (local.get $from)) (local.get $expected))
+         (then
+           (local.set $from (i32.add (local.get $from) (i32.const 1)))
+           (br $cont))))
+   (return (local.get $from)))
+
+  (func (export "run") (param $offs i32) (param $val i32) (param $len i32)
+    (memory.fill (local.get $offs) (local.get $val) (local.get $len))))
+
+(assert_trap (invoke "run" (i32.const 65279) (i32.const 37) (i32.const 4294967295))
+              "out of bounds")
+
+(assert_return (invoke "checkRange" (i32.const 65279) (i32.const 65536) (i32.const 37))
+               (i32.const -1))
+(assert_return (invoke "checkRange" (i32.const 0) (i32.const 65279) (i32.const 0))
+               (i32.const -1))
diff --git a/test/core/memory_init.wast b/test/core/memory_init.wast
new file mode 100644
index 0000000000..e30dc05e79
--- /dev/null
+++ b/test/core/memory_init.wast
@@ -0,0 +1,947 @@
+;;
+;; Generated by ../meta/generate_memory_init.js
+;;
+
+(module
+  (memory (export "memory0") 1 1)
+  (data (i32.const 2) "\03\01\04\01")
+  (data passive "\02\07\01\08")
+  (data (i32.const 12) "\07\05\02\03\06")
+  (data passive "\05\09\02\07\06")
+  (func (export "test")
+    nop)
+  (func (export "load8_u") (param i32) (result i32)
+    (i32.load8_u (local.get 0))))
+
+(invoke "test")
+
+(assert_return (invoke "load8_u" (i32.const 0)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 1)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 2)) (i32.const 3))
+(assert_return (invoke "load8_u" (i32.const 3)) (i32.const 1))
+(assert_return (invoke "load8_u" (i32.const 4)) (i32.const 4))
+(assert_return (invoke "load8_u" (i32.const 5)) (i32.const 1))
+(assert_return (invoke "load8_u" (i32.const 6)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 7)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 8)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 9)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 10)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 11)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 12)) (i32.const 7))
+(assert_return (invoke "load8_u" (i32.const 13)) (i32.const 5))
+(assert_return (invoke "load8_u" (i32.const 14)) (i32.const 2))
+(assert_return (invoke "load8_u" (i32.const 15)) (i32.const 3))
+(assert_return (invoke "load8_u" (i32.const 16)) (i32.const 6))
+(assert_return (invoke "load8_u" (i32.const 17)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 18)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 19)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 20)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 21)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 22)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 23)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 24)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 25)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 26)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 27)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 28)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 29)) (i32.const 0))
+
+(module
+  (memory (export "memory0") 1 1)
+  (data (i32.const 2) "\03\01\04\01")
+  (data passive "\02\07\01\08")
+  (data (i32.const 12) "\07\05\02\03\06")
+  (data passive "\05\09\02\07\06")
+  (func (export "test")
+    (memory.init 1 (i32.const 7) (i32.const 0) (i32.const 4)))
+  (func (export "load8_u") (param i32) (result i32)
+    (i32.load8_u (local.get 0))))
+
+(invoke "test")
+
+(assert_return (invoke "load8_u" (i32.const 0)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 1)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 2)) (i32.const 3))
+(assert_return (invoke "load8_u" (i32.const 3)) (i32.const 1))
+(assert_return (invoke "load8_u" (i32.const 4)) (i32.const 4))
+(assert_return (invoke "load8_u" (i32.const 5)) (i32.const 1))
+(assert_return (invoke "load8_u" (i32.const 6)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 7)) (i32.const 2))
+(assert_return (invoke "load8_u" (i32.const 8)) (i32.const 7))
+(assert_return (invoke "load8_u" (i32.const 9)) (i32.const 1))
+(assert_return (invoke "load8_u" (i32.const 10)) (i32.const 8))
+(assert_return (invoke "load8_u" (i32.const 11)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 12)) (i32.const 7))
+(assert_return (invoke "load8_u" (i32.const 13)) (i32.const 5))
+(assert_return (invoke "load8_u" (i32.const 14)) (i32.const 2))
+(assert_return (invoke "load8_u" (i32.const 15)) (i32.const 3))
+(assert_return (invoke "load8_u" (i32.const 16)) (i32.const 6))
+(assert_return (invoke "load8_u" (i32.const 17)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 18)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 19)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 20)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 21)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 22)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 23)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 24)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 25)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 26)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 27)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 28)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 29)) (i32.const 0))
+
+(module
+  (memory (export "memory0") 1 1)
+  (data (i32.const 2) "\03\01\04\01")
+  (data passive "\02\07\01\08")
+  (data (i32.const 12) "\07\05\02\03\06")
+  (data passive "\05\09\02\07\06")
+  (func (export "test")
+    (memory.init 3 (i32.const 15) (i32.const 1) (i32.const 3)))
+  (func (export "load8_u") (param i32) (result i32)
+    (i32.load8_u (local.get 0))))
+
+(invoke "test")
+
+(assert_return (invoke "load8_u" (i32.const 0)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 1)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 2)) (i32.const 3))
+(assert_return (invoke "load8_u" (i32.const 3)) (i32.const 1))
+(assert_return (invoke "load8_u" (i32.const 4)) (i32.const 4))
+(assert_return (invoke "load8_u" (i32.const 5)) (i32.const 1))
+(assert_return (invoke "load8_u" (i32.const 6)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 7)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 8)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 9)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 10)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 11)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 12)) (i32.const 7))
+(assert_return (invoke "load8_u" (i32.const 13)) (i32.const 5))
+(assert_return (invoke "load8_u" (i32.const 14)) (i32.const 2))
+(assert_return (invoke "load8_u" (i32.const 15)) (i32.const 9))
+(assert_return (invoke "load8_u" (i32.const 16)) (i32.const 2))
+(assert_return (invoke "load8_u" (i32.const 17)) (i32.const 7))
+(assert_return (invoke "load8_u" (i32.const 18)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 19)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 20)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 21)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 22)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 23)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 24)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 25)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 26)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 27)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 28)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 29)) (i32.const 0))
+
+(module
+  (memory (export "memory0") 1 1)
+  (data (i32.const 2) "\03\01\04\01")
+  (data passive "\02\07\01\08")
+  (data (i32.const 12) "\07\05\02\03\06")
+  (data passive "\05\09\02\07\06")
+  (func (export "test")
+    (memory.init 1 (i32.const 7) (i32.const 0) (i32.const 4)) 
+data.drop 1 
+(memory.init 3 (i32.const 15) (i32.const 1) (i32.const 3)) 
+data.drop 3 
+(memory.copy (i32.const 20) (i32.const 15) (i32.const 5)) 
+(memory.copy (i32.const 21) (i32.const 29) (i32.const 1)) 
+(memory.copy (i32.const 24) (i32.const 10) (i32.const 1)) 
+(memory.copy (i32.const 13) (i32.const 11) (i32.const 4)) 
+(memory.copy (i32.const 19) (i32.const 20) (i32.const 5)))
+  (func (export "load8_u") (param i32) (result i32)
+    (i32.load8_u (local.get 0))))
+
+(invoke "test")
+
+(assert_return (invoke "load8_u" (i32.const 0)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 1)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 2)) (i32.const 3))
+(assert_return (invoke "load8_u" (i32.const 3)) (i32.const 1))
+(assert_return (invoke "load8_u" (i32.const 4)) (i32.const 4))
+(assert_return (invoke "load8_u" (i32.const 5)) (i32.const 1))
+(assert_return (invoke "load8_u" (i32.const 6)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 7)) (i32.const 2))
+(assert_return (invoke "load8_u" (i32.const 8)) (i32.const 7))
+(assert_return (invoke "load8_u" (i32.const 9)) (i32.const 1))
+(assert_return (invoke "load8_u" (i32.const 10)) (i32.const 8))
+(assert_return (invoke "load8_u" (i32.const 11)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 12)) (i32.const 7))
+(assert_return (invoke "load8_u" (i32.const 13)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 14)) (i32.const 7))
+(assert_return (invoke "load8_u" (i32.const 15)) (i32.const 5))
+(assert_return (invoke "load8_u" (i32.const 16)) (i32.const 2))
+(assert_return (invoke "load8_u" (i32.const 17)) (i32.const 7))
+(assert_return (invoke "load8_u" (i32.const 18)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 19)) (i32.const 9))
+(assert_return (invoke "load8_u" (i32.const 20)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 21)) (i32.const 7))
+(assert_return (invoke "load8_u" (i32.const 22)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 23)) (i32.const 8))
+(assert_return (invoke "load8_u" (i32.const 24)) (i32.const 8))
+(assert_return (invoke "load8_u" (i32.const 25)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 26)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 27)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 28)) (i32.const 0))
+(assert_return (invoke "load8_u" (i32.const 29)) (i32.const 0))
+(assert_invalid
+   (module
+     (func (export "test")
+       (data.drop 0)))
+   "unknown memory 0")
+
+(assert_invalid
+  (module
+    (memory 1)
+     (data passive "\37")
+    (func (export "test")
+      (data.drop 4)))
+  "unknown data segment")
+
+(module
+  (memory 1)
+     (data passive "\37")
+  (func (export "test")
+    (data.drop 0)
+    (data.drop 0)))
+(assert_trap (invoke "test") "data segment dropped")
+
+(module
+  (memory 1)
+     (data passive "\37")
+  (func (export "test")
+    (data.drop 0)
+    (memory.init 0 (i32.const 1234) (i32.const 1) (i32.const 1))))
+(assert_trap (invoke "test") "data segment dropped")
+
+(module
+   (memory 1)
+   (data (i32.const 0) "\37")
+   (func (export "test")
+     (memory.init 0 (i32.const 1234) (i32.const 1) (i32.const 1))))
+(assert_trap (invoke "test") "data segment dropped")
+
+(assert_invalid
+  (module
+    (func (export "test")
+      (memory.init 1 (i32.const 1234) (i32.const 1) (i32.const 1))))
+  "unknown memory 0")
+
+(assert_invalid
+  (module
+    (memory 1)
+     (data passive "\37")
+    (func (export "test")
+      (memory.init 1 (i32.const 1234) (i32.const 1) (i32.const 1))))
+  "unknown data segment 1")
+
+(module
+  (memory 1)
+     (data passive "\37")
+  (func (export "test")
+    (memory.init 0 (i32.const 1) (i32.const 0) (i32.const 1))
+    (memory.init 0 (i32.const 1) (i32.const 0) (i32.const 1))))
+(invoke "test")
+
+(module
+  (memory 1)
+     (data passive "\37")
+  (func (export "test")
+    (memory.init 0 (i32.const 1234) (i32.const 0) (i32.const 5))))
+(assert_trap (invoke "test") "out of bounds")
+
+(module
+  (memory 1)
+     (data passive "\37")
+  (func (export "test")
+    (memory.init 0 (i32.const 1234) (i32.const 2) (i32.const 3))))
+(assert_trap (invoke "test") "out of bounds")
+
+(module
+  (memory 1)
+     (data passive "\37")
+  (func (export "test")
+    (memory.init 0 (i32.const 0xFFFE) (i32.const 1) (i32.const 3))))
+(assert_trap (invoke "test") "out of bounds")
+
+(module
+  (memory 1)
+     (data passive "\37")
+  (func (export "test")
+    (memory.init 0 (i32.const 1234) (i32.const 4) (i32.const 0))))
+(assert_trap (invoke "test") "out of bounds")
+
+(module
+  (memory 1)
+     (data passive "\37")
+  (func (export "test")
+    (memory.init 0 (i32.const 0x10000) (i32.const 2) (i32.const 0))))
+(assert_trap (invoke "test") "out of bounds")
+
+(assert_invalid
+   (module
+     (memory 1)
+     (data passive "\37")
+     (func (export "test")
+       (memory.init 0 (i32.const 1) (i32.const 1) (f32.const 1))))
+   "type mismatch")
+
+(assert_invalid
+   (module
+     (memory 1)
+     (data passive "\37")
+     (func (export "test")
+       (memory.init 0 (i32.const 1) (i32.const 1) (i64.const 1))))
+   "type mismatch")
+
+(assert_invalid
+   (module
+     (memory 1)
+     (data passive "\37")
+     (func (export "test")
+       (memory.init 0 (i32.const 1) (i32.const 1) (f64.const 1))))
+   "type mismatch")
+
+(assert_invalid
+   (module
+     (memory 1)
+     (data passive "\37")
+     (func (export "test")
+       (memory.init 0 (i32.const 1) (f32.const 1) (i32.const 1))))
+   "type mismatch")
+
+(assert_invalid
+   (module
+     (memory 1)
+     (data passive "\37")
+     (func (export "test")
+       (memory.init 0 (i32.const 1) (f32.const 1) (f32.const 1))))
+   "type mismatch")
+
+(assert_invalid
+   (module
+     (memory 1)
+     (data passive "\37")
+     (func (export "test")
+       (memory.init 0 (i32.const 1) (f32.const 1) (i64.const 1))))
+   "type mismatch")
+
+(assert_invalid
+   (module
+     (memory 1)
+     (data passive "\37")
+     (func (export "test")
+       (memory.init 0 (i32.const 1) (f32.const 1) (f64.const 1))))
+   "type mismatch")
+
+(assert_invalid
+   (module
+     (memory 1)
+     (data passive "\37")
+     (func (export "test")
+       (memory.init 0 (i32.const 1) (i64.const 1) (i32.const 1))))
+   "type mismatch")
+
+(assert_invalid
+   (module
+     (memory 1)
+     (data passive "\37")
+     (func (export "test")
+       (memory.init 0 (i32.const 1) (i64.const 1) (f32.const 1))))
+   "type mismatch")
+
+(assert_invalid
+   (module
+     (memory 1)
+     (data passive "\37")
+     (func (export "test")
+       (memory.init 0 (i32.const 1) (i64.const 1) (i64.const 1))))
+   "type mismatch")
+
+(assert_invalid
+   (module
+     (memory 1)
+     (data passive "\37")
+     (func (export "test")
+       (memory.init 0 (i32.const 1) (i64.const 1) (f64.const 1))))
+   "type mismatch")
+
+(assert_invalid
+   (module
+     (memory 1)
+     (data passive "\37")
+     (func (export "test")
+       (memory.init 0 (i32.const 1) (f64.const 1) (i32.const 1))))
+   "type mismatch")
+
+(assert_invalid
+   (module
+     (memory 1)
+     (data passive "\37")
+     (func (export "test")
+       (memory.init 0 (i32.const 1) (f64.const 1) (f32.const 1))))
+   "type mismatch")
+
+(assert_invalid
+   (module
+     (memory 1)
+     (data passive "\37")
+     (func (export "test")
+       (memory.init 0 (i32.const 1) (f64.const 1) (i64.const 1))))
+   "type mismatch")
+
+(assert_invalid
+   (module
+     (memory 1)
+     (data passive "\37")
+     (func (export "test")
+       (memory.init 0 (i32.const 1) (f64.const 1) (f64.const 1))))
+   "type mismatch")
+
+(assert_invalid
+   (module
+     (memory 1)
+     (data passive "\37")
+     (func (export "test")
+       (memory.init 0 (f32.const 1) (i32.const 1) (i32.const 1))))
+   "type mismatch")
+
+(assert_invalid
+   (module
+     (memory 1)
+     (data passive "\37")
+     (func (export "test")
+       (memory.init 0 (f32.const 1) (i32.const 1) (f32.const 1))))
+   "type mismatch")
+
+(assert_invalid
+   (module
+     (memory 1)
+     (data passive "\37")
+     (func (export "test")
+       (memory.init 0 (f32.const 1) (i32.const 1) (i64.const 1))))
+   "type mismatch")
+
+(assert_invalid
+   (module
+     (memory 1)
+     (data passive "\37")
+     (func (export "test")
+       (memory.init 0 (f32.const 1) (i32.const 1) (f64.const 1))))
+   "type mismatch")
+
+(assert_invalid
+   (module
+     (memory 1)
+     (data passive "\37")
+     (func (export "test")
+       (memory.init 0 (f32.const 1) (f32.const 1) (i32.const 1))))
+   "type mismatch")
+
+(assert_invalid
+   (module
+     (memory 1)
+     (data passive "\37")
+     (func (export "test")
+       (memory.init 0 (f32.const 1) (f32.const 1) (f32.const 1))))
+   "type mismatch")
+
+(assert_invalid
+   (module
+     (memory 1)
+     (data passive "\37")
+     (func (export "test")
+       (memory.init 0 (f32.const 1) (f32.const 1) (i64.const 1))))
+   "type mismatch")
+
+(assert_invalid
+   (module
+     (memory 1)
+     (data passive "\37")
+     (func (export "test")
+       (memory.init 0 (f32.const 1) (f32.const 1) (f64.const 1))))
+   "type mismatch")
+
+(assert_invalid
+   (module
+     (memory 1)
+     (data passive "\37")
+     (func (export "test")
+       (memory.init 0 (f32.const 1) (i64.const 1) (i32.const 1))))
+   "type mismatch")
+
+(assert_invalid
+   (module
+     (memory 1)
+     (data passive "\37")
+     (func (export "test")
+       (memory.init 0 (f32.const 1) (i64.const 1) (f32.const 1))))
+   "type mismatch")
+
+(assert_invalid
+   (module
+     (memory 1)
+     (data passive "\37")
+     (func (export "test")
+       (memory.init 0 (f32.const 1) (i64.const 1) (i64.const 1))))
+   "type mismatch")
+
+(assert_invalid
+   (module
+     (memory 1)
+     (data passive "\37")
+     (func (export "test")
+       (memory.init 0 (f32.const 1) (i64.const 1) (f64.const 1))))
+   "type mismatch")
+
+(assert_invalid
+   (module
+     (memory 1)
+     (data passive "\37")
+     (func (export "test")
+       (memory.init 0 (f32.const 1) (f64.const 1) (i32.const 1))))
+   "type mismatch")
+
+(assert_invalid
+   (module
+     (memory 1)
+     (data passive "\37")
+     (func (export "test")
+       (memory.init 0 (f32.const 1) (f64.const 1) (f32.const 1))))
+   "type mismatch")
+
+(assert_invalid
+   (module
+     (memory 1)
+     (data passive "\37")
+     (func (export "test")
+       (memory.init 0 (f32.const 1) (f64.const 1) (i64.const 1))))
+   "type mismatch")
+
+(assert_invalid
+   (module
+     (memory 1)
+     (data passive "\37")
+     (func (export "test")
+       (memory.init 0 (f32.const 1) (f64.const 1) (f64.const 1))))
+   "type mismatch")
+
+(assert_invalid
+   (module
+     (memory 1)
+     (data passive "\37")
+     (func (export "test")
+       (memory.init 0 (i64.const 1) (i32.const 1) (i32.const 1))))
+   "type mismatch")
+
+(assert_invalid
+   (module
+     (memory 1)
+     (data passive "\37")
+     (func (export "test")
+       (memory.init 0 (i64.const 1) (i32.const 1) (f32.const 1))))
+   "type mismatch")
+
+(assert_invalid
+   (module
+     (memory 1)
+     (data passive "\37")
+     (func (export "test")
+       (memory.init 0 (i64.const 1) (i32.const 1) (i64.const 1))))
+   "type mismatch")
+
+(assert_invalid
+   (module
+     (memory 1)
+     (data passive "\37")
+     (func (export "test")
+       (memory.init 0 (i64.const 1) (i32.const 1) (f64.const 1))))
+   "type mismatch")
+
+(assert_invalid
+   (module
+     (memory 1)
+     (data passive "\37")
+     (func (export "test")
+       (memory.init 0 (i64.const 1) (f32.const 1) (i32.const 1))))
+   "type mismatch")
+
+(assert_invalid
+   (module
+     (memory 1)
+     (data passive "\37")
+     (func (export "test")
+       (memory.init 0 (i64.const 1) (f32.const 1) (f32.const 1))))
+   "type mismatch")
+
+(assert_invalid
+   (module
+     (memory 1)
+     (data passive "\37")
+     (func (export "test")
+       (memory.init 0 (i64.const 1) (f32.const 1) (i64.const 1))))
+   "type mismatch")
+
+(assert_invalid
+   (module
+     (memory 1)
+     (data passive "\37")
+     (func (export "test")
+       (memory.init 0 (i64.const 1) (f32.const 1) (f64.const 1))))
+   "type mismatch")
+
+(assert_invalid
+   (module
+     (memory 1)
+     (data passive "\37")
+     (func (export "test")
+       (memory.init 0 (i64.const 1) (i64.const 1) (i32.const 1))))
+   "type mismatch")
+
+(assert_invalid
+   (module
+     (memory 1)
+     (data passive "\37")
+     (func (export "test")
+       (memory.init 0 (i64.const 1) (i64.const 1) (f32.const 1))))
+   "type mismatch")
+
+(assert_invalid
+   (module
+     (memory 1)
+     (data passive "\37")
+     (func (export "test")
+       (memory.init 0 (i64.const 1) (i64.const 1) (i64.const 1))))
+   "type mismatch")
+
+(assert_invalid
+   (module
+     (memory 1)
+     (data passive "\37")
+     (func (export "test")
+       (memory.init 0 (i64.const 1) (i64.const 1) (f64.const 1))))
+   "type mismatch")
+
+(assert_invalid
+   (module
+     (memory 1)
+     (data passive "\37")
+     (func (export "test")
+       (memory.init 0 (i64.const 1) (f64.const 1) (i32.const 1))))
+   "type mismatch")
+
+(assert_invalid
+   (module
+     (memory 1)
+     (data passive "\37")
+     (func (export "test")
+       (memory.init 0 (i64.const 1) (f64.const 1) (f32.const 1))))
+   "type mismatch")
+
+(assert_invalid
+   (module
+     (memory 1)
+     (data passive "\37")
+     (func (export "test")
+       (memory.init 0 (i64.const 1) (f64.const 1) (i64.const 1))))
+   "type mismatch")
+
+(assert_invalid
+   (module
+     (memory 1)
+     (data passive "\37")
+     (func (export "test")
+       (memory.init 0 (i64.const 1) (f64.const 1) (f64.const 1))))
+   "type mismatch")
+
+(assert_invalid
+   (module
+     (memory 1)
+     (data passive "\37")
+     (func (export "test")
+       (memory.init 0 (f64.const 1) (i32.const 1) (i32.const 1))))
+   "type mismatch")
+
+(assert_invalid
+   (module
+     (memory 1)
+     (data passive "\37")
+     (func (export "test")
+       (memory.init 0 (f64.const 1) (i32.const 1) (f32.const 1))))
+   "type mismatch")
+
+(assert_invalid
+   (module
+     (memory 1)
+     (data passive "\37")
+     (func (export "test")
+       (memory.init 0 (f64.const 1) (i32.const 1) (i64.const 1))))
+   "type mismatch")
+
+(assert_invalid
+   (module
+     (memory 1)
+     (data passive "\37")
+     (func (export "test")
+       (memory.init 0 (f64.const 1) (i32.const 1) (f64.const 1))))
+   "type mismatch")
+
+(assert_invalid
+   (module
+     (memory 1)
+     (data passive "\37")
+     (func (export "test")
+       (memory.init 0 (f64.const 1) (f32.const 1) (i32.const 1))))
+   "type mismatch")
+
+(assert_invalid
+   (module
+     (memory 1)
+     (data passive "\37")
+     (func (export "test")
+       (memory.init 0 (f64.const 1) (f32.const 1) (f32.const 1))))
+   "type mismatch")
+
+(assert_invalid
+   (module
+     (memory 1)
+     (data passive "\37")
+     (func (export "test")
+       (memory.init 0 (f64.const 1) (f32.const 1) (i64.const 1))))
+   "type mismatch")
+
+(assert_invalid
+   (module
+     (memory 1)
+     (data passive "\37")
+     (func (export "test")
+       (memory.init 0 (f64.const 1) (f32.const 1) (f64.const 1))))
+   "type mismatch")
+
+(assert_invalid
+   (module
+     (memory 1)
+     (data passive "\37")
+     (func (export "test")
+       (memory.init 0 (f64.const 1) (i64.const 1) (i32.const 1))))
+   "type mismatch")
+
+(assert_invalid
+   (module
+     (memory 1)
+     (data passive "\37")
+     (func (export "test")
+       (memory.init 0 (f64.const 1) (i64.const 1) (f32.const 1))))
+   "type mismatch")
+
+(assert_invalid
+   (module
+     (memory 1)
+     (data passive "\37")
+     (func (export "test")
+       (memory.init 0 (f64.const 1) (i64.const 1) (i64.const 1))))
+   "type mismatch")
+
+(assert_invalid
+   (module
+     (memory 1)
+     (data passive "\37")
+     (func (export "test")
+       (memory.init 0 (f64.const 1) (i64.const 1) (f64.const 1))))
+   "type mismatch")
+
+(assert_invalid
+   (module
+     (memory 1)
+     (data passive "\37")
+     (func (export "test")
+       (memory.init 0 (f64.const 1) (f64.const 1) (i32.const 1))))
+   "type mismatch")
+
+(assert_invalid
+   (module
+     (memory 1)
+     (data passive "\37")
+     (func (export "test")
+       (memory.init 0 (f64.const 1) (f64.const 1) (f32.const 1))))
+   "type mismatch")
+
+(assert_invalid
+   (module
+     (memory 1)
+     (data passive "\37")
+     (func (export "test")
+       (memory.init 0 (f64.const 1) (f64.const 1) (i64.const 1))))
+   "type mismatch")
+
+(assert_invalid
+   (module
+     (memory 1)
+     (data passive "\37")
+     (func (export "test")
+       (memory.init 0 (f64.const 1) (f64.const 1) (f64.const 1))))
+   "type mismatch")
+
+(module
+   (memory 1 1 )
+   (data passive "\42\42\42\42\42\42\42\42\42\42\42\42\42\42\42\42")
+   
+  (func (export "checkRange") (param $from i32) (param $to i32) (param $expected i32) (result i32)
+   (loop $cont
+     (if (i32.eq (local.get $from) (local.get $to))
+         (then
+           (return (i32.const -1))))
+     (if (i32.eq (i32.load8_u (local.get $from)) (local.get $expected))
+         (then
+           (local.set $from (i32.add (local.get $from) (i32.const 1)))
+           (br $cont))))
+   (return (local.get $from)))
+
+   (func (export "run") (param $offs i32) (param $len i32)
+     (memory.init 0 (local.get $offs) (i32.const 0) (local.get $len))))
+
+(assert_trap (invoke "run" (i32.const 65528) (i32.const 16))
+              "out of bounds")
+
+(assert_return (invoke "checkRange" (i32.const 0) (i32.const 65528) (i32.const 0))
+               (i32.const -1))
+(assert_return (invoke "checkRange" (i32.const 65528) (i32.const 65536) (i32.const 66))
+               (i32.const -1))
+(assert_return (invoke "checkRange" (i32.const 65536) (i32.const 65536) (i32.const 0))
+               (i32.const -1))
+(module
+   (memory 1 1 )
+   (data passive "\42\42\42\42\42\42\42\42\42\42\42\42\42\42\42\42")
+   
+  (func (export "checkRange") (param $from i32) (param $to i32) (param $expected i32) (result i32)
+   (loop $cont
+     (if (i32.eq (local.get $from) (local.get $to))
+         (then
+           (return (i32.const -1))))
+     (if (i32.eq (i32.load8_u (local.get $from)) (local.get $expected))
+         (then
+           (local.set $from (i32.add (local.get $from) (i32.const 1)))
+           (br $cont))))
+   (return (local.get $from)))
+
+   (func (export "run") (param $offs i32) (param $len i32)
+     (memory.init 0 (local.get $offs) (i32.const 0) (local.get $len))))
+
+(assert_trap (invoke "run" (i32.const 65527) (i32.const 16))
+              "out of bounds")
+
+(assert_return (invoke "checkRange" (i32.const 0) (i32.const 65527) (i32.const 0))
+               (i32.const -1))
+(assert_return (invoke "checkRange" (i32.const 65527) (i32.const 65536) (i32.const 66))
+               (i32.const -1))
+(assert_return (invoke "checkRange" (i32.const 65536) (i32.const 65536) (i32.const 0))
+               (i32.const -1))
+(module
+   (memory 1 1 )
+   (data passive "\42\42\42\42\42\42\42\42\42\42\42\42\42\42\42\42")
+   
+  (func (export "checkRange") (param $from i32) (param $to i32) (param $expected i32) (result i32)
+   (loop $cont
+     (if (i32.eq (local.get $from) (local.get $to))
+         (then
+           (return (i32.const -1))))
+     (if (i32.eq (i32.load8_u (local.get $from)) (local.get $expected))
+         (then
+           (local.set $from (i32.add (local.get $from) (i32.const 1)))
+           (br $cont))))
+   (return (local.get $from)))
+
+   (func (export "run") (param $offs i32) (param $len i32)
+     (memory.init 0 (local.get $offs) (i32.const 0) (local.get $len))))
+
+(assert_trap (invoke "run" (i32.const 65472) (i32.const 30))
+              "out of bounds")
+
+(assert_return (invoke "checkRange" (i32.const 0) (i32.const 65472) (i32.const 0))
+               (i32.const -1))
+(assert_return (invoke "checkRange" (i32.const 65472) (i32.const 65488) (i32.const 66))
+               (i32.const -1))
+(assert_return (invoke "checkRange" (i32.const 65488) (i32.const 65536) (i32.const 0))
+               (i32.const -1))
+(module
+   (memory 1 1 )
+   (data passive "\42\42\42\42\42\42\42\42\42\42\42\42\42\42\42\42")
+   
+  (func (export "checkRange") (param $from i32) (param $to i32) (param $expected i32) (result i32)
+   (loop $cont
+     (if (i32.eq (local.get $from) (local.get $to))
+         (then
+           (return (i32.const -1))))
+     (if (i32.eq (i32.load8_u (local.get $from)) (local.get $expected))
+         (then
+           (local.set $from (i32.add (local.get $from) (i32.const 1)))
+           (br $cont))))
+   (return (local.get $from)))
+
+   (func (export "run") (param $offs i32) (param $len i32)
+     (memory.init 0 (local.get $offs) (i32.const 0) (local.get $len))))
+
+(assert_trap (invoke "run" (i32.const 65473) (i32.const 31))
+              "out of bounds")
+
+(assert_return (invoke "checkRange" (i32.const 0) (i32.const 65473) (i32.const 0))
+               (i32.const -1))
+(assert_return (invoke "checkRange" (i32.const 65473) (i32.const 65489) (i32.const 66))
+               (i32.const -1))
+(assert_return (invoke "checkRange" (i32.const 65489) (i32.const 65536) (i32.const 0))
+               (i32.const -1))
+(module
+   (memory 1  )
+   (data passive "\42\42\42\42\42\42\42\42\42\42\42\42\42\42\42\42")
+   
+  (func (export "checkRange") (param $from i32) (param $to i32) (param $expected i32) (result i32)
+   (loop $cont
+     (if (i32.eq (local.get $from) (local.get $to))
+         (then
+           (return (i32.const -1))))
+     (if (i32.eq (i32.load8_u (local.get $from)) (local.get $expected))
+         (then
+           (local.set $from (i32.add (local.get $from) (i32.const 1)))
+           (br $cont))))
+   (return (local.get $from)))
+
+   (func (export "run") (param $offs i32) (param $len i32)
+     (memory.init 0 (local.get $offs) (i32.const 0) (local.get $len))))
+
+(assert_trap (invoke "run" (i32.const 65528) (i32.const 4294967040))
+              "out of bounds")
+
+(assert_return (invoke "checkRange" (i32.const 0) (i32.const 65528) (i32.const 0))
+               (i32.const -1))
+(assert_return (invoke "checkRange" (i32.const 65528) (i32.const 65536) (i32.const 66))
+               (i32.const -1))
+(assert_return (invoke "checkRange" (i32.const 65536) (i32.const 65536) (i32.const 0))
+               (i32.const -1))
+(module
+   (memory 1  )
+   (data passive "\42\42\42\42\42\42\42\42\42\42\42\42\42\42\42\42")
+   
+  (func (export "checkRange") (param $from i32) (param $to i32) (param $expected i32) (result i32)
+   (loop $cont
+     (if (i32.eq (local.get $from) (local.get $to))
+         (then
+           (return (i32.const -1))))
+     (if (i32.eq (i32.load8_u (local.get $from)) (local.get $expected))
+         (then
+           (local.set $from (i32.add (local.get $from) (i32.const 1)))
+           (br $cont))))
+   (return (local.get $from)))
+
+   (func (export "run") (param $offs i32) (param $len i32)
+     (memory.init 0 (local.get $offs) (i32.const 0) (local.get $len))))
+
+(assert_trap (invoke "run" (i32.const 0) (i32.const 4294967292))
+              "out of bounds")
+
+(assert_return (invoke "checkRange" (i32.const 0) (i32.const 0) (i32.const 0))
+               (i32.const -1))
+(assert_return (invoke "checkRange" (i32.const 0) (i32.const 16) (i32.const 66))
+               (i32.const -1))
+(assert_return (invoke "checkRange" (i32.const 16) (i32.const 65536) (i32.const 0))
+               (i32.const -1))
diff --git a/test/core/table_copy.wast b/test/core/table_copy.wast
new file mode 100644
index 0000000000..74c95fb424
--- /dev/null
+++ b/test/core/table_copy.wast
@@ -0,0 +1,1448 @@
+;;
+;; Generated by ../meta/generate_table_copy.js
+;;
+
+(module
+  (func (export "ef0") (result i32) (i32.const 0))
+  (func (export "ef1") (result i32) (i32.const 1))
+  (func (export "ef2") (result i32) (i32.const 2))
+  (func (export "ef3") (result i32) (i32.const 3))
+  (func (export "ef4") (result i32) (i32.const 4))
+)
+(register "a")
+
+
+(module
+  (type (func (result i32)))  ;; type #0
+  (import "a" "ef0" (func (result i32)))    ;; index 0
+  (import "a" "ef1" (func (result i32)))
+  (import "a" "ef2" (func (result i32)))
+  (import "a" "ef3" (func (result i32)))
+  (import "a" "ef4" (func (result i32)))    ;; index 4
+  (table 30 30 funcref)
+  (elem (i32.const 2) 3 1 4 1)
+  (elem passive 2 7 1 8)
+  (elem (i32.const 12) 7 5 2 3 6)
+  (elem passive 5 9 2 7 6)
+  (func (result i32) (i32.const 5))  ;; index 5
+  (func (result i32) (i32.const 6))
+  (func (result i32) (i32.const 7))
+  (func (result i32) (i32.const 8))
+  (func (result i32) (i32.const 9))  ;; index 9
+  (func (export "test")
+    nop)
+  (func (export "check") (param i32) (result i32)
+    (call_indirect (type 0) (local.get 0)))
+)
+
+(invoke "test")
+(assert_trap (invoke "check" (i32.const 0)) "uninitialized element")
+(assert_trap (invoke "check" (i32.const 1)) "uninitialized element")
+(assert_return (invoke "check" (i32.const 2)) (i32.const 3))
+(assert_return (invoke "check" (i32.const 3)) (i32.const 1))
+(assert_return (invoke "check" (i32.const 4)) (i32.const 4))
+(assert_return (invoke "check" (i32.const 5)) (i32.const 1))
+(assert_trap (invoke "check" (i32.const 6)) "uninitialized element")
+(assert_trap (invoke "check" (i32.const 7)) "uninitialized element")
+(assert_trap (invoke "check" (i32.const 8)) "uninitialized element")
+(assert_trap (invoke "check" (i32.const 9)) "uninitialized element")
+(assert_trap (invoke "check" (i32.const 10)) "uninitialized element")
+(assert_trap (invoke "check" (i32.const 11)) "uninitialized element")
+(assert_return (invoke "check" (i32.const 12)) (i32.const 7))
+(assert_return (invoke "check" (i32.const 13)) (i32.const 5))
+(assert_return (invoke "check" (i32.const 14)) (i32.const 2))
+(assert_return (invoke "check" (i32.const 15)) (i32.const 3))
+(assert_return (invoke "check" (i32.const 16)) (i32.const 6))
+(assert_trap (invoke "check" (i32.const 17)) "uninitialized element")
+(assert_trap (invoke "check" (i32.const 18)) "uninitialized element")
+(assert_trap (invoke "check" (i32.const 19)) "uninitialized element")
+(assert_trap (invoke "check" (i32.const 20)) "uninitialized element")
+(assert_trap (invoke "check" (i32.const 21)) "uninitialized element")
+(assert_trap (invoke "check" (i32.const 22)) "uninitialized element")
+(assert_trap (invoke "check" (i32.const 23)) "uninitialized element")
+(assert_trap (invoke "check" (i32.const 24)) "uninitialized element")
+(assert_trap (invoke "check" (i32.const 25)) "uninitialized element")
+(assert_trap (invoke "check" (i32.const 26)) "uninitialized element")
+(assert_trap (invoke "check" (i32.const 27)) "uninitialized element")
+(assert_trap (invoke "check" (i32.const 28)) "uninitialized element")
+(assert_trap (invoke "check" (i32.const 29)) "uninitialized element")
+
+(module
+  (type (func (result i32)))  ;; type #0
+  (import "a" "ef0" (func (result i32)))    ;; index 0
+  (import "a" "ef1" (func (result i32)))
+  (import "a" "ef2" (func (result i32)))
+  (import "a" "ef3" (func (result i32)))
+  (import "a" "ef4" (func (result i32)))    ;; index 4
+  (table 30 30 funcref)
+  (elem (i32.const 2) 3 1 4 1)
+  (elem passive 2 7 1 8)
+  (elem (i32.const 12) 7 5 2 3 6)
+  (elem passive 5 9 2 7 6)
+  (func (result i32) (i32.const 5))  ;; index 5
+  (func (result i32) (i32.const 6))
+  (func (result i32) (i32.const 7))
+  (func (result i32) (i32.const 8))
+  (func (result i32) (i32.const 9))  ;; index 9
+  (func (export "test")
+    (table.copy (i32.const 13) (i32.const 2) (i32.const 3)))
+  (func (export "check") (param i32) (result i32)
+    (call_indirect (type 0) (local.get 0)))
+)
+
+(invoke "test")
+(assert_trap (invoke "check" (i32.const 0)) "uninitialized element")
+(assert_trap (invoke "check" (i32.const 1)) "uninitialized element")
+(assert_return (invoke "check" (i32.const 2)) (i32.const 3))
+(assert_return (invoke "check" (i32.const 3)) (i32.const 1))
+(assert_return (invoke "check" (i32.const 4)) (i32.const 4))
+(assert_return (invoke "check" (i32.const 5)) (i32.const 1))
+(assert_trap (invoke "check" (i32.const 6)) "uninitialized element")
+(assert_trap (invoke "check" (i32.const 7)) "uninitialized element")
+(assert_trap (invoke "check" (i32.const 8)) "uninitialized element")
+(assert_trap (invoke "check" (i32.const 9)) "uninitialized element")
+(assert_trap (invoke "check" (i32.const 10)) "uninitialized element")
+(assert_trap (invoke "check" (i32.const 11)) "uninitialized element")
+(assert_return (invoke "check" (i32.const 12)) (i32.const 7))
+(assert_return (invoke "check" (i32.const 13)) (i32.const 3))
+(assert_return (invoke "check" (i32.const 14)) (i32.const 1))
+(assert_return (invoke "check" (i32.const 15)) (i32.const 4))
+(assert_return (invoke "check" (i32.const 16)) (i32.const 6))
+(assert_trap (invoke "check" (i32.const 17)) "uninitialized element")
+(assert_trap (invoke "check" (i32.const 18)) "uninitialized element")
+(assert_trap (invoke "check" (i32.const 19)) "uninitialized element")
+(assert_trap (invoke "check" (i32.const 20)) "uninitialized element")
+(assert_trap (invoke "check" (i32.const 21)) "uninitialized element")
+(assert_trap (invoke "check" (i32.const 22)) "uninitialized element")
+(assert_trap (invoke "check" (i32.const 23)) "uninitialized element")
+(assert_trap (invoke "check" (i32.const 24)) "uninitialized element")
+(assert_trap (invoke "check" (i32.const 25)) "uninitialized element")
+(assert_trap (invoke "check" (i32.const 26)) "uninitialized element")
+(assert_trap (invoke "check" (i32.const 27)) "uninitialized element")
+(assert_trap (invoke "check" (i32.const 28)) "uninitialized element")
+(assert_trap (invoke "check" (i32.const 29)) "uninitialized element")
+
+(module
+  (type (func (result i32)))  ;; type #0
+  (import "a" "ef0" (func (result i32)))    ;; index 0
+  (import "a" "ef1" (func (result i32)))
+  (import "a" "ef2" (func (result i32)))
+  (import "a" "ef3" (func (result i32)))
+  (import "a" "ef4" (func (result i32)))    ;; index 4
+  (table 30 30 funcref)
+  (elem (i32.const 2) 3 1 4 1)
+  (elem passive 2 7 1 8)
+  (elem (i32.const 12) 7 5 2 3 6)
+  (elem passive 5 9 2 7 6)
+  (func (result i32) (i32.const 5))  ;; index 5
+  (func (result i32) (i32.const 6))
+  (func (result i32) (i32.const 7))
+  (func (result i32) (i32.const 8))
+  (func (result i32) (i32.const 9))  ;; index 9
+  (func (export "test")
+    (table.copy (i32.const 25) (i32.const 15) (i32.const 2)))
+  (func (export "check") (param i32) (result i32)
+    (call_indirect (type 0) (local.get 0)))
+)
+
+(invoke "test")
+(assert_trap (invoke "check" (i32.const 0)) "uninitialized element")
+(assert_trap (invoke "check" (i32.const 1)) "uninitialized element")
+(assert_return (invoke "check" (i32.const 2)) (i32.const 3))
+(assert_return (invoke "check" (i32.const 3)) (i32.const 1))
+(assert_return (invoke "check" (i32.const 4)) (i32.const 4))
+(assert_return (invoke "check" (i32.const 5)) (i32.const 1))
+(assert_trap (invoke "check" (i32.const 6)) "uninitialized element")
+(assert_trap (invoke "check" (i32.const 7)) "uninitialized element")
+(assert_trap (invoke "check" (i32.const 8)) "uninitialized element")
+(assert_trap (invoke "check" (i32.const 9)) "uninitialized element")
+(assert_trap (invoke "check" (i32.const 10)) "uninitialized element")
+(assert_trap (invoke "check" (i32.const 11)) "uninitialized element")
+(assert_return (invoke "check" (i32.const 12)) (i32.const 7))
+(assert_return (invoke "check" (i32.const 13)) (i32.const 5))
+(assert_return (invoke "check" (i32.const 14)) (i32.const 2))
+(assert_return (invoke "check" (i32.const 15)) (i32.const 3))
+(assert_return (invoke "check" (i32.const 16)) (i32.const 6))
+(assert_trap (invoke "check" (i32.const 17)) "uninitialized element")
+(assert_trap (invoke "check" (i32.const 18)) "uninitialized element")
+(assert_trap (invoke "check" (i32.const 19)) "uninitialized element")
+(assert_trap (invoke "check" (i32.const 20)) "uninitialized element")
+(assert_trap (invoke "check" (i32.const 21)) "uninitialized element")
+(assert_trap (invoke "check" (i32.const 22)) "uninitialized element")
+(assert_trap (invoke "check" (i32.const 23)) "uninitialized element")
+(assert_trap (invoke "check" (i32.const 24)) "uninitialized element")
+(assert_return (invoke "check" (i32.const 25)) (i32.const 3))
+(assert_return (invoke "check" (i32.const 26)) (i32.const 6))
+(assert_trap (invoke "check" (i32.const 27)) "uninitialized element")
+(assert_trap (invoke "check" (i32.const 28)) "uninitialized element")
+(assert_trap (invoke "check" (i32.const 29)) "uninitialized element")
+
+(module
+  (type (func (result i32)))  ;; type #0
+  (import "a" "ef0" (func (result i32)))    ;; index 0
+  (import "a" "ef1" (func (result i32)))
+  (import "a" "ef2" (func (result i32)))
+  (import "a" "ef3" (func (result i32)))
+  (import "a" "ef4" (func (result i32)))    ;; index 4
+  (table 30 30 funcref)
+  (elem (i32.const 2) 3 1 4 1)
+  (elem passive 2 7 1 8)
+  (elem (i32.const 12) 7 5 2 3 6)
+  (elem passive 5 9 2 7 6)
+  (func (result i32) (i32.const 5))  ;; index 5
+  (func (result i32) (i32.const 6))
+  (func (result i32) (i32.const 7))
+  (func (result i32) (i32.const 8))
+  (func (result i32) (i32.const 9))  ;; index 9
+  (func (export "test")
+    (table.copy (i32.const 13) (i32.const 25) (i32.const 3)))
+  (func (export "check") (param i32) (result i32)
+    (call_indirect (type 0) (local.get 0)))
+)
+
+(invoke "test")
+(assert_trap (invoke "check" (i32.const 0)) "uninitialized element")
+(assert_trap (invoke "check" (i32.const 1)) "uninitialized element")
+(assert_return (invoke "check" (i32.const 2)) (i32.const 3))
+(assert_return (invoke "check" (i32.const 3)) (i32.const 1))
+(assert_return (invoke "check" (i32.const 4)) (i32.const 4))
+(assert_return (invoke "check" (i32.const 5)) (i32.const 1))
+(assert_trap (invoke "check" (i32.const 6)) "uninitialized element")
+(assert_trap (invoke "check" (i32.const 7)) "uninitialized element")
+(assert_trap (invoke "check" (i32.const 8)) "uninitialized element")
+(assert_trap (invoke "check" (i32.const 9)) "uninitialized element")
+(assert_trap (invoke "check" (i32.const 10)) "uninitialized element")
+(assert_trap (invoke "check" (i32.const 11)) "uninitialized element")
+(assert_return (invoke "check" (i32.const 12)) (i32.const 7))
+(assert_trap (invoke "check" (i32.const 13)) "uninitialized element")
+(assert_trap (invoke "check" (i32.const 14)) "uninitialized element")
+(assert_trap (invoke "check" (i32.const 15)) "uninitialized element")
+(assert_return (invoke "check" (i32.const 16)) (i32.const 6))
+(assert_trap (invoke "check" (i32.const 17)) "uninitialized element")
+(assert_trap (invoke "check" (i32.const 18)) "uninitialized element")
+(assert_trap (invoke "check" (i32.const 19)) "uninitialized element")
+(assert_trap (invoke "check" (i32.const 20)) "uninitialized element")
+(assert_trap (invoke "check" (i32.const 21)) "uninitialized element")
+(assert_trap (invoke "check" (i32.const 22)) "uninitialized element")
+(assert_trap (invoke "check" (i32.const 23)) "uninitialized element")
+(assert_trap (invoke "check" (i32.const 24)) "uninitialized element")
+(assert_trap (invoke "check" (i32.const 25)) "uninitialized element")
+(assert_trap (invoke "check" (i32.const 26)) "uninitialized element")
+(assert_trap (invoke "check" (i32.const 27)) "uninitialized element")
+(assert_trap (invoke "check" (i32.const 28)) "uninitialized element")
+(assert_trap (invoke "check" (i32.const 29)) "uninitialized element")
+
+(module
+  (type (func (result i32)))  ;; type #0
+  (import "a" "ef0" (func (result i32)))    ;; index 0
+  (import "a" "ef1" (func (result i32)))
+  (import "a" "ef2" (func (result i32)))
+  (import "a" "ef3" (func (result i32)))
+  (import "a" "ef4" (func (result i32)))    ;; index 4
+  (table 30 30 funcref)
+  (elem (i32.const 2) 3 1 4 1)
+  (elem passive 2 7 1 8)
+  (elem (i32.const 12) 7 5 2 3 6)
+  (elem passive 5 9 2 7 6)
+  (func (result i32) (i32.const 5))  ;; index 5
+  (func (result i32) (i32.const 6))
+  (func (result i32) (i32.const 7))
+  (func (result i32) (i32.const 8))
+  (func (result i32) (i32.const 9))  ;; index 9
+  (func (export "test")
+    (table.copy (i32.const 20) (i32.const 22) (i32.const 4)))
+  (func (export "check") (param i32) (result i32)
+    (call_indirect (type 0) (local.get 0)))
+)
+
+(invoke "test")
+(assert_trap (invoke "check" (i32.const 0)) "uninitialized element")
+(assert_trap (invoke "check" (i32.const 1)) "uninitialized element")
+(assert_return (invoke "check" (i32.const 2)) (i32.const 3))
+(assert_return (invoke "check" (i32.const 3)) (i32.const 1))
+(assert_return (invoke "check" (i32.const 4)) (i32.const 4))
+(assert_return (invoke "check" (i32.const 5)) (i32.const 1))
+(assert_trap (invoke "check" (i32.const 6)) "uninitialized element")
+(assert_trap (invoke "check" (i32.const 7)) "uninitialized element")
+(assert_trap (invoke "check" (i32.const 8)) "uninitialized element")
+(assert_trap (invoke "check" (i32.const 9)) "uninitialized element")
+(assert_trap (invoke "check" (i32.const 10)) "uninitialized element")
+(assert_trap (invoke "check" (i32.const 11)) "uninitialized element")
+(assert_return (invoke "check" (i32.const 12)) (i32.const 7))
+(assert_return (invoke "check" (i32.const 13)) (i32.const 5))
+(assert_return (invoke "check" (i32.const 14)) (i32.const 2))
+(assert_return (invoke "check" (i32.const 15)) (i32.const 3))
+(assert_return (invoke "check" (i32.const 16)) (i32.const 6))
+(assert_trap (invoke "check" (i32.const 17)) "uninitialized element")
+(assert_trap (invoke "check" (i32.const 18)) "uninitialized element")
+(assert_trap (invoke "check" (i32.const 19)) "uninitialized element")
+(assert_trap (invoke "check" (i32.const 20)) "uninitialized element")
+(assert_trap (invoke "check" (i32.const 21)) "uninitialized element")
+(assert_trap (invoke "check" (i32.const 22)) "uninitialized element")
+(assert_trap (invoke "check" (i32.const 23)) "uninitialized element")
+(assert_trap (invoke "check" (i32.const 24)) "uninitialized element")
+(assert_trap (invoke "check" (i32.const 25)) "uninitialized element")
+(assert_trap (invoke "check" (i32.const 26)) "uninitialized element")
+(assert_trap (invoke "check" (i32.const 27)) "uninitialized element")
+(assert_trap (invoke "check" (i32.const 28)) "uninitialized element")
+(assert_trap (invoke "check" (i32.const 29)) "uninitialized element")
+
+(module
+  (type (func (result i32)))  ;; type #0
+  (import "a" "ef0" (func (result i32)))    ;; index 0
+  (import "a" "ef1" (func (result i32)))
+  (import "a" "ef2" (func (result i32)))
+  (import "a" "ef3" (func (result i32)))
+  (import "a" "ef4" (func (result i32)))    ;; index 4
+  (table 30 30 funcref)
+  (elem (i32.const 2) 3 1 4 1)
+  (elem passive 2 7 1 8)
+  (elem (i32.const 12) 7 5 2 3 6)
+  (elem passive 5 9 2 7 6)
+  (func (result i32) (i32.const 5))  ;; index 5
+  (func (result i32) (i32.const 6))
+  (func (result i32) (i32.const 7))
+  (func (result i32) (i32.const 8))
+  (func (result i32) (i32.const 9))  ;; index 9
+  (func (export "test")
+    (table.copy (i32.const 25) (i32.const 1) (i32.const 3)))
+  (func (export "check") (param i32) (result i32)
+    (call_indirect (type 0) (local.get 0)))
+)
+
+(invoke "test")
+(assert_trap (invoke "check" (i32.const 0)) "uninitialized element")
+(assert_trap (invoke "check" (i32.const 1)) "uninitialized element")
+(assert_return (invoke "check" (i32.const 2)) (i32.const 3))
+(assert_return (invoke "check" (i32.const 3)) (i32.const 1))
+(assert_return (invoke "check" (i32.const 4)) (i32.const 4))
+(assert_return (invoke "check" (i32.const 5)) (i32.const 1))
+(assert_trap (invoke "check" (i32.const 6)) "uninitialized element")
+(assert_trap (invoke "check" (i32.const 7)) "uninitialized element")
+(assert_trap (invoke "check" (i32.const 8)) "uninitialized element")
+(assert_trap (invoke "check" (i32.const 9)) "uninitialized element")
+(assert_trap (invoke "check" (i32.const 10)) "uninitialized element")
+(assert_trap (invoke "check" (i32.const 11)) "uninitialized element")
+(assert_return (invoke "check" (i32.const 12)) (i32.const 7))
+(assert_return (invoke "check" (i32.const 13)) (i32.const 5))
+(assert_return (invoke "check" (i32.const 14)) (i32.const 2))
+(assert_return (invoke "check" (i32.const 15)) (i32.const 3))
+(assert_return (invoke "check" (i32.const 16)) (i32.const 6))
+(assert_trap (invoke "check" (i32.const 17)) "uninitialized element")
+(assert_trap (invoke "check" (i32.const 18)) "uninitialized element")
+(assert_trap (invoke "check" (i32.const 19)) "uninitialized element")
+(assert_trap (invoke "check" (i32.const 20)) "uninitialized element")
+(assert_trap (invoke "check" (i32.const 21)) "uninitialized element")
+(assert_trap (invoke "check" (i32.const 22)) "uninitialized element")
+(assert_trap (invoke "check" (i32.const 23)) "uninitialized element")
+(assert_trap (invoke "check" (i32.const 24)) "uninitialized element")
+(assert_trap (invoke "check" (i32.const 25)) "uninitialized element")
+(assert_return (invoke "check" (i32.const 26)) (i32.const 3))
+(assert_return (invoke "check" (i32.const 27)) (i32.const 1))
+(assert_trap (invoke "check" (i32.const 28)) "uninitialized element")
+(assert_trap (invoke "check" (i32.const 29)) "uninitialized element")
+
+(module
+  (type (func (result i32)))  ;; type #0
+  (import "a" "ef0" (func (result i32)))    ;; index 0
+  (import "a" "ef1" (func (result i32)))
+  (import "a" "ef2" (func (result i32)))
+  (import "a" "ef3" (func (result i32)))
+  (import "a" "ef4" (func (result i32)))    ;; index 4
+  (table 30 30 funcref)
+  (elem (i32.const 2) 3 1 4 1)
+  (elem passive 2 7 1 8)
+  (elem (i32.const 12) 7 5 2 3 6)
+  (elem passive 5 9 2 7 6)
+  (func (result i32) (i32.const 5))  ;; index 5
+  (func (result i32) (i32.const 6))
+  (func (result i32) (i32.const 7))
+  (func (result i32) (i32.const 8))
+  (func (result i32) (i32.const 9))  ;; index 9
+  (func (export "test")
+    (table.copy (i32.const 10) (i32.const 12) (i32.const 7)))
+  (func (export "check") (param i32) (result i32)
+    (call_indirect (type 0) (local.get 0)))
+)
+
+(invoke "test")
+(assert_trap (invoke "check" (i32.const 0)) "uninitialized element")
+(assert_trap (invoke "check" (i32.const 1)) "uninitialized element")
+(assert_return (invoke "check" (i32.const 2)) (i32.const 3))
+(assert_return (invoke "check" (i32.const 3)) (i32.const 1))
+(assert_return (invoke "check" (i32.const 4)) (i32.const 4))
+(assert_return (invoke "check" (i32.const 5)) (i32.const 1))
+(assert_trap (invoke "check" (i32.const 6)) "uninitialized element")
+(assert_trap (invoke "check" (i32.const 7)) "uninitialized element")
+(assert_trap (invoke "check" (i32.const 8)) "uninitialized element")
+(assert_trap (invoke "check" (i32.const 9)) "uninitialized element")
+(assert_return (invoke "check" (i32.const 10)) (i32.const 7))
+(assert_return (invoke "check" (i32.const 11)) (i32.const 5))
+(assert_return (invoke "check" (i32.const 12)) (i32.const 2))
+(assert_return (invoke "check" (i32.const 13)) (i32.const 3))
+(assert_return (invoke "check" (i32.const 14)) (i32.const 6))
+(assert_trap (invoke "check" (i32.const 15)) "uninitialized element")
+(assert_trap (invoke "check" (i32.const 16)) "uninitialized element")
+(assert_trap (invoke "check" (i32.const 17)) "uninitialized element")
+(assert_trap (invoke "check" (i32.const 18)) "uninitialized element")
+(assert_trap (invoke "check" (i32.const 19)) "uninitialized element")
+(assert_trap (invoke "check" (i32.const 20)) "uninitialized element")
+(assert_trap (invoke "check" (i32.const 21)) "uninitialized element")
+(assert_trap (invoke "check" (i32.const 22)) "uninitialized element")
+(assert_trap (invoke "check" (i32.const 23)) "uninitialized element")
+(assert_trap (invoke "check" (i32.const 24)) "uninitialized element")
+(assert_trap (invoke "check" (i32.const 25)) "uninitialized element")
+(assert_trap (invoke "check" (i32.const 26)) "uninitialized element")
+(assert_trap (invoke "check" (i32.const 27)) "uninitialized element")
+(assert_trap (invoke "check" (i32.const 28)) "uninitialized element")
+(assert_trap (invoke "check" (i32.const 29)) "uninitialized element")
+
+(module
+  (type (func (result i32)))  ;; type #0
+  (import "a" "ef0" (func (result i32)))    ;; index 0
+  (import "a" "ef1" (func (result i32)))
+  (import "a" "ef2" (func (result i32)))
+  (import "a" "ef3" (func (result i32)))
+  (import "a" "ef4" (func (result i32)))    ;; index 4
+  (table 30 30 funcref)
+  (elem (i32.const 2) 3 1 4 1)
+  (elem passive 2 7 1 8)
+  (elem (i32.const 12) 7 5 2 3 6)
+  (elem passive 5 9 2 7 6)
+  (func (result i32) (i32.const 5))  ;; index 5
+  (func (result i32) (i32.const 6))
+  (func (result i32) (i32.const 7))
+  (func (result i32) (i32.const 8))
+  (func (result i32) (i32.const 9))  ;; index 9
+  (func (export "test")
+    (table.copy (i32.const 12) (i32.const 10) (i32.const 7)))
+  (func (export "check") (param i32) (result i32)
+    (call_indirect (type 0) (local.get 0)))
+)
+
+(invoke "test")
+(assert_trap (invoke "check" (i32.const 0)) "uninitialized element")
+(assert_trap (invoke "check" (i32.const 1)) "uninitialized element")
+(assert_return (invoke "check" (i32.const 2)) (i32.const 3))
+(assert_return (invoke "check" (i32.const 3)) (i32.const 1))
+(assert_return (invoke "check" (i32.const 4)) (i32.const 4))
+(assert_return (invoke "check" (i32.const 5)) (i32.const 1))
+(assert_trap (invoke "check" (i32.const 6)) "uninitialized element")
+(assert_trap (invoke "check" (i32.const 7)) "uninitialized element")
+(assert_trap (invoke "check" (i32.const 8)) "uninitialized element")
+(assert_trap (invoke "check" (i32.const 9)) "uninitialized element")
+(assert_trap (invoke "check" (i32.const 10)) "uninitialized element")
+(assert_trap (invoke "check" (i32.const 11)) "uninitialized element")
+(assert_trap (invoke "check" (i32.const 12)) "uninitialized element")
+(assert_trap (invoke "check" (i32.const 13)) "uninitialized element")
+(assert_return (invoke "check" (i32.const 14)) (i32.const 7))
+(assert_return (invoke "check" (i32.const 15)) (i32.const 5))
+(assert_return (invoke "check" (i32.const 16)) (i32.const 2))
+(assert_return (invoke "check" (i32.const 17)) (i32.const 3))
+(assert_return (invoke "check" (i32.const 18)) (i32.const 6))
+(assert_trap (invoke "check" (i32.const 19)) "uninitialized element")
+(assert_trap (invoke "check" (i32.const 20)) "uninitialized element")
+(assert_trap (invoke "check" (i32.const 21)) "uninitialized element")
+(assert_trap (invoke "check" (i32.const 22)) "uninitialized element")
+(assert_trap (invoke "check" (i32.const 23)) "uninitialized element")
+(assert_trap (invoke "check" (i32.const 24)) "uninitialized element")
+(assert_trap (invoke "check" (i32.const 25)) "uninitialized element")
+(assert_trap (invoke "check" (i32.const 26)) "uninitialized element")
+(assert_trap (invoke "check" (i32.const 27)) "uninitialized element")
+(assert_trap (invoke "check" (i32.const 28)) "uninitialized element")
+(assert_trap (invoke "check" (i32.const 29)) "uninitialized element")
+
+(module
+  (table 30 30 funcref)
+  (elem (i32.const 2) 3 1 4 1)
+  (elem passive 2 7 1 8)
+  (elem (i32.const 12) 7 5 2 3 6)
+  (elem passive 5 9 2 7 6)
+  (func (result i32) (i32.const 0))
+  (func (result i32) (i32.const 1))
+  (func (result i32) (i32.const 2))
+  (func (result i32) (i32.const 3))
+  (func (result i32) (i32.const 4))
+  (func (result i32) (i32.const 5))
+  (func (result i32) (i32.const 6))
+  (func (result i32) (i32.const 7))
+  (func (result i32) (i32.const 8))
+  (func (result i32) (i32.const 9))
+  (func (export "test")
+    (table.copy (i32.const 28) (i32.const 1) (i32.const 3))
+    ))
+
+(assert_trap (invoke "test") "out of bounds")
+
+(module
+  (table 30 30 funcref)
+  (elem (i32.const 2) 3 1 4 1)
+  (elem passive 2 7 1 8)
+  (elem (i32.const 12) 7 5 2 3 6)
+  (elem passive 5 9 2 7 6)
+  (func (result i32) (i32.const 0))
+  (func (result i32) (i32.const 1))
+  (func (result i32) (i32.const 2))
+  (func (result i32) (i32.const 3))
+  (func (result i32) (i32.const 4))
+  (func (result i32) (i32.const 5))
+  (func (result i32) (i32.const 6))
+  (func (result i32) (i32.const 7))
+  (func (result i32) (i32.const 8))
+  (func (result i32) (i32.const 9))
+  (func (export "test")
+    (table.copy (i32.const 0xFFFFFFFE) (i32.const 1) (i32.const 2))
+    ))
+
+(assert_trap (invoke "test") "out of bounds")
+
+(module
+  (table 30 30 funcref)
+  (elem (i32.const 2) 3 1 4 1)
+  (elem passive 2 7 1 8)
+  (elem (i32.const 12) 7 5 2 3 6)
+  (elem passive 5 9 2 7 6)
+  (func (result i32) (i32.const 0))
+  (func (result i32) (i32.const 1))
+  (func (result i32) (i32.const 2))
+  (func (result i32) (i32.const 3))
+  (func (result i32) (i32.const 4))
+  (func (result i32) (i32.const 5))
+  (func (result i32) (i32.const 6))
+  (func (result i32) (i32.const 7))
+  (func (result i32) (i32.const 8))
+  (func (result i32) (i32.const 9))
+  (func (export "test")
+    (table.copy (i32.const 15) (i32.const 25) (i32.const 6))
+    ))
+
+(assert_trap (invoke "test") "out of bounds")
+
+(module
+  (table 30 30 funcref)
+  (elem (i32.const 2) 3 1 4 1)
+  (elem passive 2 7 1 8)
+  (elem (i32.const 12) 7 5 2 3 6)
+  (elem passive 5 9 2 7 6)
+  (func (result i32) (i32.const 0))
+  (func (result i32) (i32.const 1))
+  (func (result i32) (i32.const 2))
+  (func (result i32) (i32.const 3))
+  (func (result i32) (i32.const 4))
+  (func (result i32) (i32.const 5))
+  (func (result i32) (i32.const 6))
+  (func (result i32) (i32.const 7))
+  (func (result i32) (i32.const 8))
+  (func (result i32) (i32.const 9))
+  (func (export "test")
+    (table.copy (i32.const 15) (i32.const 0xFFFFFFFE) (i32.const 2))
+    ))
+
+(assert_trap (invoke "test") "out of bounds")
+
+(module
+  (table 30 30 funcref)
+  (elem (i32.const 2) 3 1 4 1)
+  (elem passive 2 7 1 8)
+  (elem (i32.const 12) 7 5 2 3 6)
+  (elem passive 5 9 2 7 6)
+  (func (result i32) (i32.const 0))
+  (func (result i32) (i32.const 1))
+  (func (result i32) (i32.const 2))
+  (func (result i32) (i32.const 3))
+  (func (result i32) (i32.const 4))
+  (func (result i32) (i32.const 5))
+  (func (result i32) (i32.const 6))
+  (func (result i32) (i32.const 7))
+  (func (result i32) (i32.const 8))
+  (func (result i32) (i32.const 9))
+  (func (export "test")
+    (table.copy (i32.const 15) (i32.const 25) (i32.const 0))
+    ))
+
+(invoke "test")
+
+(module
+  (table 30 30 funcref)
+  (elem (i32.const 2) 3 1 4 1)
+  (elem passive 2 7 1 8)
+  (elem (i32.const 12) 7 5 2 3 6)
+  (elem passive 5 9 2 7 6)
+  (func (result i32) (i32.const 0))
+  (func (result i32) (i32.const 1))
+  (func (result i32) (i32.const 2))
+  (func (result i32) (i32.const 3))
+  (func (result i32) (i32.const 4))
+  (func (result i32) (i32.const 5))
+  (func (result i32) (i32.const 6))
+  (func (result i32) (i32.const 7))
+  (func (result i32) (i32.const 8))
+  (func (result i32) (i32.const 9))
+  (func (export "test")
+    (table.copy (i32.const 30) (i32.const 15) (i32.const 0))
+    ))
+
+(invoke "test")
+
+(module
+  (table 30 30 funcref)
+  (elem (i32.const 2) 3 1 4 1)
+  (elem passive 2 7 1 8)
+  (elem (i32.const 12) 7 5 2 3 6)
+  (elem passive 5 9 2 7 6)
+  (func (result i32) (i32.const 0))
+  (func (result i32) (i32.const 1))
+  (func (result i32) (i32.const 2))
+  (func (result i32) (i32.const 3))
+  (func (result i32) (i32.const 4))
+  (func (result i32) (i32.const 5))
+  (func (result i32) (i32.const 6))
+  (func (result i32) (i32.const 7))
+  (func (result i32) (i32.const 8))
+  (func (result i32) (i32.const 9))
+  (func (export "test")
+    (table.copy (i32.const 15) (i32.const 30) (i32.const 0))
+    ))
+
+(invoke "test")
+(module
+           (type (func (result i32)))
+           (table 32 64 funcref)
+           (elem (i32.const 0)
+                  $f0 $f1 $f2 $f3 $f4 $f5 $f6 $f7)
+           (func $f0 (export "f0") (result i32) (i32.const 0))
+           (func $f1 (export "f1") (result i32) (i32.const 1))
+           (func $f2 (export "f2") (result i32) (i32.const 2))
+           (func $f3 (export "f3") (result i32) (i32.const 3))
+           (func $f4 (export "f4") (result i32) (i32.const 4))
+           (func $f5 (export "f5") (result i32) (i32.const 5))
+           (func $f6 (export "f6") (result i32) (i32.const 6))
+           (func $f7 (export "f7") (result i32) (i32.const 7))
+           (func $f8 (export "f8") (result i32) (i32.const 8))
+           (func $f9 (export "f9") (result i32) (i32.const 9))
+           (func $f10 (export "f10") (result i32) (i32.const 10))
+           (func $f11 (export "f11") (result i32) (i32.const 11))
+           (func $f12 (export "f12") (result i32) (i32.const 12))
+           (func $f13 (export "f13") (result i32) (i32.const 13))
+           (func $f14 (export "f14") (result i32) (i32.const 14))
+           (func $f15 (export "f15") (result i32) (i32.const 15))
+           (func (export "test") (param $n i32) (result i32)
+             (call_indirect (type 0) (local.get $n)))
+           (func (export "run") (param $targetOffs i32) (param $srcOffs i32) (param $len i32)
+             (table.copy (local.get $targetOffs) (local.get $srcOffs) (local.get $len))))
+(assert_trap (invoke "run" (i32.const 24) (i32.const 0) (i32.const 16))
+                        "out of bounds")
+(assert_return (invoke "test" (i32.const 0)) (i32.const 0))
+(assert_return (invoke "test" (i32.const 1)) (i32.const 1))
+(assert_return (invoke "test" (i32.const 2)) (i32.const 2))
+(assert_return (invoke "test" (i32.const 3)) (i32.const 3))
+(assert_return (invoke "test" (i32.const 4)) (i32.const 4))
+(assert_return (invoke "test" (i32.const 5)) (i32.const 5))
+(assert_return (invoke "test" (i32.const 6)) (i32.const 6))
+(assert_return (invoke "test" (i32.const 7)) (i32.const 7))
+(assert_trap (invoke "test" (i32.const 8)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 9)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 10)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 11)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 12)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 13)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 14)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 15)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 16)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 17)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 18)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 19)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 20)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 21)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 22)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 23)) "uninitialized element")
+(assert_return (invoke "test" (i32.const 24)) (i32.const 0))
+(assert_return (invoke "test" (i32.const 25)) (i32.const 1))
+(assert_return (invoke "test" (i32.const 26)) (i32.const 2))
+(assert_return (invoke "test" (i32.const 27)) (i32.const 3))
+(assert_return (invoke "test" (i32.const 28)) (i32.const 4))
+(assert_return (invoke "test" (i32.const 29)) (i32.const 5))
+(assert_return (invoke "test" (i32.const 30)) (i32.const 6))
+(assert_return (invoke "test" (i32.const 31)) (i32.const 7))
+(module
+           (type (func (result i32)))
+           (table 32 64 funcref)
+           (elem (i32.const 0)
+                  $f0 $f1 $f2 $f3 $f4 $f5 $f6 $f7 $f8)
+           (func $f0 (export "f0") (result i32) (i32.const 0))
+           (func $f1 (export "f1") (result i32) (i32.const 1))
+           (func $f2 (export "f2") (result i32) (i32.const 2))
+           (func $f3 (export "f3") (result i32) (i32.const 3))
+           (func $f4 (export "f4") (result i32) (i32.const 4))
+           (func $f5 (export "f5") (result i32) (i32.const 5))
+           (func $f6 (export "f6") (result i32) (i32.const 6))
+           (func $f7 (export "f7") (result i32) (i32.const 7))
+           (func $f8 (export "f8") (result i32) (i32.const 8))
+           (func $f9 (export "f9") (result i32) (i32.const 9))
+           (func $f10 (export "f10") (result i32) (i32.const 10))
+           (func $f11 (export "f11") (result i32) (i32.const 11))
+           (func $f12 (export "f12") (result i32) (i32.const 12))
+           (func $f13 (export "f13") (result i32) (i32.const 13))
+           (func $f14 (export "f14") (result i32) (i32.const 14))
+           (func $f15 (export "f15") (result i32) (i32.const 15))
+           (func (export "test") (param $n i32) (result i32)
+             (call_indirect (type 0) (local.get $n)))
+           (func (export "run") (param $targetOffs i32) (param $srcOffs i32) (param $len i32)
+             (table.copy (local.get $targetOffs) (local.get $srcOffs) (local.get $len))))
+(assert_trap (invoke "run" (i32.const 23) (i32.const 0) (i32.const 15))
+                        "out of bounds")
+(assert_return (invoke "test" (i32.const 0)) (i32.const 0))
+(assert_return (invoke "test" (i32.const 1)) (i32.const 1))
+(assert_return (invoke "test" (i32.const 2)) (i32.const 2))
+(assert_return (invoke "test" (i32.const 3)) (i32.const 3))
+(assert_return (invoke "test" (i32.const 4)) (i32.const 4))
+(assert_return (invoke "test" (i32.const 5)) (i32.const 5))
+(assert_return (invoke "test" (i32.const 6)) (i32.const 6))
+(assert_return (invoke "test" (i32.const 7)) (i32.const 7))
+(assert_return (invoke "test" (i32.const 8)) (i32.const 8))
+(assert_trap (invoke "test" (i32.const 9)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 10)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 11)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 12)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 13)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 14)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 15)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 16)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 17)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 18)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 19)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 20)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 21)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 22)) "uninitialized element")
+(assert_return (invoke "test" (i32.const 23)) (i32.const 0))
+(assert_return (invoke "test" (i32.const 24)) (i32.const 1))
+(assert_return (invoke "test" (i32.const 25)) (i32.const 2))
+(assert_return (invoke "test" (i32.const 26)) (i32.const 3))
+(assert_return (invoke "test" (i32.const 27)) (i32.const 4))
+(assert_return (invoke "test" (i32.const 28)) (i32.const 5))
+(assert_return (invoke "test" (i32.const 29)) (i32.const 6))
+(assert_return (invoke "test" (i32.const 30)) (i32.const 7))
+(assert_return (invoke "test" (i32.const 31)) (i32.const 8))
+(module
+           (type (func (result i32)))
+           (table 32 64 funcref)
+           (elem (i32.const 24)
+                  $f0 $f1 $f2 $f3 $f4 $f5 $f6 $f7)
+           (func $f0 (export "f0") (result i32) (i32.const 0))
+           (func $f1 (export "f1") (result i32) (i32.const 1))
+           (func $f2 (export "f2") (result i32) (i32.const 2))
+           (func $f3 (export "f3") (result i32) (i32.const 3))
+           (func $f4 (export "f4") (result i32) (i32.const 4))
+           (func $f5 (export "f5") (result i32) (i32.const 5))
+           (func $f6 (export "f6") (result i32) (i32.const 6))
+           (func $f7 (export "f7") (result i32) (i32.const 7))
+           (func $f8 (export "f8") (result i32) (i32.const 8))
+           (func $f9 (export "f9") (result i32) (i32.const 9))
+           (func $f10 (export "f10") (result i32) (i32.const 10))
+           (func $f11 (export "f11") (result i32) (i32.const 11))
+           (func $f12 (export "f12") (result i32) (i32.const 12))
+           (func $f13 (export "f13") (result i32) (i32.const 13))
+           (func $f14 (export "f14") (result i32) (i32.const 14))
+           (func $f15 (export "f15") (result i32) (i32.const 15))
+           (func (export "test") (param $n i32) (result i32)
+             (call_indirect (type 0) (local.get $n)))
+           (func (export "run") (param $targetOffs i32) (param $srcOffs i32) (param $len i32)
+             (table.copy (local.get $targetOffs) (local.get $srcOffs) (local.get $len))))
+(assert_trap (invoke "run" (i32.const 0) (i32.const 24) (i32.const 16))
+                        "out of bounds")
+(assert_return (invoke "test" (i32.const 0)) (i32.const 0))
+(assert_return (invoke "test" (i32.const 1)) (i32.const 1))
+(assert_return (invoke "test" (i32.const 2)) (i32.const 2))
+(assert_return (invoke "test" (i32.const 3)) (i32.const 3))
+(assert_return (invoke "test" (i32.const 4)) (i32.const 4))
+(assert_return (invoke "test" (i32.const 5)) (i32.const 5))
+(assert_return (invoke "test" (i32.const 6)) (i32.const 6))
+(assert_return (invoke "test" (i32.const 7)) (i32.const 7))
+(assert_trap (invoke "test" (i32.const 8)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 9)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 10)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 11)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 12)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 13)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 14)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 15)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 16)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 17)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 18)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 19)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 20)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 21)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 22)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 23)) "uninitialized element")
+(assert_return (invoke "test" (i32.const 24)) (i32.const 0))
+(assert_return (invoke "test" (i32.const 25)) (i32.const 1))
+(assert_return (invoke "test" (i32.const 26)) (i32.const 2))
+(assert_return (invoke "test" (i32.const 27)) (i32.const 3))
+(assert_return (invoke "test" (i32.const 28)) (i32.const 4))
+(assert_return (invoke "test" (i32.const 29)) (i32.const 5))
+(assert_return (invoke "test" (i32.const 30)) (i32.const 6))
+(assert_return (invoke "test" (i32.const 31)) (i32.const 7))
+(module
+           (type (func (result i32)))
+           (table 32 64 funcref)
+           (elem (i32.const 23)
+                  $f0 $f1 $f2 $f3 $f4 $f5 $f6 $f7 $f8)
+           (func $f0 (export "f0") (result i32) (i32.const 0))
+           (func $f1 (export "f1") (result i32) (i32.const 1))
+           (func $f2 (export "f2") (result i32) (i32.const 2))
+           (func $f3 (export "f3") (result i32) (i32.const 3))
+           (func $f4 (export "f4") (result i32) (i32.const 4))
+           (func $f5 (export "f5") (result i32) (i32.const 5))
+           (func $f6 (export "f6") (result i32) (i32.const 6))
+           (func $f7 (export "f7") (result i32) (i32.const 7))
+           (func $f8 (export "f8") (result i32) (i32.const 8))
+           (func $f9 (export "f9") (result i32) (i32.const 9))
+           (func $f10 (export "f10") (result i32) (i32.const 10))
+           (func $f11 (export "f11") (result i32) (i32.const 11))
+           (func $f12 (export "f12") (result i32) (i32.const 12))
+           (func $f13 (export "f13") (result i32) (i32.const 13))
+           (func $f14 (export "f14") (result i32) (i32.const 14))
+           (func $f15 (export "f15") (result i32) (i32.const 15))
+           (func (export "test") (param $n i32) (result i32)
+             (call_indirect (type 0) (local.get $n)))
+           (func (export "run") (param $targetOffs i32) (param $srcOffs i32) (param $len i32)
+             (table.copy (local.get $targetOffs) (local.get $srcOffs) (local.get $len))))
+(assert_trap (invoke "run" (i32.const 0) (i32.const 23) (i32.const 15))
+                        "out of bounds")
+(assert_return (invoke "test" (i32.const 0)) (i32.const 0))
+(assert_return (invoke "test" (i32.const 1)) (i32.const 1))
+(assert_return (invoke "test" (i32.const 2)) (i32.const 2))
+(assert_return (invoke "test" (i32.const 3)) (i32.const 3))
+(assert_return (invoke "test" (i32.const 4)) (i32.const 4))
+(assert_return (invoke "test" (i32.const 5)) (i32.const 5))
+(assert_return (invoke "test" (i32.const 6)) (i32.const 6))
+(assert_return (invoke "test" (i32.const 7)) (i32.const 7))
+(assert_return (invoke "test" (i32.const 8)) (i32.const 8))
+(assert_trap (invoke "test" (i32.const 9)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 10)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 11)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 12)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 13)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 14)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 15)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 16)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 17)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 18)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 19)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 20)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 21)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 22)) "uninitialized element")
+(assert_return (invoke "test" (i32.const 23)) (i32.const 0))
+(assert_return (invoke "test" (i32.const 24)) (i32.const 1))
+(assert_return (invoke "test" (i32.const 25)) (i32.const 2))
+(assert_return (invoke "test" (i32.const 26)) (i32.const 3))
+(assert_return (invoke "test" (i32.const 27)) (i32.const 4))
+(assert_return (invoke "test" (i32.const 28)) (i32.const 5))
+(assert_return (invoke "test" (i32.const 29)) (i32.const 6))
+(assert_return (invoke "test" (i32.const 30)) (i32.const 7))
+(assert_return (invoke "test" (i32.const 31)) (i32.const 8))
+(module
+           (type (func (result i32)))
+           (table 32 64 funcref)
+           (elem (i32.const 11)
+                  $f0 $f1 $f2 $f3 $f4 $f5 $f6 $f7)
+           (func $f0 (export "f0") (result i32) (i32.const 0))
+           (func $f1 (export "f1") (result i32) (i32.const 1))
+           (func $f2 (export "f2") (result i32) (i32.const 2))
+           (func $f3 (export "f3") (result i32) (i32.const 3))
+           (func $f4 (export "f4") (result i32) (i32.const 4))
+           (func $f5 (export "f5") (result i32) (i32.const 5))
+           (func $f6 (export "f6") (result i32) (i32.const 6))
+           (func $f7 (export "f7") (result i32) (i32.const 7))
+           (func $f8 (export "f8") (result i32) (i32.const 8))
+           (func $f9 (export "f9") (result i32) (i32.const 9))
+           (func $f10 (export "f10") (result i32) (i32.const 10))
+           (func $f11 (export "f11") (result i32) (i32.const 11))
+           (func $f12 (export "f12") (result i32) (i32.const 12))
+           (func $f13 (export "f13") (result i32) (i32.const 13))
+           (func $f14 (export "f14") (result i32) (i32.const 14))
+           (func $f15 (export "f15") (result i32) (i32.const 15))
+           (func (export "test") (param $n i32) (result i32)
+             (call_indirect (type 0) (local.get $n)))
+           (func (export "run") (param $targetOffs i32) (param $srcOffs i32) (param $len i32)
+             (table.copy (local.get $targetOffs) (local.get $srcOffs) (local.get $len))))
+(assert_trap (invoke "run" (i32.const 24) (i32.const 11) (i32.const 16))
+                        "out of bounds")
+(assert_trap (invoke "test" (i32.const 0)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 1)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 2)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 3)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 4)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 5)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 6)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 7)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 8)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 9)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 10)) "uninitialized element")
+(assert_return (invoke "test" (i32.const 11)) (i32.const 0))
+(assert_return (invoke "test" (i32.const 12)) (i32.const 1))
+(assert_return (invoke "test" (i32.const 13)) (i32.const 2))
+(assert_return (invoke "test" (i32.const 14)) (i32.const 3))
+(assert_return (invoke "test" (i32.const 15)) (i32.const 4))
+(assert_return (invoke "test" (i32.const 16)) (i32.const 5))
+(assert_return (invoke "test" (i32.const 17)) (i32.const 6))
+(assert_return (invoke "test" (i32.const 18)) (i32.const 7))
+(assert_trap (invoke "test" (i32.const 19)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 20)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 21)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 22)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 23)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 24)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 25)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 26)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 27)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 28)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 29)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 30)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 31)) "uninitialized element")
+(module
+           (type (func (result i32)))
+           (table 32 64 funcref)
+           (elem (i32.const 24)
+                  $f0 $f1 $f2 $f3 $f4 $f5 $f6 $f7)
+           (func $f0 (export "f0") (result i32) (i32.const 0))
+           (func $f1 (export "f1") (result i32) (i32.const 1))
+           (func $f2 (export "f2") (result i32) (i32.const 2))
+           (func $f3 (export "f3") (result i32) (i32.const 3))
+           (func $f4 (export "f4") (result i32) (i32.const 4))
+           (func $f5 (export "f5") (result i32) (i32.const 5))
+           (func $f6 (export "f6") (result i32) (i32.const 6))
+           (func $f7 (export "f7") (result i32) (i32.const 7))
+           (func $f8 (export "f8") (result i32) (i32.const 8))
+           (func $f9 (export "f9") (result i32) (i32.const 9))
+           (func $f10 (export "f10") (result i32) (i32.const 10))
+           (func $f11 (export "f11") (result i32) (i32.const 11))
+           (func $f12 (export "f12") (result i32) (i32.const 12))
+           (func $f13 (export "f13") (result i32) (i32.const 13))
+           (func $f14 (export "f14") (result i32) (i32.const 14))
+           (func $f15 (export "f15") (result i32) (i32.const 15))
+           (func (export "test") (param $n i32) (result i32)
+             (call_indirect (type 0) (local.get $n)))
+           (func (export "run") (param $targetOffs i32) (param $srcOffs i32) (param $len i32)
+             (table.copy (local.get $targetOffs) (local.get $srcOffs) (local.get $len))))
+(assert_trap (invoke "run" (i32.const 11) (i32.const 24) (i32.const 16))
+                        "out of bounds")
+(assert_trap (invoke "test" (i32.const 0)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 1)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 2)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 3)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 4)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 5)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 6)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 7)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 8)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 9)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 10)) "uninitialized element")
+(assert_return (invoke "test" (i32.const 11)) (i32.const 0))
+(assert_return (invoke "test" (i32.const 12)) (i32.const 1))
+(assert_return (invoke "test" (i32.const 13)) (i32.const 2))
+(assert_return (invoke "test" (i32.const 14)) (i32.const 3))
+(assert_return (invoke "test" (i32.const 15)) (i32.const 4))
+(assert_return (invoke "test" (i32.const 16)) (i32.const 5))
+(assert_return (invoke "test" (i32.const 17)) (i32.const 6))
+(assert_return (invoke "test" (i32.const 18)) (i32.const 7))
+(assert_trap (invoke "test" (i32.const 19)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 20)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 21)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 22)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 23)) "uninitialized element")
+(assert_return (invoke "test" (i32.const 24)) (i32.const 0))
+(assert_return (invoke "test" (i32.const 25)) (i32.const 1))
+(assert_return (invoke "test" (i32.const 26)) (i32.const 2))
+(assert_return (invoke "test" (i32.const 27)) (i32.const 3))
+(assert_return (invoke "test" (i32.const 28)) (i32.const 4))
+(assert_return (invoke "test" (i32.const 29)) (i32.const 5))
+(assert_return (invoke "test" (i32.const 30)) (i32.const 6))
+(assert_return (invoke "test" (i32.const 31)) (i32.const 7))
+(module
+           (type (func (result i32)))
+           (table 32 64 funcref)
+           (elem (i32.const 21)
+                  $f0 $f1 $f2 $f3 $f4 $f5 $f6 $f7)
+           (func $f0 (export "f0") (result i32) (i32.const 0))
+           (func $f1 (export "f1") (result i32) (i32.const 1))
+           (func $f2 (export "f2") (result i32) (i32.const 2))
+           (func $f3 (export "f3") (result i32) (i32.const 3))
+           (func $f4 (export "f4") (result i32) (i32.const 4))
+           (func $f5 (export "f5") (result i32) (i32.const 5))
+           (func $f6 (export "f6") (result i32) (i32.const 6))
+           (func $f7 (export "f7") (result i32) (i32.const 7))
+           (func $f8 (export "f8") (result i32) (i32.const 8))
+           (func $f9 (export "f9") (result i32) (i32.const 9))
+           (func $f10 (export "f10") (result i32) (i32.const 10))
+           (func $f11 (export "f11") (result i32) (i32.const 11))
+           (func $f12 (export "f12") (result i32) (i32.const 12))
+           (func $f13 (export "f13") (result i32) (i32.const 13))
+           (func $f14 (export "f14") (result i32) (i32.const 14))
+           (func $f15 (export "f15") (result i32) (i32.const 15))
+           (func (export "test") (param $n i32) (result i32)
+             (call_indirect (type 0) (local.get $n)))
+           (func (export "run") (param $targetOffs i32) (param $srcOffs i32) (param $len i32)
+             (table.copy (local.get $targetOffs) (local.get $srcOffs) (local.get $len))))
+(assert_trap (invoke "run" (i32.const 24) (i32.const 21) (i32.const 16))
+                        "out of bounds")
+(assert_trap (invoke "test" (i32.const 0)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 1)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 2)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 3)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 4)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 5)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 6)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 7)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 8)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 9)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 10)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 11)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 12)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 13)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 14)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 15)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 16)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 17)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 18)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 19)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 20)) "uninitialized element")
+(assert_return (invoke "test" (i32.const 21)) (i32.const 0))
+(assert_return (invoke "test" (i32.const 22)) (i32.const 1))
+(assert_return (invoke "test" (i32.const 23)) (i32.const 2))
+(assert_return (invoke "test" (i32.const 24)) (i32.const 3))
+(assert_return (invoke "test" (i32.const 25)) (i32.const 4))
+(assert_return (invoke "test" (i32.const 26)) (i32.const 5))
+(assert_return (invoke "test" (i32.const 27)) (i32.const 6))
+(assert_return (invoke "test" (i32.const 28)) (i32.const 7))
+(assert_trap (invoke "test" (i32.const 29)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 30)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 31)) "uninitialized element")
+(module
+           (type (func (result i32)))
+           (table 32 64 funcref)
+           (elem (i32.const 24)
+                  $f0 $f1 $f2 $f3 $f4 $f5 $f6 $f7)
+           (func $f0 (export "f0") (result i32) (i32.const 0))
+           (func $f1 (export "f1") (result i32) (i32.const 1))
+           (func $f2 (export "f2") (result i32) (i32.const 2))
+           (func $f3 (export "f3") (result i32) (i32.const 3))
+           (func $f4 (export "f4") (result i32) (i32.const 4))
+           (func $f5 (export "f5") (result i32) (i32.const 5))
+           (func $f6 (export "f6") (result i32) (i32.const 6))
+           (func $f7 (export "f7") (result i32) (i32.const 7))
+           (func $f8 (export "f8") (result i32) (i32.const 8))
+           (func $f9 (export "f9") (result i32) (i32.const 9))
+           (func $f10 (export "f10") (result i32) (i32.const 10))
+           (func $f11 (export "f11") (result i32) (i32.const 11))
+           (func $f12 (export "f12") (result i32) (i32.const 12))
+           (func $f13 (export "f13") (result i32) (i32.const 13))
+           (func $f14 (export "f14") (result i32) (i32.const 14))
+           (func $f15 (export "f15") (result i32) (i32.const 15))
+           (func (export "test") (param $n i32) (result i32)
+             (call_indirect (type 0) (local.get $n)))
+           (func (export "run") (param $targetOffs i32) (param $srcOffs i32) (param $len i32)
+             (table.copy (local.get $targetOffs) (local.get $srcOffs) (local.get $len))))
+(assert_trap (invoke "run" (i32.const 21) (i32.const 24) (i32.const 16))
+                        "out of bounds")
+(assert_trap (invoke "test" (i32.const 0)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 1)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 2)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 3)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 4)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 5)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 6)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 7)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 8)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 9)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 10)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 11)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 12)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 13)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 14)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 15)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 16)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 17)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 18)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 19)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 20)) "uninitialized element")
+(assert_return (invoke "test" (i32.const 21)) (i32.const 0))
+(assert_return (invoke "test" (i32.const 22)) (i32.const 1))
+(assert_return (invoke "test" (i32.const 23)) (i32.const 2))
+(assert_return (invoke "test" (i32.const 24)) (i32.const 3))
+(assert_return (invoke "test" (i32.const 25)) (i32.const 4))
+(assert_return (invoke "test" (i32.const 26)) (i32.const 5))
+(assert_return (invoke "test" (i32.const 27)) (i32.const 6))
+(assert_return (invoke "test" (i32.const 28)) (i32.const 7))
+(assert_return (invoke "test" (i32.const 29)) (i32.const 5))
+(assert_return (invoke "test" (i32.const 30)) (i32.const 6))
+(assert_return (invoke "test" (i32.const 31)) (i32.const 7))
+(module
+           (type (func (result i32)))
+           (table 32 64 funcref)
+           (elem (i32.const 21)
+                  $f0 $f1 $f2 $f3 $f4 $f5 $f6 $f7 $f8 $f9 $f10)
+           (func $f0 (export "f0") (result i32) (i32.const 0))
+           (func $f1 (export "f1") (result i32) (i32.const 1))
+           (func $f2 (export "f2") (result i32) (i32.const 2))
+           (func $f3 (export "f3") (result i32) (i32.const 3))
+           (func $f4 (export "f4") (result i32) (i32.const 4))
+           (func $f5 (export "f5") (result i32) (i32.const 5))
+           (func $f6 (export "f6") (result i32) (i32.const 6))
+           (func $f7 (export "f7") (result i32) (i32.const 7))
+           (func $f8 (export "f8") (result i32) (i32.const 8))
+           (func $f9 (export "f9") (result i32) (i32.const 9))
+           (func $f10 (export "f10") (result i32) (i32.const 10))
+           (func $f11 (export "f11") (result i32) (i32.const 11))
+           (func $f12 (export "f12") (result i32) (i32.const 12))
+           (func $f13 (export "f13") (result i32) (i32.const 13))
+           (func $f14 (export "f14") (result i32) (i32.const 14))
+           (func $f15 (export "f15") (result i32) (i32.const 15))
+           (func (export "test") (param $n i32) (result i32)
+             (call_indirect (type 0) (local.get $n)))
+           (func (export "run") (param $targetOffs i32) (param $srcOffs i32) (param $len i32)
+             (table.copy (local.get $targetOffs) (local.get $srcOffs) (local.get $len))))
+(assert_trap (invoke "run" (i32.const 21) (i32.const 21) (i32.const 16))
+                        "out of bounds")
+(assert_trap (invoke "test" (i32.const 0)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 1)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 2)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 3)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 4)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 5)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 6)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 7)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 8)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 9)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 10)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 11)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 12)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 13)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 14)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 15)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 16)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 17)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 18)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 19)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 20)) "uninitialized element")
+(assert_return (invoke "test" (i32.const 21)) (i32.const 0))
+(assert_return (invoke "test" (i32.const 22)) (i32.const 1))
+(assert_return (invoke "test" (i32.const 23)) (i32.const 2))
+(assert_return (invoke "test" (i32.const 24)) (i32.const 3))
+(assert_return (invoke "test" (i32.const 25)) (i32.const 4))
+(assert_return (invoke "test" (i32.const 26)) (i32.const 5))
+(assert_return (invoke "test" (i32.const 27)) (i32.const 6))
+(assert_return (invoke "test" (i32.const 28)) (i32.const 7))
+(assert_return (invoke "test" (i32.const 29)) (i32.const 8))
+(assert_return (invoke "test" (i32.const 30)) (i32.const 9))
+(assert_return (invoke "test" (i32.const 31)) (i32.const 10))
+(module
+           (type (func (result i32)))
+           (table 128 128 funcref)
+           (elem (i32.const 112)
+                  $f0 $f1 $f2 $f3 $f4 $f5 $f6 $f7 $f8 $f9 $f10 $f11 $f12 $f13 $f14 $f15)
+           (func $f0 (export "f0") (result i32) (i32.const 0))
+           (func $f1 (export "f1") (result i32) (i32.const 1))
+           (func $f2 (export "f2") (result i32) (i32.const 2))
+           (func $f3 (export "f3") (result i32) (i32.const 3))
+           (func $f4 (export "f4") (result i32) (i32.const 4))
+           (func $f5 (export "f5") (result i32) (i32.const 5))
+           (func $f6 (export "f6") (result i32) (i32.const 6))
+           (func $f7 (export "f7") (result i32) (i32.const 7))
+           (func $f8 (export "f8") (result i32) (i32.const 8))
+           (func $f9 (export "f9") (result i32) (i32.const 9))
+           (func $f10 (export "f10") (result i32) (i32.const 10))
+           (func $f11 (export "f11") (result i32) (i32.const 11))
+           (func $f12 (export "f12") (result i32) (i32.const 12))
+           (func $f13 (export "f13") (result i32) (i32.const 13))
+           (func $f14 (export "f14") (result i32) (i32.const 14))
+           (func $f15 (export "f15") (result i32) (i32.const 15))
+           (func (export "test") (param $n i32) (result i32)
+             (call_indirect (type 0) (local.get $n)))
+           (func (export "run") (param $targetOffs i32) (param $srcOffs i32) (param $len i32)
+             (table.copy (local.get $targetOffs) (local.get $srcOffs) (local.get $len))))
+(assert_trap (invoke "run" (i32.const 0) (i32.const 112) (i32.const 4294967264))
+                        "out of bounds")
+(assert_return (invoke "test" (i32.const 0)) (i32.const 0))
+(assert_return (invoke "test" (i32.const 1)) (i32.const 1))
+(assert_return (invoke "test" (i32.const 2)) (i32.const 2))
+(assert_return (invoke "test" (i32.const 3)) (i32.const 3))
+(assert_return (invoke "test" (i32.const 4)) (i32.const 4))
+(assert_return (invoke "test" (i32.const 5)) (i32.const 5))
+(assert_return (invoke "test" (i32.const 6)) (i32.const 6))
+(assert_return (invoke "test" (i32.const 7)) (i32.const 7))
+(assert_return (invoke "test" (i32.const 8)) (i32.const 8))
+(assert_return (invoke "test" (i32.const 9)) (i32.const 9))
+(assert_return (invoke "test" (i32.const 10)) (i32.const 10))
+(assert_return (invoke "test" (i32.const 11)) (i32.const 11))
+(assert_return (invoke "test" (i32.const 12)) (i32.const 12))
+(assert_return (invoke "test" (i32.const 13)) (i32.const 13))
+(assert_return (invoke "test" (i32.const 14)) (i32.const 14))
+(assert_return (invoke "test" (i32.const 15)) (i32.const 15))
+(assert_trap (invoke "test" (i32.const 16)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 17)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 18)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 19)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 20)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 21)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 22)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 23)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 24)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 25)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 26)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 27)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 28)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 29)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 30)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 31)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 32)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 33)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 34)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 35)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 36)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 37)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 38)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 39)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 40)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 41)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 42)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 43)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 44)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 45)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 46)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 47)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 48)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 49)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 50)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 51)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 52)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 53)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 54)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 55)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 56)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 57)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 58)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 59)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 60)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 61)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 62)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 63)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 64)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 65)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 66)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 67)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 68)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 69)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 70)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 71)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 72)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 73)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 74)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 75)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 76)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 77)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 78)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 79)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 80)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 81)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 82)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 83)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 84)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 85)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 86)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 87)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 88)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 89)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 90)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 91)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 92)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 93)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 94)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 95)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 96)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 97)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 98)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 99)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 100)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 101)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 102)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 103)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 104)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 105)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 106)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 107)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 108)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 109)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 110)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 111)) "uninitialized element")
+(assert_return (invoke "test" (i32.const 112)) (i32.const 0))
+(assert_return (invoke "test" (i32.const 113)) (i32.const 1))
+(assert_return (invoke "test" (i32.const 114)) (i32.const 2))
+(assert_return (invoke "test" (i32.const 115)) (i32.const 3))
+(assert_return (invoke "test" (i32.const 116)) (i32.const 4))
+(assert_return (invoke "test" (i32.const 117)) (i32.const 5))
+(assert_return (invoke "test" (i32.const 118)) (i32.const 6))
+(assert_return (invoke "test" (i32.const 119)) (i32.const 7))
+(assert_return (invoke "test" (i32.const 120)) (i32.const 8))
+(assert_return (invoke "test" (i32.const 121)) (i32.const 9))
+(assert_return (invoke "test" (i32.const 122)) (i32.const 10))
+(assert_return (invoke "test" (i32.const 123)) (i32.const 11))
+(assert_return (invoke "test" (i32.const 124)) (i32.const 12))
+(assert_return (invoke "test" (i32.const 125)) (i32.const 13))
+(assert_return (invoke "test" (i32.const 126)) (i32.const 14))
+(assert_return (invoke "test" (i32.const 127)) (i32.const 15))
+(module
+           (type (func (result i32)))
+           (table 128 128 funcref)
+           (elem (i32.const 0)
+                  $f0 $f1 $f2 $f3 $f4 $f5 $f6 $f7 $f8 $f9 $f10 $f11 $f12 $f13 $f14 $f15)
+           (func $f0 (export "f0") (result i32) (i32.const 0))
+           (func $f1 (export "f1") (result i32) (i32.const 1))
+           (func $f2 (export "f2") (result i32) (i32.const 2))
+           (func $f3 (export "f3") (result i32) (i32.const 3))
+           (func $f4 (export "f4") (result i32) (i32.const 4))
+           (func $f5 (export "f5") (result i32) (i32.const 5))
+           (func $f6 (export "f6") (result i32) (i32.const 6))
+           (func $f7 (export "f7") (result i32) (i32.const 7))
+           (func $f8 (export "f8") (result i32) (i32.const 8))
+           (func $f9 (export "f9") (result i32) (i32.const 9))
+           (func $f10 (export "f10") (result i32) (i32.const 10))
+           (func $f11 (export "f11") (result i32) (i32.const 11))
+           (func $f12 (export "f12") (result i32) (i32.const 12))
+           (func $f13 (export "f13") (result i32) (i32.const 13))
+           (func $f14 (export "f14") (result i32) (i32.const 14))
+           (func $f15 (export "f15") (result i32) (i32.const 15))
+           (func (export "test") (param $n i32) (result i32)
+             (call_indirect (type 0) (local.get $n)))
+           (func (export "run") (param $targetOffs i32) (param $srcOffs i32) (param $len i32)
+             (table.copy (local.get $targetOffs) (local.get $srcOffs) (local.get $len))))
+(assert_trap (invoke "run" (i32.const 112) (i32.const 0) (i32.const 4294967264))
+                        "out of bounds")
+(assert_return (invoke "test" (i32.const 0)) (i32.const 0))
+(assert_return (invoke "test" (i32.const 1)) (i32.const 1))
+(assert_return (invoke "test" (i32.const 2)) (i32.const 2))
+(assert_return (invoke "test" (i32.const 3)) (i32.const 3))
+(assert_return (invoke "test" (i32.const 4)) (i32.const 4))
+(assert_return (invoke "test" (i32.const 5)) (i32.const 5))
+(assert_return (invoke "test" (i32.const 6)) (i32.const 6))
+(assert_return (invoke "test" (i32.const 7)) (i32.const 7))
+(assert_return (invoke "test" (i32.const 8)) (i32.const 8))
+(assert_return (invoke "test" (i32.const 9)) (i32.const 9))
+(assert_return (invoke "test" (i32.const 10)) (i32.const 10))
+(assert_return (invoke "test" (i32.const 11)) (i32.const 11))
+(assert_return (invoke "test" (i32.const 12)) (i32.const 12))
+(assert_return (invoke "test" (i32.const 13)) (i32.const 13))
+(assert_return (invoke "test" (i32.const 14)) (i32.const 14))
+(assert_return (invoke "test" (i32.const 15)) (i32.const 15))
+(assert_trap (invoke "test" (i32.const 16)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 17)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 18)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 19)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 20)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 21)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 22)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 23)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 24)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 25)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 26)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 27)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 28)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 29)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 30)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 31)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 32)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 33)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 34)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 35)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 36)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 37)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 38)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 39)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 40)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 41)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 42)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 43)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 44)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 45)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 46)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 47)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 48)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 49)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 50)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 51)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 52)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 53)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 54)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 55)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 56)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 57)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 58)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 59)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 60)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 61)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 62)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 63)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 64)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 65)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 66)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 67)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 68)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 69)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 70)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 71)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 72)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 73)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 74)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 75)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 76)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 77)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 78)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 79)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 80)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 81)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 82)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 83)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 84)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 85)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 86)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 87)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 88)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 89)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 90)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 91)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 92)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 93)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 94)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 95)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 96)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 97)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 98)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 99)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 100)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 101)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 102)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 103)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 104)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 105)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 106)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 107)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 108)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 109)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 110)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 111)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 112)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 113)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 114)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 115)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 116)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 117)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 118)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 119)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 120)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 121)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 122)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 123)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 124)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 125)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 126)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 127)) "uninitialized element")
diff --git a/test/core/table_init.wast b/test/core/table_init.wast
new file mode 100644
index 0000000000..6cd8cbf745
--- /dev/null
+++ b/test/core/table_init.wast
@@ -0,0 +1,1607 @@
+;;
+;; Generated by ../meta/generate_table_init.js
+;;
+
+(module
+  (func (export "ef0") (result i32) (i32.const 0))
+  (func (export "ef1") (result i32) (i32.const 1))
+  (func (export "ef2") (result i32) (i32.const 2))
+  (func (export "ef3") (result i32) (i32.const 3))
+  (func (export "ef4") (result i32) (i32.const 4))
+)
+(register "a")
+
+
+(module
+  (type (func (result i32)))  ;; type #0
+  (import "a" "ef0" (func (result i32)))    ;; index 0
+  (import "a" "ef1" (func (result i32)))
+  (import "a" "ef2" (func (result i32)))
+  (import "a" "ef3" (func (result i32)))
+  (import "a" "ef4" (func (result i32)))    ;; index 4
+  (table 30 30 funcref)
+  (elem (i32.const 2) 3 1 4 1)
+  (elem passive 2 7 1 8)
+  (elem (i32.const 12) 7 5 2 3 6)
+  (elem passive 5 9 2 7 6)
+  (func (result i32) (i32.const 5))  ;; index 5
+  (func (result i32) (i32.const 6))
+  (func (result i32) (i32.const 7))
+  (func (result i32) (i32.const 8))
+  (func (result i32) (i32.const 9))  ;; index 9
+  (func (export "test")
+    (table.init 1 (i32.const 7) (i32.const 0) (i32.const 4)))
+  (func (export "check") (param i32) (result i32)
+    (call_indirect (type 0) (local.get 0)))
+)
+
+(invoke "test")
+(assert_trap (invoke "check" (i32.const 0)) "uninitialized element")
+(assert_trap (invoke "check" (i32.const 1)) "uninitialized element")
+(assert_return (invoke "check" (i32.const 2)) (i32.const 3))
+(assert_return (invoke "check" (i32.const 3)) (i32.const 1))
+(assert_return (invoke "check" (i32.const 4)) (i32.const 4))
+(assert_return (invoke "check" (i32.const 5)) (i32.const 1))
+(assert_trap (invoke "check" (i32.const 6)) "uninitialized element")
+(assert_return (invoke "check" (i32.const 7)) (i32.const 2))
+(assert_return (invoke "check" (i32.const 8)) (i32.const 7))
+(assert_return (invoke "check" (i32.const 9)) (i32.const 1))
+(assert_return (invoke "check" (i32.const 10)) (i32.const 8))
+(assert_trap (invoke "check" (i32.const 11)) "uninitialized element")
+(assert_return (invoke "check" (i32.const 12)) (i32.const 7))
+(assert_return (invoke "check" (i32.const 13)) (i32.const 5))
+(assert_return (invoke "check" (i32.const 14)) (i32.const 2))
+(assert_return (invoke "check" (i32.const 15)) (i32.const 3))
+(assert_return (invoke "check" (i32.const 16)) (i32.const 6))
+(assert_trap (invoke "check" (i32.const 17)) "uninitialized element")
+(assert_trap (invoke "check" (i32.const 18)) "uninitialized element")
+(assert_trap (invoke "check" (i32.const 19)) "uninitialized element")
+(assert_trap (invoke "check" (i32.const 20)) "uninitialized element")
+(assert_trap (invoke "check" (i32.const 21)) "uninitialized element")
+(assert_trap (invoke "check" (i32.const 22)) "uninitialized element")
+(assert_trap (invoke "check" (i32.const 23)) "uninitialized element")
+(assert_trap (invoke "check" (i32.const 24)) "uninitialized element")
+(assert_trap (invoke "check" (i32.const 25)) "uninitialized element")
+(assert_trap (invoke "check" (i32.const 26)) "uninitialized element")
+(assert_trap (invoke "check" (i32.const 27)) "uninitialized element")
+(assert_trap (invoke "check" (i32.const 28)) "uninitialized element")
+(assert_trap (invoke "check" (i32.const 29)) "uninitialized element")
+
+(module
+  (type (func (result i32)))  ;; type #0
+  (import "a" "ef0" (func (result i32)))    ;; index 0
+  (import "a" "ef1" (func (result i32)))
+  (import "a" "ef2" (func (result i32)))
+  (import "a" "ef3" (func (result i32)))
+  (import "a" "ef4" (func (result i32)))    ;; index 4
+  (table 30 30 funcref)
+  (elem (i32.const 2) 3 1 4 1)
+  (elem passive 2 7 1 8)
+  (elem (i32.const 12) 7 5 2 3 6)
+  (elem passive 5 9 2 7 6)
+  (func (result i32) (i32.const 5))  ;; index 5
+  (func (result i32) (i32.const 6))
+  (func (result i32) (i32.const 7))
+  (func (result i32) (i32.const 8))
+  (func (result i32) (i32.const 9))  ;; index 9
+  (func (export "test")
+    (table.init 3 (i32.const 15) (i32.const 1) (i32.const 3)))
+  (func (export "check") (param i32) (result i32)
+    (call_indirect (type 0) (local.get 0)))
+)
+
+(invoke "test")
+(assert_trap (invoke "check" (i32.const 0)) "uninitialized element")
+(assert_trap (invoke "check" (i32.const 1)) "uninitialized element")
+(assert_return (invoke "check" (i32.const 2)) (i32.const 3))
+(assert_return (invoke "check" (i32.const 3)) (i32.const 1))
+(assert_return (invoke "check" (i32.const 4)) (i32.const 4))
+(assert_return (invoke "check" (i32.const 5)) (i32.const 1))
+(assert_trap (invoke "check" (i32.const 6)) "uninitialized element")
+(assert_trap (invoke "check" (i32.const 7)) "uninitialized element")
+(assert_trap (invoke "check" (i32.const 8)) "uninitialized element")
+(assert_trap (invoke "check" (i32.const 9)) "uninitialized element")
+(assert_trap (invoke "check" (i32.const 10)) "uninitialized element")
+(assert_trap (invoke "check" (i32.const 11)) "uninitialized element")
+(assert_return (invoke "check" (i32.const 12)) (i32.const 7))
+(assert_return (invoke "check" (i32.const 13)) (i32.const 5))
+(assert_return (invoke "check" (i32.const 14)) (i32.const 2))
+(assert_return (invoke "check" (i32.const 15)) (i32.const 9))
+(assert_return (invoke "check" (i32.const 16)) (i32.const 2))
+(assert_return (invoke "check" (i32.const 17)) (i32.const 7))
+(assert_trap (invoke "check" (i32.const 18)) "uninitialized element")
+(assert_trap (invoke "check" (i32.const 19)) "uninitialized element")
+(assert_trap (invoke "check" (i32.const 20)) "uninitialized element")
+(assert_trap (invoke "check" (i32.const 21)) "uninitialized element")
+(assert_trap (invoke "check" (i32.const 22)) "uninitialized element")
+(assert_trap (invoke "check" (i32.const 23)) "uninitialized element")
+(assert_trap (invoke "check" (i32.const 24)) "uninitialized element")
+(assert_trap (invoke "check" (i32.const 25)) "uninitialized element")
+(assert_trap (invoke "check" (i32.const 26)) "uninitialized element")
+(assert_trap (invoke "check" (i32.const 27)) "uninitialized element")
+(assert_trap (invoke "check" (i32.const 28)) "uninitialized element")
+(assert_trap (invoke "check" (i32.const 29)) "uninitialized element")
+
+(module
+  (type (func (result i32)))  ;; type #0
+  (import "a" "ef0" (func (result i32)))    ;; index 0
+  (import "a" "ef1" (func (result i32)))
+  (import "a" "ef2" (func (result i32)))
+  (import "a" "ef3" (func (result i32)))
+  (import "a" "ef4" (func (result i32)))    ;; index 4
+  (table 30 30 funcref)
+  (elem (i32.const 2) 3 1 4 1)
+  (elem passive 2 7 1 8)
+  (elem (i32.const 12) 7 5 2 3 6)
+  (elem passive 5 9 2 7 6)
+  (func (result i32) (i32.const 5))  ;; index 5
+  (func (result i32) (i32.const 6))
+  (func (result i32) (i32.const 7))
+  (func (result i32) (i32.const 8))
+  (func (result i32) (i32.const 9))  ;; index 9
+  (func (export "test")
+    (table.init 1 (i32.const 7) (i32.const 0) (i32.const 4)) 
+elem.drop 1 
+(table.init 3 (i32.const 15) (i32.const 1) (i32.const 3)) 
+elem.drop 3 
+(table.copy (i32.const 20) (i32.const 15) (i32.const 5)) 
+(table.copy (i32.const 21) (i32.const 29) (i32.const 1)) 
+(table.copy (i32.const 24) (i32.const 10) (i32.const 1)) 
+(table.copy (i32.const 13) (i32.const 11) (i32.const 4)) 
+(table.copy (i32.const 19) (i32.const 20) (i32.const 5)))
+  (func (export "check") (param i32) (result i32)
+    (call_indirect (type 0) (local.get 0)))
+)
+
+(invoke "test")
+(assert_trap (invoke "check" (i32.const 0)) "uninitialized element")
+(assert_trap (invoke "check" (i32.const 1)) "uninitialized element")
+(assert_return (invoke "check" (i32.const 2)) (i32.const 3))
+(assert_return (invoke "check" (i32.const 3)) (i32.const 1))
+(assert_return (invoke "check" (i32.const 4)) (i32.const 4))
+(assert_return (invoke "check" (i32.const 5)) (i32.const 1))
+(assert_trap (invoke "check" (i32.const 6)) "uninitialized element")
+(assert_return (invoke "check" (i32.const 7)) (i32.const 2))
+(assert_return (invoke "check" (i32.const 8)) (i32.const 7))
+(assert_return (invoke "check" (i32.const 9)) (i32.const 1))
+(assert_return (invoke "check" (i32.const 10)) (i32.const 8))
+(assert_trap (invoke "check" (i32.const 11)) "uninitialized element")
+(assert_return (invoke "check" (i32.const 12)) (i32.const 7))
+(assert_trap (invoke "check" (i32.const 13)) "uninitialized element")
+(assert_return (invoke "check" (i32.const 14)) (i32.const 7))
+(assert_return (invoke "check" (i32.const 15)) (i32.const 5))
+(assert_return (invoke "check" (i32.const 16)) (i32.const 2))
+(assert_return (invoke "check" (i32.const 17)) (i32.const 7))
+(assert_trap (invoke "check" (i32.const 18)) "uninitialized element")
+(assert_return (invoke "check" (i32.const 19)) (i32.const 9))
+(assert_trap (invoke "check" (i32.const 20)) "uninitialized element")
+(assert_return (invoke "check" (i32.const 21)) (i32.const 7))
+(assert_trap (invoke "check" (i32.const 22)) "uninitialized element")
+(assert_return (invoke "check" (i32.const 23)) (i32.const 8))
+(assert_return (invoke "check" (i32.const 24)) (i32.const 8))
+(assert_trap (invoke "check" (i32.const 25)) "uninitialized element")
+(assert_trap (invoke "check" (i32.const 26)) "uninitialized element")
+(assert_trap (invoke "check" (i32.const 27)) "uninitialized element")
+(assert_trap (invoke "check" (i32.const 28)) "uninitialized element")
+(assert_trap (invoke "check" (i32.const 29)) "uninitialized element")
+(assert_invalid
+  (module
+    (func (export "test")
+      (elem.drop 0)))
+  "unknown table 0")
+
+(assert_invalid
+  (module
+    (func (export "test")
+      (table.init 0 (i32.const 12) (i32.const 1) (i32.const 1))))
+  "unknown table 0")
+
+(assert_invalid
+  (module
+    (elem passive 0)
+    (func (result i32) (i32.const 0))
+    (func (export "test")
+      (elem.drop 4)))
+  "unknown table 0")
+
+(assert_invalid
+  (module
+    (elem passive 0)
+    (func (result i32) (i32.const 0))
+    (func (export "test")
+      (table.init 4 (i32.const 12) (i32.const 1) (i32.const 1))))
+  "unknown table 0")
+
+
+(module
+  (table 30 30 funcref)
+  (elem (i32.const 2) 3 1 4 1)
+  (elem passive 2 7 1 8)
+  (elem (i32.const 12) 7 5 2 3 6)
+  (elem passive 5 9 2 7 6)
+  (func (result i32) (i32.const 0))
+  (func (result i32) (i32.const 1))
+  (func (result i32) (i32.const 2))
+  (func (result i32) (i32.const 3))
+  (func (result i32) (i32.const 4))
+  (func (result i32) (i32.const 5))
+  (func (result i32) (i32.const 6))
+  (func (result i32) (i32.const 7))
+  (func (result i32) (i32.const 8))
+  (func (result i32) (i32.const 9))
+  (func (export "test")
+    elem.drop 2
+    ))
+
+(assert_trap (invoke "test") "elements segment dropped")
+
+(module
+  (table 30 30 funcref)
+  (elem (i32.const 2) 3 1 4 1)
+  (elem passive 2 7 1 8)
+  (elem (i32.const 12) 7 5 2 3 6)
+  (elem passive 5 9 2 7 6)
+  (func (result i32) (i32.const 0))
+  (func (result i32) (i32.const 1))
+  (func (result i32) (i32.const 2))
+  (func (result i32) (i32.const 3))
+  (func (result i32) (i32.const 4))
+  (func (result i32) (i32.const 5))
+  (func (result i32) (i32.const 6))
+  (func (result i32) (i32.const 7))
+  (func (result i32) (i32.const 8))
+  (func (result i32) (i32.const 9))
+  (func (export "test")
+    (table.init 2 (i32.const 12) (i32.const 1) (i32.const 1))
+    ))
+
+(assert_trap (invoke "test") "elements segment dropped")
+
+(module
+  (table 30 30 funcref)
+  (elem (i32.const 2) 3 1 4 1)
+  (elem passive 2 7 1 8)
+  (elem (i32.const 12) 7 5 2 3 6)
+  (elem passive 5 9 2 7 6)
+  (func (result i32) (i32.const 0))
+  (func (result i32) (i32.const 1))
+  (func (result i32) (i32.const 2))
+  (func (result i32) (i32.const 3))
+  (func (result i32) (i32.const 4))
+  (func (result i32) (i32.const 5))
+  (func (result i32) (i32.const 6))
+  (func (result i32) (i32.const 7))
+  (func (result i32) (i32.const 8))
+  (func (result i32) (i32.const 9))
+  (func (export "test")
+    (table.init 1 (i32.const 12) (i32.const 1) (i32.const 1))
+    (table.init 1 (i32.const 21) (i32.const 1) (i32.const 1))))
+
+(invoke "test")
+
+(module
+  (table 30 30 funcref)
+  (elem (i32.const 2) 3 1 4 1)
+  (elem passive 2 7 1 8)
+  (elem (i32.const 12) 7 5 2 3 6)
+  (elem passive 5 9 2 7 6)
+  (func (result i32) (i32.const 0))
+  (func (result i32) (i32.const 1))
+  (func (result i32) (i32.const 2))
+  (func (result i32) (i32.const 3))
+  (func (result i32) (i32.const 4))
+  (func (result i32) (i32.const 5))
+  (func (result i32) (i32.const 6))
+  (func (result i32) (i32.const 7))
+  (func (result i32) (i32.const 8))
+  (func (result i32) (i32.const 9))
+  (func (export "test")
+    elem.drop 1
+    elem.drop 1))
+
+(assert_trap (invoke "test") "elements segment dropped")
+
+(module
+  (table 30 30 funcref)
+  (elem (i32.const 2) 3 1 4 1)
+  (elem passive 2 7 1 8)
+  (elem (i32.const 12) 7 5 2 3 6)
+  (elem passive 5 9 2 7 6)
+  (func (result i32) (i32.const 0))
+  (func (result i32) (i32.const 1))
+  (func (result i32) (i32.const 2))
+  (func (result i32) (i32.const 3))
+  (func (result i32) (i32.const 4))
+  (func (result i32) (i32.const 5))
+  (func (result i32) (i32.const 6))
+  (func (result i32) (i32.const 7))
+  (func (result i32) (i32.const 8))
+  (func (result i32) (i32.const 9))
+  (func (export "test")
+    elem.drop 1
+    (table.init 1 (i32.const 12) (i32.const 1) (i32.const 1))))
+
+(assert_trap (invoke "test") "elements segment dropped")
+
+(module
+  (table 30 30 funcref)
+  (elem (i32.const 2) 3 1 4 1)
+  (elem passive 2 7 1 8)
+  (elem (i32.const 12) 7 5 2 3 6)
+  (elem passive 5 9 2 7 6)
+  (func (result i32) (i32.const 0))
+  (func (result i32) (i32.const 1))
+  (func (result i32) (i32.const 2))
+  (func (result i32) (i32.const 3))
+  (func (result i32) (i32.const 4))
+  (func (result i32) (i32.const 5))
+  (func (result i32) (i32.const 6))
+  (func (result i32) (i32.const 7))
+  (func (result i32) (i32.const 8))
+  (func (result i32) (i32.const 9))
+  (func (export "test")
+    
+    (table.init 1 (i32.const 12) (i32.const 0) (i32.const 5))))
+
+(assert_trap (invoke "test") "out of bounds")
+
+(module
+  (table 30 30 funcref)
+  (elem (i32.const 2) 3 1 4 1)
+  (elem passive 2 7 1 8)
+  (elem (i32.const 12) 7 5 2 3 6)
+  (elem passive 5 9 2 7 6)
+  (func (result i32) (i32.const 0))
+  (func (result i32) (i32.const 1))
+  (func (result i32) (i32.const 2))
+  (func (result i32) (i32.const 3))
+  (func (result i32) (i32.const 4))
+  (func (result i32) (i32.const 5))
+  (func (result i32) (i32.const 6))
+  (func (result i32) (i32.const 7))
+  (func (result i32) (i32.const 8))
+  (func (result i32) (i32.const 9))
+  (func (export "test")
+    
+    (table.init 1 (i32.const 12) (i32.const 2) (i32.const 3))))
+
+(assert_trap (invoke "test") "out of bounds")
+
+(module
+  (table 30 30 funcref)
+  (elem (i32.const 2) 3 1 4 1)
+  (elem passive 2 7 1 8)
+  (elem (i32.const 12) 7 5 2 3 6)
+  (elem passive 5 9 2 7 6)
+  (func (result i32) (i32.const 0))
+  (func (result i32) (i32.const 1))
+  (func (result i32) (i32.const 2))
+  (func (result i32) (i32.const 3))
+  (func (result i32) (i32.const 4))
+  (func (result i32) (i32.const 5))
+  (func (result i32) (i32.const 6))
+  (func (result i32) (i32.const 7))
+  (func (result i32) (i32.const 8))
+  (func (result i32) (i32.const 9))
+  (func (export "test")
+    
+    (table.init 1 (i32.const 28) (i32.const 1) (i32.const 3))))
+
+(assert_trap (invoke "test") "out of bounds")
+
+(module
+  (table 30 30 funcref)
+  (elem (i32.const 2) 3 1 4 1)
+  (elem passive 2 7 1 8)
+  (elem (i32.const 12) 7 5 2 3 6)
+  (elem passive 5 9 2 7 6)
+  (func (result i32) (i32.const 0))
+  (func (result i32) (i32.const 1))
+  (func (result i32) (i32.const 2))
+  (func (result i32) (i32.const 3))
+  (func (result i32) (i32.const 4))
+  (func (result i32) (i32.const 5))
+  (func (result i32) (i32.const 6))
+  (func (result i32) (i32.const 7))
+  (func (result i32) (i32.const 8))
+  (func (result i32) (i32.const 9))
+  (func (export "test")
+    
+    (table.init 1 (i32.const 12) (i32.const 4) (i32.const 0))))
+
+(invoke "test")
+
+(module
+  (table 30 30 funcref)
+  (elem (i32.const 2) 3 1 4 1)
+  (elem passive 2 7 1 8)
+  (elem (i32.const 12) 7 5 2 3 6)
+  (elem passive 5 9 2 7 6)
+  (func (result i32) (i32.const 0))
+  (func (result i32) (i32.const 1))
+  (func (result i32) (i32.const 2))
+  (func (result i32) (i32.const 3))
+  (func (result i32) (i32.const 4))
+  (func (result i32) (i32.const 5))
+  (func (result i32) (i32.const 6))
+  (func (result i32) (i32.const 7))
+  (func (result i32) (i32.const 8))
+  (func (result i32) (i32.const 9))
+  (func (export "test")
+    
+    (table.init 1 (i32.const 30) (i32.const 2) (i32.const 0))))
+
+(invoke "test")
+(assert_invalid
+   (module
+     (table 10 funcref)
+     (elem passive $f0 $f0 $f0)
+     (func $f0)
+     (func (export "test")
+       (table.init 0 (i32.const 1) (i32.const 1) (f32.const 1))))
+   "type mismatch")
+
+(assert_invalid
+   (module
+     (table 10 funcref)
+     (elem passive $f0 $f0 $f0)
+     (func $f0)
+     (func (export "test")
+       (table.init 0 (i32.const 1) (i32.const 1) (i64.const 1))))
+   "type mismatch")
+
+(assert_invalid
+   (module
+     (table 10 funcref)
+     (elem passive $f0 $f0 $f0)
+     (func $f0)
+     (func (export "test")
+       (table.init 0 (i32.const 1) (i32.const 1) (f64.const 1))))
+   "type mismatch")
+
+(assert_invalid
+   (module
+     (table 10 funcref)
+     (elem passive $f0 $f0 $f0)
+     (func $f0)
+     (func (export "test")
+       (table.init 0 (i32.const 1) (f32.const 1) (i32.const 1))))
+   "type mismatch")
+
+(assert_invalid
+   (module
+     (table 10 funcref)
+     (elem passive $f0 $f0 $f0)
+     (func $f0)
+     (func (export "test")
+       (table.init 0 (i32.const 1) (f32.const 1) (f32.const 1))))
+   "type mismatch")
+
+(assert_invalid
+   (module
+     (table 10 funcref)
+     (elem passive $f0 $f0 $f0)
+     (func $f0)
+     (func (export "test")
+       (table.init 0 (i32.const 1) (f32.const 1) (i64.const 1))))
+   "type mismatch")
+
+(assert_invalid
+   (module
+     (table 10 funcref)
+     (elem passive $f0 $f0 $f0)
+     (func $f0)
+     (func (export "test")
+       (table.init 0 (i32.const 1) (f32.const 1) (f64.const 1))))
+   "type mismatch")
+
+(assert_invalid
+   (module
+     (table 10 funcref)
+     (elem passive $f0 $f0 $f0)
+     (func $f0)
+     (func (export "test")
+       (table.init 0 (i32.const 1) (i64.const 1) (i32.const 1))))
+   "type mismatch")
+
+(assert_invalid
+   (module
+     (table 10 funcref)
+     (elem passive $f0 $f0 $f0)
+     (func $f0)
+     (func (export "test")
+       (table.init 0 (i32.const 1) (i64.const 1) (f32.const 1))))
+   "type mismatch")
+
+(assert_invalid
+   (module
+     (table 10 funcref)
+     (elem passive $f0 $f0 $f0)
+     (func $f0)
+     (func (export "test")
+       (table.init 0 (i32.const 1) (i64.const 1) (i64.const 1))))
+   "type mismatch")
+
+(assert_invalid
+   (module
+     (table 10 funcref)
+     (elem passive $f0 $f0 $f0)
+     (func $f0)
+     (func (export "test")
+       (table.init 0 (i32.const 1) (i64.const 1) (f64.const 1))))
+   "type mismatch")
+
+(assert_invalid
+   (module
+     (table 10 funcref)
+     (elem passive $f0 $f0 $f0)
+     (func $f0)
+     (func (export "test")
+       (table.init 0 (i32.const 1) (f64.const 1) (i32.const 1))))
+   "type mismatch")
+
+(assert_invalid
+   (module
+     (table 10 funcref)
+     (elem passive $f0 $f0 $f0)
+     (func $f0)
+     (func (export "test")
+       (table.init 0 (i32.const 1) (f64.const 1) (f32.const 1))))
+   "type mismatch")
+
+(assert_invalid
+   (module
+     (table 10 funcref)
+     (elem passive $f0 $f0 $f0)
+     (func $f0)
+     (func (export "test")
+       (table.init 0 (i32.const 1) (f64.const 1) (i64.const 1))))
+   "type mismatch")
+
+(assert_invalid
+   (module
+     (table 10 funcref)
+     (elem passive $f0 $f0 $f0)
+     (func $f0)
+     (func (export "test")
+       (table.init 0 (i32.const 1) (f64.const 1) (f64.const 1))))
+   "type mismatch")
+
+(assert_invalid
+   (module
+     (table 10 funcref)
+     (elem passive $f0 $f0 $f0)
+     (func $f0)
+     (func (export "test")
+       (table.init 0 (f32.const 1) (i32.const 1) (i32.const 1))))
+   "type mismatch")
+
+(assert_invalid
+   (module
+     (table 10 funcref)
+     (elem passive $f0 $f0 $f0)
+     (func $f0)
+     (func (export "test")
+       (table.init 0 (f32.const 1) (i32.const 1) (f32.const 1))))
+   "type mismatch")
+
+(assert_invalid
+   (module
+     (table 10 funcref)
+     (elem passive $f0 $f0 $f0)
+     (func $f0)
+     (func (export "test")
+       (table.init 0 (f32.const 1) (i32.const 1) (i64.const 1))))
+   "type mismatch")
+
+(assert_invalid
+   (module
+     (table 10 funcref)
+     (elem passive $f0 $f0 $f0)
+     (func $f0)
+     (func (export "test")
+       (table.init 0 (f32.const 1) (i32.const 1) (f64.const 1))))
+   "type mismatch")
+
+(assert_invalid
+   (module
+     (table 10 funcref)
+     (elem passive $f0 $f0 $f0)
+     (func $f0)
+     (func (export "test")
+       (table.init 0 (f32.const 1) (f32.const 1) (i32.const 1))))
+   "type mismatch")
+
+(assert_invalid
+   (module
+     (table 10 funcref)
+     (elem passive $f0 $f0 $f0)
+     (func $f0)
+     (func (export "test")
+       (table.init 0 (f32.const 1) (f32.const 1) (f32.const 1))))
+   "type mismatch")
+
+(assert_invalid
+   (module
+     (table 10 funcref)
+     (elem passive $f0 $f0 $f0)
+     (func $f0)
+     (func (export "test")
+       (table.init 0 (f32.const 1) (f32.const 1) (i64.const 1))))
+   "type mismatch")
+
+(assert_invalid
+   (module
+     (table 10 funcref)
+     (elem passive $f0 $f0 $f0)
+     (func $f0)
+     (func (export "test")
+       (table.init 0 (f32.const 1) (f32.const 1) (f64.const 1))))
+   "type mismatch")
+
+(assert_invalid
+   (module
+     (table 10 funcref)
+     (elem passive $f0 $f0 $f0)
+     (func $f0)
+     (func (export "test")
+       (table.init 0 (f32.const 1) (i64.const 1) (i32.const 1))))
+   "type mismatch")
+
+(assert_invalid
+   (module
+     (table 10 funcref)
+     (elem passive $f0 $f0 $f0)
+     (func $f0)
+     (func (export "test")
+       (table.init 0 (f32.const 1) (i64.const 1) (f32.const 1))))
+   "type mismatch")
+
+(assert_invalid
+   (module
+     (table 10 funcref)
+     (elem passive $f0 $f0 $f0)
+     (func $f0)
+     (func (export "test")
+       (table.init 0 (f32.const 1) (i64.const 1) (i64.const 1))))
+   "type mismatch")
+
+(assert_invalid
+   (module
+     (table 10 funcref)
+     (elem passive $f0 $f0 $f0)
+     (func $f0)
+     (func (export "test")
+       (table.init 0 (f32.const 1) (i64.const 1) (f64.const 1))))
+   "type mismatch")
+
+(assert_invalid
+   (module
+     (table 10 funcref)
+     (elem passive $f0 $f0 $f0)
+     (func $f0)
+     (func (export "test")
+       (table.init 0 (f32.const 1) (f64.const 1) (i32.const 1))))
+   "type mismatch")
+
+(assert_invalid
+   (module
+     (table 10 funcref)
+     (elem passive $f0 $f0 $f0)
+     (func $f0)
+     (func (export "test")
+       (table.init 0 (f32.const 1) (f64.const 1) (f32.const 1))))
+   "type mismatch")
+
+(assert_invalid
+   (module
+     (table 10 funcref)
+     (elem passive $f0 $f0 $f0)
+     (func $f0)
+     (func (export "test")
+       (table.init 0 (f32.const 1) (f64.const 1) (i64.const 1))))
+   "type mismatch")
+
+(assert_invalid
+   (module
+     (table 10 funcref)
+     (elem passive $f0 $f0 $f0)
+     (func $f0)
+     (func (export "test")
+       (table.init 0 (f32.const 1) (f64.const 1) (f64.const 1))))
+   "type mismatch")
+
+(assert_invalid
+   (module
+     (table 10 funcref)
+     (elem passive $f0 $f0 $f0)
+     (func $f0)
+     (func (export "test")
+       (table.init 0 (i64.const 1) (i32.const 1) (i32.const 1))))
+   "type mismatch")
+
+(assert_invalid
+   (module
+     (table 10 funcref)
+     (elem passive $f0 $f0 $f0)
+     (func $f0)
+     (func (export "test")
+       (table.init 0 (i64.const 1) (i32.const 1) (f32.const 1))))
+   "type mismatch")
+
+(assert_invalid
+   (module
+     (table 10 funcref)
+     (elem passive $f0 $f0 $f0)
+     (func $f0)
+     (func (export "test")
+       (table.init 0 (i64.const 1) (i32.const 1) (i64.const 1))))
+   "type mismatch")
+
+(assert_invalid
+   (module
+     (table 10 funcref)
+     (elem passive $f0 $f0 $f0)
+     (func $f0)
+     (func (export "test")
+       (table.init 0 (i64.const 1) (i32.const 1) (f64.const 1))))
+   "type mismatch")
+
+(assert_invalid
+   (module
+     (table 10 funcref)
+     (elem passive $f0 $f0 $f0)
+     (func $f0)
+     (func (export "test")
+       (table.init 0 (i64.const 1) (f32.const 1) (i32.const 1))))
+   "type mismatch")
+
+(assert_invalid
+   (module
+     (table 10 funcref)
+     (elem passive $f0 $f0 $f0)
+     (func $f0)
+     (func (export "test")
+       (table.init 0 (i64.const 1) (f32.const 1) (f32.const 1))))
+   "type mismatch")
+
+(assert_invalid
+   (module
+     (table 10 funcref)
+     (elem passive $f0 $f0 $f0)
+     (func $f0)
+     (func (export "test")
+       (table.init 0 (i64.const 1) (f32.const 1) (i64.const 1))))
+   "type mismatch")
+
+(assert_invalid
+   (module
+     (table 10 funcref)
+     (elem passive $f0 $f0 $f0)
+     (func $f0)
+     (func (export "test")
+       (table.init 0 (i64.const 1) (f32.const 1) (f64.const 1))))
+   "type mismatch")
+
+(assert_invalid
+   (module
+     (table 10 funcref)
+     (elem passive $f0 $f0 $f0)
+     (func $f0)
+     (func (export "test")
+       (table.init 0 (i64.const 1) (i64.const 1) (i32.const 1))))
+   "type mismatch")
+
+(assert_invalid
+   (module
+     (table 10 funcref)
+     (elem passive $f0 $f0 $f0)
+     (func $f0)
+     (func (export "test")
+       (table.init 0 (i64.const 1) (i64.const 1) (f32.const 1))))
+   "type mismatch")
+
+(assert_invalid
+   (module
+     (table 10 funcref)
+     (elem passive $f0 $f0 $f0)
+     (func $f0)
+     (func (export "test")
+       (table.init 0 (i64.const 1) (i64.const 1) (i64.const 1))))
+   "type mismatch")
+
+(assert_invalid
+   (module
+     (table 10 funcref)
+     (elem passive $f0 $f0 $f0)
+     (func $f0)
+     (func (export "test")
+       (table.init 0 (i64.const 1) (i64.const 1) (f64.const 1))))
+   "type mismatch")
+
+(assert_invalid
+   (module
+     (table 10 funcref)
+     (elem passive $f0 $f0 $f0)
+     (func $f0)
+     (func (export "test")
+       (table.init 0 (i64.const 1) (f64.const 1) (i32.const 1))))
+   "type mismatch")
+
+(assert_invalid
+   (module
+     (table 10 funcref)
+     (elem passive $f0 $f0 $f0)
+     (func $f0)
+     (func (export "test")
+       (table.init 0 (i64.const 1) (f64.const 1) (f32.const 1))))
+   "type mismatch")
+
+(assert_invalid
+   (module
+     (table 10 funcref)
+     (elem passive $f0 $f0 $f0)
+     (func $f0)
+     (func (export "test")
+       (table.init 0 (i64.const 1) (f64.const 1) (i64.const 1))))
+   "type mismatch")
+
+(assert_invalid
+   (module
+     (table 10 funcref)
+     (elem passive $f0 $f0 $f0)
+     (func $f0)
+     (func (export "test")
+       (table.init 0 (i64.const 1) (f64.const 1) (f64.const 1))))
+   "type mismatch")
+
+(assert_invalid
+   (module
+     (table 10 funcref)
+     (elem passive $f0 $f0 $f0)
+     (func $f0)
+     (func (export "test")
+       (table.init 0 (f64.const 1) (i32.const 1) (i32.const 1))))
+   "type mismatch")
+
+(assert_invalid
+   (module
+     (table 10 funcref)
+     (elem passive $f0 $f0 $f0)
+     (func $f0)
+     (func (export "test")
+       (table.init 0 (f64.const 1) (i32.const 1) (f32.const 1))))
+   "type mismatch")
+
+(assert_invalid
+   (module
+     (table 10 funcref)
+     (elem passive $f0 $f0 $f0)
+     (func $f0)
+     (func (export "test")
+       (table.init 0 (f64.const 1) (i32.const 1) (i64.const 1))))
+   "type mismatch")
+
+(assert_invalid
+   (module
+     (table 10 funcref)
+     (elem passive $f0 $f0 $f0)
+     (func $f0)
+     (func (export "test")
+       (table.init 0 (f64.const 1) (i32.const 1) (f64.const 1))))
+   "type mismatch")
+
+(assert_invalid
+   (module
+     (table 10 funcref)
+     (elem passive $f0 $f0 $f0)
+     (func $f0)
+     (func (export "test")
+       (table.init 0 (f64.const 1) (f32.const 1) (i32.const 1))))
+   "type mismatch")
+
+(assert_invalid
+   (module
+     (table 10 funcref)
+     (elem passive $f0 $f0 $f0)
+     (func $f0)
+     (func (export "test")
+       (table.init 0 (f64.const 1) (f32.const 1) (f32.const 1))))
+   "type mismatch")
+
+(assert_invalid
+   (module
+     (table 10 funcref)
+     (elem passive $f0 $f0 $f0)
+     (func $f0)
+     (func (export "test")
+       (table.init 0 (f64.const 1) (f32.const 1) (i64.const 1))))
+   "type mismatch")
+
+(assert_invalid
+   (module
+     (table 10 funcref)
+     (elem passive $f0 $f0 $f0)
+     (func $f0)
+     (func (export "test")
+       (table.init 0 (f64.const 1) (f32.const 1) (f64.const 1))))
+   "type mismatch")
+
+(assert_invalid
+   (module
+     (table 10 funcref)
+     (elem passive $f0 $f0 $f0)
+     (func $f0)
+     (func (export "test")
+       (table.init 0 (f64.const 1) (i64.const 1) (i32.const 1))))
+   "type mismatch")
+
+(assert_invalid
+   (module
+     (table 10 funcref)
+     (elem passive $f0 $f0 $f0)
+     (func $f0)
+     (func (export "test")
+       (table.init 0 (f64.const 1) (i64.const 1) (f32.const 1))))
+   "type mismatch")
+
+(assert_invalid
+   (module
+     (table 10 funcref)
+     (elem passive $f0 $f0 $f0)
+     (func $f0)
+     (func (export "test")
+       (table.init 0 (f64.const 1) (i64.const 1) (i64.const 1))))
+   "type mismatch")
+
+(assert_invalid
+   (module
+     (table 10 funcref)
+     (elem passive $f0 $f0 $f0)
+     (func $f0)
+     (func (export "test")
+       (table.init 0 (f64.const 1) (i64.const 1) (f64.const 1))))
+   "type mismatch")
+
+(assert_invalid
+   (module
+     (table 10 funcref)
+     (elem passive $f0 $f0 $f0)
+     (func $f0)
+     (func (export "test")
+       (table.init 0 (f64.const 1) (f64.const 1) (i32.const 1))))
+   "type mismatch")
+
+(assert_invalid
+   (module
+     (table 10 funcref)
+     (elem passive $f0 $f0 $f0)
+     (func $f0)
+     (func (export "test")
+       (table.init 0 (f64.const 1) (f64.const 1) (f32.const 1))))
+   "type mismatch")
+
+(assert_invalid
+   (module
+     (table 10 funcref)
+     (elem passive $f0 $f0 $f0)
+     (func $f0)
+     (func (export "test")
+       (table.init 0 (f64.const 1) (f64.const 1) (i64.const 1))))
+   "type mismatch")
+
+(assert_invalid
+   (module
+     (table 10 funcref)
+     (elem passive $f0 $f0 $f0)
+     (func $f0)
+     (func (export "test")
+       (table.init 0 (f64.const 1) (f64.const 1) (f64.const 1))))
+   "type mismatch")
+
+(module
+           (type (func (result i32)))
+           (table 32 64 funcref)
+           (elem passive $f0 $f1 $f2 $f3 $f4 $f5 $f6 $f7 $f8 $f9 $f10 $f11 $f12 $f13 $f14 $f15)
+           (func $f0 (export "f0") (result i32) (i32.const 0))
+           (func $f1 (export "f1") (result i32) (i32.const 1))
+           (func $f2 (export "f2") (result i32) (i32.const 2))
+           (func $f3 (export "f3") (result i32) (i32.const 3))
+           (func $f4 (export "f4") (result i32) (i32.const 4))
+           (func $f5 (export "f5") (result i32) (i32.const 5))
+           (func $f6 (export "f6") (result i32) (i32.const 6))
+           (func $f7 (export "f7") (result i32) (i32.const 7))
+           (func $f8 (export "f8") (result i32) (i32.const 8))
+           (func $f9 (export "f9") (result i32) (i32.const 9))
+           (func $f10 (export "f10") (result i32) (i32.const 10))
+           (func $f11 (export "f11") (result i32) (i32.const 11))
+           (func $f12 (export "f12") (result i32) (i32.const 12))
+           (func $f13 (export "f13") (result i32) (i32.const 13))
+           (func $f14 (export "f14") (result i32) (i32.const 14))
+           (func $f15 (export "f15") (result i32) (i32.const 15))
+           (func (export "test") (param $n i32) (result i32)
+             (call_indirect (type 0) (local.get $n)))
+           (func (export "run") (param $offs i32) (param $len i32)
+             (table.init 0 (local.get $offs) (i32.const 0) (local.get $len))))
+(assert_trap (invoke "run" (i32.const 24) (i32.const 16)) "out of bounds")
+(assert_return (invoke "test" (i32.const 24)) (i32.const 0))
+(assert_return (invoke "test" (i32.const 25)) (i32.const 1))
+(assert_return (invoke "test" (i32.const 26)) (i32.const 2))
+(assert_return (invoke "test" (i32.const 27)) (i32.const 3))
+(assert_return (invoke "test" (i32.const 28)) (i32.const 4))
+(assert_return (invoke "test" (i32.const 29)) (i32.const 5))
+(assert_return (invoke "test" (i32.const 30)) (i32.const 6))
+(assert_return (invoke "test" (i32.const 31)) (i32.const 7))
+(assert_trap (invoke "test" (i32.const 0)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 1)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 2)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 3)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 4)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 5)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 6)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 7)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 8)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 9)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 10)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 11)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 12)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 13)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 14)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 15)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 16)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 17)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 18)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 19)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 20)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 21)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 22)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 23)) "uninitialized element")
+(module
+           (type (func (result i32)))
+           (table 32 64 funcref)
+           (elem passive $f0 $f1 $f2 $f3 $f4 $f5 $f6 $f7 $f8 $f9 $f10 $f11 $f12 $f13 $f14 $f15)
+           (func $f0 (export "f0") (result i32) (i32.const 0))
+           (func $f1 (export "f1") (result i32) (i32.const 1))
+           (func $f2 (export "f2") (result i32) (i32.const 2))
+           (func $f3 (export "f3") (result i32) (i32.const 3))
+           (func $f4 (export "f4") (result i32) (i32.const 4))
+           (func $f5 (export "f5") (result i32) (i32.const 5))
+           (func $f6 (export "f6") (result i32) (i32.const 6))
+           (func $f7 (export "f7") (result i32) (i32.const 7))
+           (func $f8 (export "f8") (result i32) (i32.const 8))
+           (func $f9 (export "f9") (result i32) (i32.const 9))
+           (func $f10 (export "f10") (result i32) (i32.const 10))
+           (func $f11 (export "f11") (result i32) (i32.const 11))
+           (func $f12 (export "f12") (result i32) (i32.const 12))
+           (func $f13 (export "f13") (result i32) (i32.const 13))
+           (func $f14 (export "f14") (result i32) (i32.const 14))
+           (func $f15 (export "f15") (result i32) (i32.const 15))
+           (func (export "test") (param $n i32) (result i32)
+             (call_indirect (type 0) (local.get $n)))
+           (func (export "run") (param $offs i32) (param $len i32)
+             (table.init 0 (local.get $offs) (i32.const 0) (local.get $len))))
+(assert_trap (invoke "run" (i32.const 25) (i32.const 16)) "out of bounds")
+(assert_return (invoke "test" (i32.const 25)) (i32.const 0))
+(assert_return (invoke "test" (i32.const 26)) (i32.const 1))
+(assert_return (invoke "test" (i32.const 27)) (i32.const 2))
+(assert_return (invoke "test" (i32.const 28)) (i32.const 3))
+(assert_return (invoke "test" (i32.const 29)) (i32.const 4))
+(assert_return (invoke "test" (i32.const 30)) (i32.const 5))
+(assert_return (invoke "test" (i32.const 31)) (i32.const 6))
+(assert_trap (invoke "test" (i32.const 0)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 1)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 2)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 3)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 4)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 5)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 6)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 7)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 8)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 9)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 10)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 11)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 12)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 13)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 14)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 15)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 16)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 17)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 18)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 19)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 20)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 21)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 22)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 23)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 24)) "uninitialized element")
+(module
+           (type (func (result i32)))
+           (table 160 320 funcref)
+           (elem passive $f0 $f1 $f2 $f3 $f4 $f5 $f6 $f7 $f8 $f9 $f10 $f11 $f12 $f13 $f14 $f15)
+           (func $f0 (export "f0") (result i32) (i32.const 0))
+           (func $f1 (export "f1") (result i32) (i32.const 1))
+           (func $f2 (export "f2") (result i32) (i32.const 2))
+           (func $f3 (export "f3") (result i32) (i32.const 3))
+           (func $f4 (export "f4") (result i32) (i32.const 4))
+           (func $f5 (export "f5") (result i32) (i32.const 5))
+           (func $f6 (export "f6") (result i32) (i32.const 6))
+           (func $f7 (export "f7") (result i32) (i32.const 7))
+           (func $f8 (export "f8") (result i32) (i32.const 8))
+           (func $f9 (export "f9") (result i32) (i32.const 9))
+           (func $f10 (export "f10") (result i32) (i32.const 10))
+           (func $f11 (export "f11") (result i32) (i32.const 11))
+           (func $f12 (export "f12") (result i32) (i32.const 12))
+           (func $f13 (export "f13") (result i32) (i32.const 13))
+           (func $f14 (export "f14") (result i32) (i32.const 14))
+           (func $f15 (export "f15") (result i32) (i32.const 15))
+           (func (export "test") (param $n i32) (result i32)
+             (call_indirect (type 0) (local.get $n)))
+           (func (export "run") (param $offs i32) (param $len i32)
+             (table.init 0 (local.get $offs) (i32.const 0) (local.get $len))))
+(assert_trap (invoke "run" (i32.const 96) (i32.const 32)) "out of bounds")
+(assert_return (invoke "test" (i32.const 96)) (i32.const 0))
+(assert_return (invoke "test" (i32.const 97)) (i32.const 1))
+(assert_return (invoke "test" (i32.const 98)) (i32.const 2))
+(assert_return (invoke "test" (i32.const 99)) (i32.const 3))
+(assert_return (invoke "test" (i32.const 100)) (i32.const 4))
+(assert_return (invoke "test" (i32.const 101)) (i32.const 5))
+(assert_return (invoke "test" (i32.const 102)) (i32.const 6))
+(assert_return (invoke "test" (i32.const 103)) (i32.const 7))
+(assert_return (invoke "test" (i32.const 104)) (i32.const 8))
+(assert_return (invoke "test" (i32.const 105)) (i32.const 9))
+(assert_return (invoke "test" (i32.const 106)) (i32.const 10))
+(assert_return (invoke "test" (i32.const 107)) (i32.const 11))
+(assert_return (invoke "test" (i32.const 108)) (i32.const 12))
+(assert_return (invoke "test" (i32.const 109)) (i32.const 13))
+(assert_return (invoke "test" (i32.const 110)) (i32.const 14))
+(assert_return (invoke "test" (i32.const 111)) (i32.const 15))
+(assert_trap (invoke "test" (i32.const 112)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 113)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 114)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 115)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 116)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 117)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 118)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 119)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 120)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 121)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 122)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 123)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 124)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 125)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 126)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 127)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 128)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 129)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 130)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 131)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 132)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 133)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 134)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 135)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 136)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 137)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 138)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 139)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 140)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 141)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 142)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 143)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 144)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 145)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 146)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 147)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 148)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 149)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 150)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 151)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 152)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 153)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 154)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 155)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 156)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 157)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 158)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 159)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 0)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 1)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 2)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 3)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 4)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 5)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 6)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 7)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 8)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 9)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 10)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 11)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 12)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 13)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 14)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 15)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 16)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 17)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 18)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 19)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 20)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 21)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 22)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 23)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 24)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 25)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 26)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 27)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 28)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 29)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 30)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 31)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 32)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 33)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 34)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 35)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 36)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 37)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 38)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 39)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 40)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 41)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 42)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 43)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 44)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 45)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 46)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 47)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 48)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 49)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 50)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 51)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 52)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 53)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 54)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 55)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 56)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 57)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 58)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 59)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 60)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 61)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 62)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 63)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 64)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 65)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 66)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 67)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 68)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 69)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 70)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 71)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 72)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 73)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 74)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 75)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 76)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 77)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 78)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 79)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 80)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 81)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 82)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 83)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 84)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 85)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 86)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 87)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 88)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 89)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 90)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 91)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 92)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 93)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 94)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 95)) "uninitialized element")
+(module
+           (type (func (result i32)))
+           (table 160 320 funcref)
+           (elem passive $f0 $f1 $f2 $f3 $f4 $f5 $f6 $f7 $f8 $f9 $f10 $f11 $f12 $f13 $f14 $f15)
+           (func $f0 (export "f0") (result i32) (i32.const 0))
+           (func $f1 (export "f1") (result i32) (i32.const 1))
+           (func $f2 (export "f2") (result i32) (i32.const 2))
+           (func $f3 (export "f3") (result i32) (i32.const 3))
+           (func $f4 (export "f4") (result i32) (i32.const 4))
+           (func $f5 (export "f5") (result i32) (i32.const 5))
+           (func $f6 (export "f6") (result i32) (i32.const 6))
+           (func $f7 (export "f7") (result i32) (i32.const 7))
+           (func $f8 (export "f8") (result i32) (i32.const 8))
+           (func $f9 (export "f9") (result i32) (i32.const 9))
+           (func $f10 (export "f10") (result i32) (i32.const 10))
+           (func $f11 (export "f11") (result i32) (i32.const 11))
+           (func $f12 (export "f12") (result i32) (i32.const 12))
+           (func $f13 (export "f13") (result i32) (i32.const 13))
+           (func $f14 (export "f14") (result i32) (i32.const 14))
+           (func $f15 (export "f15") (result i32) (i32.const 15))
+           (func (export "test") (param $n i32) (result i32)
+             (call_indirect (type 0) (local.get $n)))
+           (func (export "run") (param $offs i32) (param $len i32)
+             (table.init 0 (local.get $offs) (i32.const 0) (local.get $len))))
+(assert_trap (invoke "run" (i32.const 97) (i32.const 31)) "out of bounds")
+(assert_return (invoke "test" (i32.const 97)) (i32.const 0))
+(assert_return (invoke "test" (i32.const 98)) (i32.const 1))
+(assert_return (invoke "test" (i32.const 99)) (i32.const 2))
+(assert_return (invoke "test" (i32.const 100)) (i32.const 3))
+(assert_return (invoke "test" (i32.const 101)) (i32.const 4))
+(assert_return (invoke "test" (i32.const 102)) (i32.const 5))
+(assert_return (invoke "test" (i32.const 103)) (i32.const 6))
+(assert_return (invoke "test" (i32.const 104)) (i32.const 7))
+(assert_return (invoke "test" (i32.const 105)) (i32.const 8))
+(assert_return (invoke "test" (i32.const 106)) (i32.const 9))
+(assert_return (invoke "test" (i32.const 107)) (i32.const 10))
+(assert_return (invoke "test" (i32.const 108)) (i32.const 11))
+(assert_return (invoke "test" (i32.const 109)) (i32.const 12))
+(assert_return (invoke "test" (i32.const 110)) (i32.const 13))
+(assert_return (invoke "test" (i32.const 111)) (i32.const 14))
+(assert_return (invoke "test" (i32.const 112)) (i32.const 15))
+(assert_trap (invoke "test" (i32.const 113)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 114)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 115)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 116)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 117)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 118)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 119)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 120)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 121)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 122)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 123)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 124)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 125)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 126)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 127)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 128)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 129)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 130)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 131)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 132)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 133)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 134)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 135)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 136)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 137)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 138)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 139)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 140)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 141)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 142)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 143)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 144)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 145)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 146)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 147)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 148)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 149)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 150)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 151)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 152)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 153)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 154)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 155)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 156)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 157)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 158)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 159)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 0)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 1)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 2)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 3)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 4)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 5)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 6)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 7)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 8)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 9)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 10)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 11)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 12)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 13)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 14)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 15)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 16)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 17)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 18)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 19)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 20)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 21)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 22)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 23)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 24)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 25)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 26)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 27)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 28)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 29)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 30)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 31)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 32)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 33)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 34)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 35)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 36)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 37)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 38)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 39)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 40)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 41)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 42)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 43)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 44)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 45)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 46)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 47)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 48)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 49)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 50)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 51)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 52)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 53)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 54)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 55)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 56)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 57)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 58)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 59)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 60)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 61)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 62)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 63)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 64)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 65)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 66)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 67)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 68)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 69)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 70)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 71)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 72)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 73)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 74)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 75)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 76)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 77)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 78)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 79)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 80)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 81)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 82)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 83)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 84)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 85)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 86)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 87)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 88)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 89)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 90)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 91)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 92)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 93)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 94)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 95)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 96)) "uninitialized element")
+(module
+           (type (func (result i32)))
+           (table 64 64 funcref)
+           (elem passive $f0 $f1 $f2 $f3 $f4 $f5 $f6 $f7 $f8 $f9 $f10 $f11 $f12 $f13 $f14 $f15)
+           (func $f0 (export "f0") (result i32) (i32.const 0))
+           (func $f1 (export "f1") (result i32) (i32.const 1))
+           (func $f2 (export "f2") (result i32) (i32.const 2))
+           (func $f3 (export "f3") (result i32) (i32.const 3))
+           (func $f4 (export "f4") (result i32) (i32.const 4))
+           (func $f5 (export "f5") (result i32) (i32.const 5))
+           (func $f6 (export "f6") (result i32) (i32.const 6))
+           (func $f7 (export "f7") (result i32) (i32.const 7))
+           (func $f8 (export "f8") (result i32) (i32.const 8))
+           (func $f9 (export "f9") (result i32) (i32.const 9))
+           (func $f10 (export "f10") (result i32) (i32.const 10))
+           (func $f11 (export "f11") (result i32) (i32.const 11))
+           (func $f12 (export "f12") (result i32) (i32.const 12))
+           (func $f13 (export "f13") (result i32) (i32.const 13))
+           (func $f14 (export "f14") (result i32) (i32.const 14))
+           (func $f15 (export "f15") (result i32) (i32.const 15))
+           (func (export "test") (param $n i32) (result i32)
+             (call_indirect (type 0) (local.get $n)))
+           (func (export "run") (param $offs i32) (param $len i32)
+             (table.init 0 (local.get $offs) (i32.const 0) (local.get $len))))
+(assert_trap (invoke "run" (i32.const 48) (i32.const 4294967280)) "out of bounds")
+(assert_return (invoke "test" (i32.const 48)) (i32.const 0))
+(assert_return (invoke "test" (i32.const 49)) (i32.const 1))
+(assert_return (invoke "test" (i32.const 50)) (i32.const 2))
+(assert_return (invoke "test" (i32.const 51)) (i32.const 3))
+(assert_return (invoke "test" (i32.const 52)) (i32.const 4))
+(assert_return (invoke "test" (i32.const 53)) (i32.const 5))
+(assert_return (invoke "test" (i32.const 54)) (i32.const 6))
+(assert_return (invoke "test" (i32.const 55)) (i32.const 7))
+(assert_return (invoke "test" (i32.const 56)) (i32.const 8))
+(assert_return (invoke "test" (i32.const 57)) (i32.const 9))
+(assert_return (invoke "test" (i32.const 58)) (i32.const 10))
+(assert_return (invoke "test" (i32.const 59)) (i32.const 11))
+(assert_return (invoke "test" (i32.const 60)) (i32.const 12))
+(assert_return (invoke "test" (i32.const 61)) (i32.const 13))
+(assert_return (invoke "test" (i32.const 62)) (i32.const 14))
+(assert_return (invoke "test" (i32.const 63)) (i32.const 15))
+(assert_trap (invoke "test" (i32.const 0)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 1)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 2)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 3)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 4)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 5)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 6)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 7)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 8)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 9)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 10)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 11)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 12)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 13)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 14)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 15)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 16)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 17)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 18)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 19)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 20)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 21)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 22)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 23)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 24)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 25)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 26)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 27)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 28)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 29)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 30)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 31)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 32)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 33)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 34)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 35)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 36)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 37)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 38)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 39)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 40)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 41)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 42)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 43)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 44)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 45)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 46)) "uninitialized element")
+(assert_trap (invoke "test" (i32.const 47)) "uninitialized element")
+(module
+           (type (func (result i32)))
+           (table 16 16 funcref)
+           (elem passive $f0 $f1 $f2 $f3 $f4 $f5 $f6 $f7 $f8 $f9 $f10 $f11 $f12 $f13 $f14 $f15)
+           (func $f0 (export "f0") (result i32) (i32.const 0))
+           (func $f1 (export "f1") (result i32) (i32.const 1))
+           (func $f2 (export "f2") (result i32) (i32.const 2))
+           (func $f3 (export "f3") (result i32) (i32.const 3))
+           (func $f4 (export "f4") (result i32) (i32.const 4))
+           (func $f5 (export "f5") (result i32) (i32.const 5))
+           (func $f6 (export "f6") (result i32) (i32.const 6))
+           (func $f7 (export "f7") (result i32) (i32.const 7))
+           (func $f8 (export "f8") (result i32) (i32.const 8))
+           (func $f9 (export "f9") (result i32) (i32.const 9))
+           (func $f10 (export "f10") (result i32) (i32.const 10))
+           (func $f11 (export "f11") (result i32) (i32.const 11))
+           (func $f12 (export "f12") (result i32) (i32.const 12))
+           (func $f13 (export "f13") (result i32) (i32.const 13))
+           (func $f14 (export "f14") (result i32) (i32.const 14))
+           (func $f15 (export "f15") (result i32) (i32.const 15))
+           (func (export "test") (param $n i32) (result i32)
+             (call_indirect (type 0) (local.get $n)))
+           (func (export "run") (param $offs i32) (param $len i32)
+             (table.init 0 (local.get $offs) (i32.const 8) (local.get $len))))
+(assert_trap (invoke "run" (i32.const 0) (i32.const 4294967292)) "out of bounds")
+(assert_return (invoke "test" (i32.const 0)) (i32.const 8))
+(assert_return (invoke "test" (i32.const 1)) (i32.const 9))
+(assert_return (invoke "test" (i32.const 2)) (i32.const 10))
+(assert_return (invoke "test" (i32.const 3)) (i32.const 11))
+(assert_return (invoke "test" (i32.const 4)) (i32.const 12))
+(assert_return (invoke "test" (i32.const 5)) (i32.const 13))
+(assert_return (invoke "test" (i32.const 6)) (i32.const 14))
+(assert_return (invoke "test" (i32.const 7)) (i32.const 15))
diff --git a/test/meta/Makefile b/test/meta/Makefile
new file mode 100644
index 0000000000..11c8c0cad1
--- /dev/null
+++ b/test/meta/Makefile
@@ -0,0 +1,27 @@
+# SpiderMonkey shell
+JSSHELL=~/m-i/js/src/build-debug/dist/bin/js -e 'const WITH_SHARED_MEMORY=false;' -f common.js
+
+TARGETDIR=../core
+
+.PHONY: all
+
+all: $(TARGETDIR)/memory_copy.wast \
+	$(TARGETDIR)/memory_init.wast \
+	$(TARGETDIR)/memory_fill.wast \
+	$(TARGETDIR)/table_copy.wast \
+	$(TARGETDIR)/table_init.wast
+
+$(TARGETDIR)/memory_copy.wast: generate_memory_copy.js common.js Makefile
+	$(JSSHELL) $< > $@
+
+$(TARGETDIR)/memory_init.wast: generate_memory_init.js common.js Makefile
+	$(JSSHELL) $< > $@
+
+$(TARGETDIR)/memory_fill.wast: generate_memory_fill.js common.js Makefile
+	$(JSSHELL) $< > $@
+
+$(TARGETDIR)/table_copy.wast: generate_table_copy.js common.js Makefile
+	$(JSSHELL) $< > $@
+
+$(TARGETDIR)/table_init.wast: generate_table_init.js common.js Makefile
+	$(JSSHELL) $< > $@
diff --git a/test/meta/README.md b/test/meta/README.md
new file mode 100644
index 0000000000..aeaf790251
--- /dev/null
+++ b/test/meta/README.md
@@ -0,0 +1 @@
+These programs generate test cases.  See Makefile for details.
diff --git a/test/meta/common.js b/test/meta/common.js
new file mode 100644
index 0000000000..151eb4adfe
--- /dev/null
+++ b/test/meta/common.js
@@ -0,0 +1,36 @@
+// WITH_SHARED_MEMORY can be overridden in a preamble, see `Makefile`.
+//
+// Set WITH_SHARED_MEMORY to true to get additional testing on memory backed by
+// SharedArrayBuffer.
+if (typeof this.WITH_SHARED_MEMORY == "undefined") {
+    this.WITH_SHARED_MEMORY = false;
+}
+
+const PAGESIZE = 65536;
+
+function print_origin(origin) {
+    print(";;");
+    print(";; Generated by ../meta/" + origin);
+    print(";;");
+}
+
+function checkRangeCode() {
+    return `
+  (func (export "checkRange") (param $from i32) (param $to i32) (param $expected i32) (result i32)
+   (loop $cont
+     (if (i32.eq (local.get $from) (local.get $to))
+         (then
+           (return (i32.const -1))))
+     (if (i32.eq (i32.load8_u (local.get $from)) (local.get $expected))
+         (then
+           (local.set $from (i32.add (local.get $from) (i32.const 1)))
+           (br $cont))))
+   (return (local.get $from)))
+`;
+}
+
+function checkRange(from, to, expected) {
+    print(
+`(assert_return (invoke "checkRange" (i32.const ${from}) (i32.const ${to}) (i32.const ${expected}))
+               (i32.const -1))`);
+}
diff --git a/test/meta/generate_memory_copy.js b/test/meta/generate_memory_copy.js
new file mode 100644
index 0000000000..f64f0d77b6
--- /dev/null
+++ b/test/meta/generate_memory_copy.js
@@ -0,0 +1,764 @@
+// This program generates .wast code that contains all the spec tests for
+// memory.copy.  See `Makefile`.
+
+print_origin("generate_memory_copy.js");
+
+// In-bounds tests.
+
+function mem_test(instruction, expected_result_vector) {
+    print(
+`
+(module
+  (memory (export "memory0") 1 1)
+  (data (i32.const 2) "\\03\\01\\04\\01")
+  (data (i32.const 12) "\\07\\05\\02\\03\\06")
+  (func (export "test")
+    ${instruction})
+  (func (export "load8_u") (param i32) (result i32)
+    (i32.load8_u (local.get 0))))
+
+(invoke "test")
+`);
+    for (let i = 0; i < expected_result_vector.length; i++) {
+        print(`(assert_return (invoke "load8_u" (i32.const ${i})) (i32.const ${expected_result_vector[i]}))`);
+    }
+}
+
+const e = 0;
+
+// This just gives the initial state of the memory, with its active
+// initialisers applied.
+mem_test("nop",
+         [e,e,3,1,4, 1,e,e,e,e, e,e,7,5,2, 3,6,e,e,e, e,e,e,e,e, e,e,e,e,e]);
+
+// Copy non-zero over non-zero
+mem_test("(memory.copy (i32.const 13) (i32.const 2) (i32.const 3))",
+         [e,e,3,1,4, 1,e,e,e,e, e,e,7,3,1, 4,6,e,e,e, e,e,e,e,e, e,e,e,e,e]);
+
+// Copy non-zero over zero
+mem_test("(memory.copy (i32.const 25) (i32.const 15) (i32.const 2))",
+         [e,e,3,1,4, 1,e,e,e,e, e,e,7,5,2, 3,6,e,e,e, e,e,e,e,e, 3,6,e,e,e]);
+
+// Copy zero over non-zero
+mem_test("(memory.copy (i32.const 13) (i32.const 25) (i32.const 3))",
+         [e,e,3,1,4, 1,e,e,e,e, e,e,7,e,e, e,6,e,e,e, e,e,e,e,e, e,e,e,e,e]);
+
+// Copy zero over zero
+mem_test("(memory.copy (i32.const 20) (i32.const 22) (i32.const 4))",
+         [e,e,3,1,4, 1,e,e,e,e, e,e,7,5,2, 3,6,e,e,e, e,e,e,e,e, e,e,e,e,e]);
+
+// Copy zero and non-zero entries, non overlapping
+mem_test("(memory.copy (i32.const 25) (i32.const 1) (i32.const 3))",
+         [e,e,3,1,4, 1,e,e,e,e, e,e,7,5,2, 3,6,e,e,e, e,e,e,e,e, e,3,1,e,e]);
+
+// Copy zero and non-zero entries, overlapping, backwards
+mem_test("(memory.copy (i32.const 10) (i32.const 12) (i32.const 7))",
+         [e,e,3,1,4, 1,e,e,e,e, 7,5,2,3,6, e,e,e,e,e, e,e,e,e,e, e,e,e,e,e]);
+
+// Copy zero and non-zero entries, overlapping, forwards
+mem_test("(memory.copy (i32.const 12) (i32.const 10) (i32.const 7))",
+         [e,e,3,1,4, 1,e,e,e,e, e,e,e,e,7, 5,2,3,6,e, e,e,e,e,e, e,e,e,e,e]);
+
+// Out-of-bounds tests.
+//
+// The operation is out of bounds of the memory for the source or target, but
+// must perform the operation up to the appropriate bound.  Major cases:
+//
+// - non-overlapping regions
+// - overlapping regions with src >= dest
+// - overlapping regions with src == dest
+// - overlapping regions with src < dest
+// - arithmetic overflow on src addresses
+// - arithmetic overflow on target addresses
+//
+// for each of those,
+//
+// - src address oob
+// - target address oob
+// - both oob
+
+function initializers(count, startingAt) {
+    let s = "";
+    for ( let i=0, j=startingAt; i < count; i++, j++ )
+        s += "\\" + (i + 256).toString(16).substring(1);
+    return s;
+}
+
+function mem_copy(min, max, shared, srcOffs, targetOffs, len, copyDown=false) {
+    let memLength = min * PAGESIZE;
+    let targetAvail = memLength - targetOffs;
+    let srcAvail = memLength - srcOffs;
+    let targetLim = targetOffs + Math.min(len, targetAvail, srcAvail);
+    let srcLim = srcOffs + Math.min(len, targetAvail, srcAvail);
+
+    print(
+`
+(module
+  (memory (export "mem") ${min} ${max} ${shared})
+  (data (i32.const ${srcOffs}) "${initializers(srcLim - srcOffs, 0)}")
+  (func (export "run") (param $targetOffs i32) (param $srcOffs i32) (param $len i32)
+    (memory.copy (local.get $targetOffs) (local.get $srcOffs) (local.get $len)))
+  (func (export "load8_u") (param i32) (result i32)
+    (i32.load8_u (local.get 0))))
+
+(assert_trap (invoke "run" (i32.const ${targetOffs}) (i32.const ${srcOffs}) (i32.const ${len}))
+             "out of bounds")
+`);
+
+    let immediateOOB = copyDown && (srcOffs + len > memLength || targetOffs + len > memLength);
+
+    var t = 0;
+    var s = 0;
+    var i = 0;
+    function checkTarget() {
+        if (i >= targetOffs && i < targetLim) {
+            print(`(assert_return (invoke "load8_u" (i32.const ${i})) (i32.const ${(t++) & 0xFF}))`);
+            if (i >= srcOffs && i < srcLim)
+                s++;
+            return true;
+        }
+        return false;
+    }
+    function checkSource() {
+        if (i >= srcOffs && i < srcLim) {
+            print(`(assert_return (invoke "load8_u" (i32.const ${i})) (i32.const ${(s++) & 0xFF}))`);
+            if (i >= targetOffs && i < targetLim)
+                t++;
+            return true;
+        }
+        return false;
+    }
+
+    let k = 0;
+    for (i=0; i < memLength; i++ ) {
+        if (immediateOOB) {
+            if (checkSource())
+                continue;
+        } else {
+            if (copyDown && (checkSource() || checkTarget()))
+                continue;
+            if (!copyDown && (checkTarget() || checkSource()))
+                continue;
+        }
+        // Only spot-check for zero, or we'll be here all night.
+        if (++k == 199) {
+            print(`(assert_return (invoke "load8_u" (i32.const ${i})) (i32.const 0))`);
+            k = 0;
+        }
+    }
+}
+
+// OOB target address, nonoverlapping
+mem_copy(1, 1, "", 0, PAGESIZE-20, 40);
+mem_copy(1, 1, "", 0, PAGESIZE-21, 39);
+if (WITH_SHARED_MEMORY) {
+    mem_copy(2, 4, "shared", 0, 2*PAGESIZE-20, 40);
+    mem_copy(2, 4, "shared", 0, 2*PAGESIZE-21, 39);
+}
+
+// OOB source address, nonoverlapping
+mem_copy(1, 1, "", PAGESIZE-20, 0, 40);
+mem_copy(1, 1, "", PAGESIZE-21, 0, 39);
+if (WITH_SHARED_MEMORY) {
+    mem_copy(2, 4, "shared", 2*PAGESIZE-20, 0, 40);
+    mem_copy(2, 4, "shared", 2*PAGESIZE-21, 0, 39);
+}
+
+// OOB target address, overlapping, src < target
+mem_copy(1, 1, "", PAGESIZE-50, PAGESIZE-20, 40, true);
+
+// OOB source address, overlapping, target < src
+mem_copy(1, 1, "", PAGESIZE-20, PAGESIZE-50, 40);
+
+// OOB both, overlapping, including target == src
+mem_copy(1, 1, "", PAGESIZE-30, PAGESIZE-20, 40, true);
+mem_copy(1, 1, "", PAGESIZE-20, PAGESIZE-30, 40);
+mem_copy(1, 1, "", PAGESIZE-20, PAGESIZE-20, 40);
+
+// Arithmetic overflow on source address.
+mem_copy(1, "", "", PAGESIZE-20, 0, 0xFFFFF000);
+
+// Arithmetic overflow on target adddress is an overlapping case.
+mem_copy(1, 1, "", PAGESIZE-0x1000, PAGESIZE-20, 0xFFFFFF00, true);
+
+// Sundry compilation failures.
+
+// Module doesn't have a memory.
+print(
+`
+(assert_invalid
+  (module
+    (func (export "testfn")
+      (memory.copy (i32.const 10) (i32.const 20) (i32.const 30))))
+  "unknown memory 0")
+`);
+
+// Invalid argument types.  TODO: We can add anyref, funcref, etc here.
+{
+    const tys = ['i32', 'f32', 'i64', 'f64'];
+    for (let ty1 of tys) {
+    for (let ty2 of tys) {
+    for (let ty3 of tys) {
+        if (ty1 == 'i32' && ty2 == 'i32' && ty3 == 'i32')
+            continue;  // this is the only valid case
+        print(
+`
+(assert_invalid
+  (module
+    (memory 1 1)
+    (func (export "testfn")
+      (memory.copy (${ty1}.const 10) (${ty2}.const 20) (${ty3}.const 30))))
+  "type mismatch")
+`);
+    }}}
+}
+
+// Both ranges valid.  Copy 5 bytes backwards by 1 (overlapping).
+// result = 0x00--(09) 0x55--(11) 0x00--(pagesize-20)
+print(
+`
+(module
+  (memory 1 1)
+  (func (export "test")
+    (memory.fill (i32.const 10) (i32.const 0x55) (i32.const 10))
+    (memory.copy (i32.const 9) (i32.const 10) (i32.const 5)))
+  ${checkRangeCode()})
+(invoke "test")
+`);
+checkRange(0,    0+9,     0x00);
+checkRange(9,    9+11,    0x55);
+checkRange(9+11, 0x10000, 0x00);
+
+// Both ranges valid.  Copy 5 bytes forwards by 1 (overlapping).
+// result = 0x00--(10) 0x55--(11) 0x00--(pagesize-19)
+print(
+`
+(module
+  (memory 1 1)
+  (func (export "test")
+    (memory.fill (i32.const 10) (i32.const 0x55) (i32.const 10))
+    (memory.copy (i32.const 16) (i32.const 15) (i32.const 5)))
+  ${checkRangeCode()})
+(invoke "test")
+`);
+checkRange(0,     0+10,    0x00);
+checkRange(10,    10+11,   0x55);
+checkRange(10+11, 0x10000, 0x00);
+
+// Destination range invalid
+print(
+`
+(module
+  (memory 1 1)
+  (func (export "test")
+    (memory.copy (i32.const 0xFF00) (i32.const 0x8000) (i32.const 257))))
+(assert_trap (invoke "test") "out of bounds")
+`);
+
+// Destination wraparound the end of 32-bit offset space
+print(
+`
+(module
+  (memory 1 1)
+  (func (export "test")
+    (memory.copy (i32.const 0xFFFFFF00) (i32.const 0x4000) (i32.const 257))))
+(assert_trap (invoke "test") "out of bounds")
+`);
+
+// Source range invalid
+print(
+`
+(module
+  (memory 1 1)
+  (func (export "test")
+    (memory.copy (i32.const 0x8000) (i32.const 0xFF00) (i32.const 257))))
+(assert_trap (invoke "test") "out of bounds")
+`);
+
+// Source wraparound the end of 32-bit offset space
+print(
+`
+(module
+ (memory 1 1)
+ (func (export "test")
+   (memory.copy (i32.const 0x4000) (i32.const 0xFFFFFF00) (i32.const 257))))
+(assert_trap (invoke "test") "out of bounds")
+`);
+
+// Zero len with both offsets in-bounds is a no-op
+print(
+`
+(module
+  (memory 1 1)
+  (func (export "test")
+    (memory.fill (i32.const 0x0000) (i32.const 0x55) (i32.const 0x8000))
+    (memory.fill (i32.const 0x8000) (i32.const 0xAA) (i32.const 0x8000))
+    (memory.copy (i32.const 0x9000) (i32.const 0x7000) (i32.const 0)))
+  ${checkRangeCode()})
+(invoke "test")
+`);
+checkRange(0x00000, 0x08000, 0x55);
+checkRange(0x08000, 0x10000, 0xAA);
+
+// Zero len with dest offset out-of-bounds at the end of memory is allowed
+print(
+`
+(module
+  (memory 1 1)
+  (func (export "test")
+    (memory.copy (i32.const 0x10000) (i32.const 0x7000) (i32.const 0))))
+(invoke "test")
+`);
+
+// Zero len with src offset out-of-bounds at the end of memory is allowed
+print(
+`
+(module
+  (memory 1 1)
+  (func (export "test")
+    (memory.copy (i32.const 0x9000) (i32.const 0x10000) (i32.const 0))))
+(invoke "test")
+`);
+
+// 100 random fills followed by 100 random copies, in a single-page buffer,
+// followed by verification of the (now heavily mashed-around) buffer.
+print(
+`
+(module
+       (memory 1 1)
+       (func (export "test")
+         (memory.fill (i32.const 17767) (i32.const 1) (i32.const 1344))
+         (memory.fill (i32.const 39017) (i32.const 2) (i32.const 1055))
+         (memory.fill (i32.const 56401) (i32.const 3) (i32.const 988))
+         (memory.fill (i32.const 37962) (i32.const 4) (i32.const 322))
+         (memory.fill (i32.const 7977) (i32.const 5) (i32.const 1994))
+         (memory.fill (i32.const 22714) (i32.const 6) (i32.const 3036))
+         (memory.fill (i32.const 16882) (i32.const 7) (i32.const 2372))
+         (memory.fill (i32.const 43491) (i32.const 8) (i32.const 835))
+         (memory.fill (i32.const 124) (i32.const 9) (i32.const 1393))
+         (memory.fill (i32.const 2132) (i32.const 10) (i32.const 2758))
+         (memory.fill (i32.const 8987) (i32.const 11) (i32.const 3098))
+         (memory.fill (i32.const 52711) (i32.const 12) (i32.const 741))
+         (memory.fill (i32.const 3958) (i32.const 13) (i32.const 2823))
+         (memory.fill (i32.const 49715) (i32.const 14) (i32.const 1280))
+         (memory.fill (i32.const 50377) (i32.const 15) (i32.const 1466))
+         (memory.fill (i32.const 20493) (i32.const 16) (i32.const 3158))
+         (memory.fill (i32.const 47665) (i32.const 17) (i32.const 544))
+         (memory.fill (i32.const 12451) (i32.const 18) (i32.const 2669))
+         (memory.fill (i32.const 24869) (i32.const 19) (i32.const 2651))
+         (memory.fill (i32.const 45317) (i32.const 20) (i32.const 1570))
+         (memory.fill (i32.const 43096) (i32.const 21) (i32.const 1691))
+         (memory.fill (i32.const 33886) (i32.const 22) (i32.const 646))
+         (memory.fill (i32.const 48555) (i32.const 23) (i32.const 1858))
+         (memory.fill (i32.const 53453) (i32.const 24) (i32.const 2657))
+         (memory.fill (i32.const 30363) (i32.const 25) (i32.const 981))
+         (memory.fill (i32.const 9300) (i32.const 26) (i32.const 1807))
+         (memory.fill (i32.const 50190) (i32.const 27) (i32.const 487))
+         (memory.fill (i32.const 62753) (i32.const 28) (i32.const 530))
+         (memory.fill (i32.const 36316) (i32.const 29) (i32.const 943))
+         (memory.fill (i32.const 6768) (i32.const 30) (i32.const 381))
+         (memory.fill (i32.const 51262) (i32.const 31) (i32.const 3089))
+         (memory.fill (i32.const 49729) (i32.const 32) (i32.const 658))
+         (memory.fill (i32.const 44540) (i32.const 33) (i32.const 1702))
+         (memory.fill (i32.const 33342) (i32.const 34) (i32.const 1092))
+         (memory.fill (i32.const 50814) (i32.const 35) (i32.const 1410))
+         (memory.fill (i32.const 47594) (i32.const 36) (i32.const 2204))
+         (memory.fill (i32.const 54123) (i32.const 37) (i32.const 2394))
+         (memory.fill (i32.const 55183) (i32.const 38) (i32.const 250))
+         (memory.fill (i32.const 22620) (i32.const 39) (i32.const 2097))
+         (memory.fill (i32.const 17132) (i32.const 40) (i32.const 3264))
+         (memory.fill (i32.const 54331) (i32.const 41) (i32.const 3299))
+         (memory.fill (i32.const 39474) (i32.const 42) (i32.const 2796))
+         (memory.fill (i32.const 36156) (i32.const 43) (i32.const 2070))
+         (memory.fill (i32.const 35308) (i32.const 44) (i32.const 2763))
+         (memory.fill (i32.const 32731) (i32.const 45) (i32.const 312))
+         (memory.fill (i32.const 63746) (i32.const 46) (i32.const 192))
+         (memory.fill (i32.const 30974) (i32.const 47) (i32.const 596))
+         (memory.fill (i32.const 16635) (i32.const 48) (i32.const 501))
+         (memory.fill (i32.const 57002) (i32.const 49) (i32.const 686))
+         (memory.fill (i32.const 34299) (i32.const 50) (i32.const 385))
+         (memory.fill (i32.const 60881) (i32.const 51) (i32.const 903))
+         (memory.fill (i32.const 61445) (i32.const 52) (i32.const 2390))
+         (memory.fill (i32.const 46972) (i32.const 53) (i32.const 1441))
+         (memory.fill (i32.const 25973) (i32.const 54) (i32.const 3162))
+         (memory.fill (i32.const 5566) (i32.const 55) (i32.const 2135))
+         (memory.fill (i32.const 35977) (i32.const 56) (i32.const 519))
+         (memory.fill (i32.const 44892) (i32.const 57) (i32.const 3280))
+         (memory.fill (i32.const 46760) (i32.const 58) (i32.const 1678))
+         (memory.fill (i32.const 46607) (i32.const 59) (i32.const 3168))
+         (memory.fill (i32.const 22449) (i32.const 60) (i32.const 1441))
+         (memory.fill (i32.const 58609) (i32.const 61) (i32.const 663))
+         (memory.fill (i32.const 32261) (i32.const 62) (i32.const 1671))
+         (memory.fill (i32.const 3063) (i32.const 63) (i32.const 721))
+         (memory.fill (i32.const 34025) (i32.const 64) (i32.const 84))
+         (memory.fill (i32.const 33338) (i32.const 65) (i32.const 2029))
+         (memory.fill (i32.const 36810) (i32.const 66) (i32.const 29))
+         (memory.fill (i32.const 19147) (i32.const 67) (i32.const 3034))
+         (memory.fill (i32.const 12616) (i32.const 68) (i32.const 1043))
+         (memory.fill (i32.const 18276) (i32.const 69) (i32.const 3324))
+         (memory.fill (i32.const 4639) (i32.const 70) (i32.const 1091))
+         (memory.fill (i32.const 16158) (i32.const 71) (i32.const 1997))
+         (memory.fill (i32.const 18204) (i32.const 72) (i32.const 2259))
+         (memory.fill (i32.const 50532) (i32.const 73) (i32.const 3189))
+         (memory.fill (i32.const 11028) (i32.const 74) (i32.const 1968))
+         (memory.fill (i32.const 15962) (i32.const 75) (i32.const 1455))
+         (memory.fill (i32.const 45406) (i32.const 76) (i32.const 1177))
+         (memory.fill (i32.const 54137) (i32.const 77) (i32.const 1568))
+         (memory.fill (i32.const 33083) (i32.const 78) (i32.const 1642))
+         (memory.fill (i32.const 61028) (i32.const 79) (i32.const 3284))
+         (memory.fill (i32.const 51729) (i32.const 80) (i32.const 223))
+         (memory.fill (i32.const 4361) (i32.const 81) (i32.const 2171))
+         (memory.fill (i32.const 57514) (i32.const 82) (i32.const 1322))
+         (memory.fill (i32.const 55724) (i32.const 83) (i32.const 2648))
+         (memory.fill (i32.const 24091) (i32.const 84) (i32.const 1045))
+         (memory.fill (i32.const 43183) (i32.const 85) (i32.const 3097))
+         (memory.fill (i32.const 32307) (i32.const 86) (i32.const 2796))
+         (memory.fill (i32.const 3811) (i32.const 87) (i32.const 2010))
+         (memory.fill (i32.const 54856) (i32.const 88) (i32.const 0))
+         (memory.fill (i32.const 49941) (i32.const 89) (i32.const 2069))
+         (memory.fill (i32.const 20411) (i32.const 90) (i32.const 2896))
+         (memory.fill (i32.const 33826) (i32.const 91) (i32.const 192))
+         (memory.fill (i32.const 9402) (i32.const 92) (i32.const 2195))
+         (memory.fill (i32.const 12413) (i32.const 93) (i32.const 24))
+         (memory.fill (i32.const 14091) (i32.const 94) (i32.const 577))
+         (memory.fill (i32.const 44058) (i32.const 95) (i32.const 2089))
+         (memory.fill (i32.const 36735) (i32.const 96) (i32.const 3436))
+         (memory.fill (i32.const 23288) (i32.const 97) (i32.const 2765))
+         (memory.fill (i32.const 6392) (i32.const 98) (i32.const 830))
+         (memory.fill (i32.const 33307) (i32.const 99) (i32.const 1938))
+         (memory.fill (i32.const 21941) (i32.const 100) (i32.const 2750))
+         (memory.copy (i32.const 59214) (i32.const 54248) (i32.const 2098))
+         (memory.copy (i32.const 63026) (i32.const 39224) (i32.const 230))
+         (memory.copy (i32.const 51833) (i32.const 23629) (i32.const 2300))
+         (memory.copy (i32.const 6708) (i32.const 23996) (i32.const 639))
+         (memory.copy (i32.const 6990) (i32.const 33399) (i32.const 1097))
+         (memory.copy (i32.const 19403) (i32.const 10348) (i32.const 3197))
+         (memory.copy (i32.const 27308) (i32.const 54406) (i32.const 100))
+         (memory.copy (i32.const 27221) (i32.const 43682) (i32.const 1717))
+         (memory.copy (i32.const 60528) (i32.const 8629) (i32.const 119))
+         (memory.copy (i32.const 5947) (i32.const 2308) (i32.const 658))
+         (memory.copy (i32.const 4787) (i32.const 51631) (i32.const 2269))
+         (memory.copy (i32.const 12617) (i32.const 19197) (i32.const 833))
+         (memory.copy (i32.const 11854) (i32.const 46505) (i32.const 3300))
+         (memory.copy (i32.const 11376) (i32.const 45012) (i32.const 2281))
+         (memory.copy (i32.const 34186) (i32.const 6697) (i32.const 2572))
+         (memory.copy (i32.const 4936) (i32.const 1690) (i32.const 1328))
+         (memory.copy (i32.const 63164) (i32.const 7637) (i32.const 1670))
+         (memory.copy (i32.const 44568) (i32.const 18344) (i32.const 33))
+         (memory.copy (i32.const 43918) (i32.const 22348) (i32.const 1427))
+         (memory.copy (i32.const 46637) (i32.const 49819) (i32.const 1434))
+         (memory.copy (i32.const 63684) (i32.const 8755) (i32.const 834))
+         (memory.copy (i32.const 33485) (i32.const 20131) (i32.const 3317))
+         (memory.copy (i32.const 40575) (i32.const 54317) (i32.const 3201))
+         (memory.copy (i32.const 25812) (i32.const 59254) (i32.const 2452))
+         (memory.copy (i32.const 19678) (i32.const 56882) (i32.const 346))
+         (memory.copy (i32.const 15852) (i32.const 35914) (i32.const 2430))
+         (memory.copy (i32.const 11824) (i32.const 35574) (i32.const 300))
+         (memory.copy (i32.const 59427) (i32.const 13957) (i32.const 3153))
+         (memory.copy (i32.const 34299) (i32.const 60594) (i32.const 1281))
+         (memory.copy (i32.const 8964) (i32.const 12276) (i32.const 943))
+         (memory.copy (i32.const 2827) (i32.const 10425) (i32.const 1887))
+         (memory.copy (i32.const 43194) (i32.const 43910) (i32.const 738))
+         (memory.copy (i32.const 63038) (i32.const 18949) (i32.const 122))
+         (memory.copy (i32.const 24044) (i32.const 44761) (i32.const 1755))
+         (memory.copy (i32.const 22608) (i32.const 14755) (i32.const 702))
+         (memory.copy (i32.const 11284) (i32.const 26579) (i32.const 1830))
+         (memory.copy (i32.const 23092) (i32.const 20471) (i32.const 1064))
+         (memory.copy (i32.const 57248) (i32.const 54770) (i32.const 2631))
+         (memory.copy (i32.const 25492) (i32.const 1025) (i32.const 3113))
+         (memory.copy (i32.const 49588) (i32.const 44220) (i32.const 975))
+         (memory.copy (i32.const 28280) (i32.const 41722) (i32.const 2336))
+         (memory.copy (i32.const 61289) (i32.const 230) (i32.const 2872))
+         (memory.copy (i32.const 22480) (i32.const 52506) (i32.const 2197))
+         (memory.copy (i32.const 40553) (i32.const 9578) (i32.const 1958))
+         (memory.copy (i32.const 29004) (i32.const 20862) (i32.const 2186))
+         (memory.copy (i32.const 53029) (i32.const 43955) (i32.const 1037))
+         (memory.copy (i32.const 25476) (i32.const 35667) (i32.const 1650))
+         (memory.copy (i32.const 58516) (i32.const 45819) (i32.const 1986))
+         (memory.copy (i32.const 38297) (i32.const 5776) (i32.const 1955))
+         (memory.copy (i32.const 28503) (i32.const 55364) (i32.const 2368))
+         (memory.copy (i32.const 62619) (i32.const 18108) (i32.const 1356))
+         (memory.copy (i32.const 50149) (i32.const 13861) (i32.const 382))
+         (memory.copy (i32.const 16904) (i32.const 36341) (i32.const 1900))
+         (memory.copy (i32.const 48098) (i32.const 11358) (i32.const 2807))
+         (memory.copy (i32.const 28512) (i32.const 40362) (i32.const 323))
+         (memory.copy (i32.const 35506) (i32.const 27856) (i32.const 1670))
+         (memory.copy (i32.const 62970) (i32.const 53332) (i32.const 1341))
+         (memory.copy (i32.const 14133) (i32.const 46312) (i32.const 644))
+         (memory.copy (i32.const 29030) (i32.const 19074) (i32.const 496))
+         (memory.copy (i32.const 44952) (i32.const 47577) (i32.const 2784))
+         (memory.copy (i32.const 39559) (i32.const 44661) (i32.const 1350))
+         (memory.copy (i32.const 10352) (i32.const 29274) (i32.const 1475))
+         (memory.copy (i32.const 46911) (i32.const 46178) (i32.const 1467))
+         (memory.copy (i32.const 4905) (i32.const 28740) (i32.const 1895))
+         (memory.copy (i32.const 38012) (i32.const 57253) (i32.const 1751))
+         (memory.copy (i32.const 26446) (i32.const 27223) (i32.const 1127))
+         (memory.copy (i32.const 58835) (i32.const 24657) (i32.const 1063))
+         (memory.copy (i32.const 61356) (i32.const 38790) (i32.const 766))
+         (memory.copy (i32.const 44160) (i32.const 2284) (i32.const 1520))
+         (memory.copy (i32.const 32740) (i32.const 47237) (i32.const 3014))
+         (memory.copy (i32.const 11148) (i32.const 21260) (i32.const 1011))
+         (memory.copy (i32.const 7665) (i32.const 31612) (i32.const 3034))
+         (memory.copy (i32.const 18044) (i32.const 12987) (i32.const 3320))
+         (memory.copy (i32.const 57306) (i32.const 55905) (i32.const 308))
+         (memory.copy (i32.const 24675) (i32.const 16815) (i32.const 1155))
+         (memory.copy (i32.const 19900) (i32.const 10115) (i32.const 722))
+         (memory.copy (i32.const 2921) (i32.const 5935) (i32.const 2370))
+         (memory.copy (i32.const 32255) (i32.const 50095) (i32.const 2926))
+         (memory.copy (i32.const 15126) (i32.const 17299) (i32.const 2607))
+         (memory.copy (i32.const 45575) (i32.const 28447) (i32.const 2045))
+         (memory.copy (i32.const 55149) (i32.const 36113) (i32.const 2596))
+         (memory.copy (i32.const 28461) (i32.const 54157) (i32.const 1168))
+         (memory.copy (i32.const 47951) (i32.const 53385) (i32.const 3137))
+         (memory.copy (i32.const 30646) (i32.const 45155) (i32.const 2649))
+         (memory.copy (i32.const 5057) (i32.const 4295) (i32.const 52))
+         (memory.copy (i32.const 6692) (i32.const 24195) (i32.const 441))
+         (memory.copy (i32.const 32984) (i32.const 27117) (i32.const 3445))
+         (memory.copy (i32.const 32530) (i32.const 59372) (i32.const 2785))
+         (memory.copy (i32.const 34361) (i32.const 8962) (i32.const 2406))
+         (memory.copy (i32.const 17893) (i32.const 54538) (i32.const 3381))
+         (memory.copy (i32.const 22685) (i32.const 44151) (i32.const 136))
+         (memory.copy (i32.const 59089) (i32.const 7077) (i32.const 1045))
+         (memory.copy (i32.const 42945) (i32.const 55028) (i32.const 2389))
+         (memory.copy (i32.const 44693) (i32.const 20138) (i32.const 877))
+         (memory.copy (i32.const 36810) (i32.const 25196) (i32.const 3447))
+         (memory.copy (i32.const 45742) (i32.const 31888) (i32.const 854))
+         (memory.copy (i32.const 24236) (i32.const 31866) (i32.const 1377))
+         (memory.copy (i32.const 33778) (i32.const 692) (i32.const 1594))
+         (memory.copy (i32.const 60618) (i32.const 18585) (i32.const 2987))
+         (memory.copy (i32.const 50370) (i32.const 41271) (i32.const 1406))
+       )
+  ${checkRangeCode()})
+(invoke "test")
+`);
+checkRange(0, 124, 0);
+checkRange(124, 1517, 9);
+checkRange(1517, 2132, 0);
+checkRange(2132, 2827, 10);
+checkRange(2827, 2921, 92);
+checkRange(2921, 3538, 83);
+checkRange(3538, 3786, 77);
+checkRange(3786, 4042, 97);
+checkRange(4042, 4651, 99);
+checkRange(4651, 5057, 0);
+checkRange(5057, 5109, 99);
+checkRange(5109, 5291, 0);
+checkRange(5291, 5524, 72);
+checkRange(5524, 5691, 92);
+checkRange(5691, 6552, 83);
+checkRange(6552, 7133, 77);
+checkRange(7133, 7665, 99);
+checkRange(7665, 8314, 0);
+checkRange(8314, 8360, 62);
+checkRange(8360, 8793, 86);
+checkRange(8793, 8979, 83);
+checkRange(8979, 9373, 79);
+checkRange(9373, 9518, 95);
+checkRange(9518, 9934, 59);
+checkRange(9934, 10087, 77);
+checkRange(10087, 10206, 5);
+checkRange(10206, 10230, 77);
+checkRange(10230, 10249, 41);
+checkRange(10249, 11148, 83);
+checkRange(11148, 11356, 74);
+checkRange(11356, 11380, 93);
+checkRange(11380, 11939, 74);
+checkRange(11939, 12159, 68);
+checkRange(12159, 12575, 83);
+checkRange(12575, 12969, 79);
+checkRange(12969, 13114, 95);
+checkRange(13114, 14133, 59);
+checkRange(14133, 14404, 76);
+checkRange(14404, 14428, 57);
+checkRange(14428, 14458, 59);
+checkRange(14458, 14580, 32);
+checkRange(14580, 14777, 89);
+checkRange(14777, 15124, 59);
+checkRange(15124, 15126, 36);
+checkRange(15126, 15192, 100);
+checkRange(15192, 15871, 96);
+checkRange(15871, 15998, 95);
+checkRange(15998, 17017, 59);
+checkRange(17017, 17288, 76);
+checkRange(17288, 17312, 57);
+checkRange(17312, 17342, 59);
+checkRange(17342, 17464, 32);
+checkRange(17464, 17661, 89);
+checkRange(17661, 17727, 59);
+checkRange(17727, 17733, 5);
+checkRange(17733, 17893, 96);
+checkRange(17893, 18553, 77);
+checkRange(18553, 18744, 42);
+checkRange(18744, 18801, 76);
+checkRange(18801, 18825, 57);
+checkRange(18825, 18876, 59);
+checkRange(18876, 18885, 77);
+checkRange(18885, 18904, 41);
+checkRange(18904, 19567, 83);
+checkRange(19567, 20403, 96);
+checkRange(20403, 21274, 77);
+checkRange(21274, 21364, 100);
+checkRange(21364, 21468, 74);
+checkRange(21468, 21492, 93);
+checkRange(21492, 22051, 74);
+checkRange(22051, 22480, 68);
+checkRange(22480, 22685, 100);
+checkRange(22685, 22694, 68);
+checkRange(22694, 22821, 10);
+checkRange(22821, 22869, 100);
+checkRange(22869, 24107, 97);
+checkRange(24107, 24111, 37);
+checkRange(24111, 24236, 77);
+checkRange(24236, 24348, 72);
+checkRange(24348, 24515, 92);
+checkRange(24515, 24900, 83);
+checkRange(24900, 25136, 95);
+checkRange(25136, 25182, 85);
+checkRange(25182, 25426, 68);
+checkRange(25426, 25613, 89);
+checkRange(25613, 25830, 96);
+checkRange(25830, 26446, 100);
+checkRange(26446, 26517, 10);
+checkRange(26517, 27468, 92);
+checkRange(27468, 27503, 95);
+checkRange(27503, 27573, 77);
+checkRange(27573, 28245, 92);
+checkRange(28245, 28280, 95);
+checkRange(28280, 29502, 77);
+checkRange(29502, 29629, 42);
+checkRange(29629, 30387, 83);
+checkRange(30387, 30646, 77);
+checkRange(30646, 31066, 92);
+checkRange(31066, 31131, 77);
+checkRange(31131, 31322, 42);
+checkRange(31322, 31379, 76);
+checkRange(31379, 31403, 57);
+checkRange(31403, 31454, 59);
+checkRange(31454, 31463, 77);
+checkRange(31463, 31482, 41);
+checkRange(31482, 31649, 83);
+checkRange(31649, 31978, 72);
+checkRange(31978, 32145, 92);
+checkRange(32145, 32530, 83);
+checkRange(32530, 32766, 95);
+checkRange(32766, 32812, 85);
+checkRange(32812, 33056, 68);
+checkRange(33056, 33660, 89);
+checkRange(33660, 33752, 59);
+checkRange(33752, 33775, 36);
+checkRange(33775, 33778, 32);
+checkRange(33778, 34603, 9);
+checkRange(34603, 35218, 0);
+checkRange(35218, 35372, 10);
+checkRange(35372, 35486, 77);
+checkRange(35486, 35605, 5);
+checkRange(35605, 35629, 77);
+checkRange(35629, 35648, 41);
+checkRange(35648, 36547, 83);
+checkRange(36547, 36755, 74);
+checkRange(36755, 36767, 93);
+checkRange(36767, 36810, 83);
+checkRange(36810, 36839, 100);
+checkRange(36839, 37444, 96);
+checkRange(37444, 38060, 100);
+checkRange(38060, 38131, 10);
+checkRange(38131, 39082, 92);
+checkRange(39082, 39117, 95);
+checkRange(39117, 39187, 77);
+checkRange(39187, 39859, 92);
+checkRange(39859, 39894, 95);
+checkRange(39894, 40257, 77);
+checkRange(40257, 40344, 89);
+checkRange(40344, 40371, 59);
+checkRange(40371, 40804, 77);
+checkRange(40804, 40909, 5);
+checkRange(40909, 42259, 92);
+checkRange(42259, 42511, 77);
+checkRange(42511, 42945, 83);
+checkRange(42945, 43115, 77);
+checkRange(43115, 43306, 42);
+checkRange(43306, 43363, 76);
+checkRange(43363, 43387, 57);
+checkRange(43387, 43438, 59);
+checkRange(43438, 43447, 77);
+checkRange(43447, 43466, 41);
+checkRange(43466, 44129, 83);
+checkRange(44129, 44958, 96);
+checkRange(44958, 45570, 77);
+checkRange(45570, 45575, 92);
+checkRange(45575, 45640, 77);
+checkRange(45640, 45742, 42);
+checkRange(45742, 45832, 72);
+checkRange(45832, 45999, 92);
+checkRange(45999, 46384, 83);
+checkRange(46384, 46596, 95);
+checkRange(46596, 46654, 92);
+checkRange(46654, 47515, 83);
+checkRange(47515, 47620, 77);
+checkRange(47620, 47817, 79);
+checkRange(47817, 47951, 95);
+checkRange(47951, 48632, 100);
+checkRange(48632, 48699, 97);
+checkRange(48699, 48703, 37);
+checkRange(48703, 49764, 77);
+checkRange(49764, 49955, 42);
+checkRange(49955, 50012, 76);
+checkRange(50012, 50036, 57);
+checkRange(50036, 50087, 59);
+checkRange(50087, 50096, 77);
+checkRange(50096, 50115, 41);
+checkRange(50115, 50370, 83);
+checkRange(50370, 51358, 92);
+checkRange(51358, 51610, 77);
+checkRange(51610, 51776, 83);
+checkRange(51776, 51833, 89);
+checkRange(51833, 52895, 100);
+checkRange(52895, 53029, 97);
+checkRange(53029, 53244, 68);
+checkRange(53244, 54066, 100);
+checkRange(54066, 54133, 97);
+checkRange(54133, 54137, 37);
+checkRange(54137, 55198, 77);
+checkRange(55198, 55389, 42);
+checkRange(55389, 55446, 76);
+checkRange(55446, 55470, 57);
+checkRange(55470, 55521, 59);
+checkRange(55521, 55530, 77);
+checkRange(55530, 55549, 41);
+checkRange(55549, 56212, 83);
+checkRange(56212, 57048, 96);
+checkRange(57048, 58183, 77);
+checkRange(58183, 58202, 41);
+checkRange(58202, 58516, 83);
+checkRange(58516, 58835, 95);
+checkRange(58835, 58855, 77);
+checkRange(58855, 59089, 95);
+checkRange(59089, 59145, 77);
+checkRange(59145, 59677, 99);
+checkRange(59677, 60134, 0);
+checkRange(60134, 60502, 89);
+checkRange(60502, 60594, 59);
+checkRange(60594, 60617, 36);
+checkRange(60617, 60618, 32);
+checkRange(60618, 60777, 42);
+checkRange(60777, 60834, 76);
+checkRange(60834, 60858, 57);
+checkRange(60858, 60909, 59);
+checkRange(60909, 60918, 77);
+checkRange(60918, 60937, 41);
+checkRange(60937, 61600, 83);
+checkRange(61600, 62436, 96);
+checkRange(62436, 63307, 77);
+checkRange(63307, 63397, 100);
+checkRange(63397, 63501, 74);
+checkRange(63501, 63525, 93);
+checkRange(63525, 63605, 74);
+checkRange(63605, 63704, 100);
+checkRange(63704, 63771, 97);
+checkRange(63771, 63775, 37);
+checkRange(63775, 64311, 77);
+checkRange(64311, 64331, 26);
+checkRange(64331, 64518, 92);
+checkRange(64518, 64827, 11);
+checkRange(64827, 64834, 26);
+checkRange(64834, 65536, 0);
diff --git a/test/meta/generate_memory_fill.js b/test/meta/generate_memory_fill.js
new file mode 100644
index 0000000000..255b2d28cc
--- /dev/null
+++ b/test/meta/generate_memory_fill.js
@@ -0,0 +1,156 @@
+// This program generates .wast code that contains all the spec tests for
+// memory.fill.  See `Makefile`.
+
+print_origin("generate_memory_fill.js");
+
+let PREAMBLE = `
+  (memory 1 1)
+  ${checkRangeCode()}`;
+
+// Range valid
+print(
+`
+(module
+  ${PREAMBLE}
+  (func (export "test")
+    (memory.fill (i32.const 0xFF00) (i32.const 0x55) (i32.const 256))))
+(invoke "test")
+`);
+checkRange(0x00000, 0x0FF00, 0x00)
+checkRange(0x0FF00, 0x10000, 0x55)
+
+// Range invalid
+print(
+`
+(module
+  ${PREAMBLE}
+  (func (export "test")
+    (memory.fill (i32.const 0xFF00) (i32.const 0x55) (i32.const 257))))
+(assert_trap (invoke "test") "out of bounds memory access")
+`);
+
+// Wraparound the end of 32-bit offset space
+print(
+`
+(module
+  ${PREAMBLE}
+  (func (export "test")
+    (memory.fill (i32.const 0xFFFFFF00) (i32.const 0x55) (i32.const 257))))
+(assert_trap (invoke "test") "out of bounds memory access")
+`);
+
+// Zero len with offset in-bounds is a no-op
+print(
+`
+(module
+  ${PREAMBLE}
+  (func (export "test")
+    (memory.fill (i32.const 0x12) (i32.const 0x55) (i32.const 0))))
+(invoke "test")
+`);
+checkRange(0x00000, 0x10000, 0x00);
+
+// Zero len with offset out-of-bounds at the end of memory is allowed
+print(
+`
+(module
+  ${PREAMBLE}
+  (func (export "test")
+    (memory.fill (i32.const 0x10000) (i32.const 0x55) (i32.const 0))))
+(invoke "test")
+`);
+
+// Very large range
+print(
+`
+(module
+  ${PREAMBLE}
+  (func (export "test")
+    (memory.fill (i32.const 0x1) (i32.const 0xAA) (i32.const 0xFFFE))))
+(invoke "test")
+`);
+checkRange(0x00000, 0x00001, 0x00);
+checkRange(0x00001, 0x0FFFF, 0xAA);
+checkRange(0x0FFFF, 0x10000, 0x00);
+
+// Sequencing
+print(
+`
+(module
+  ${PREAMBLE}
+  (func (export "test")
+     (memory.fill (i32.const 0x12) (i32.const 0x55) (i32.const 10))
+     (memory.fill (i32.const 0x15) (i32.const 0xAA) (i32.const 4))))
+(invoke "test")
+`);
+checkRange(0x0,     0x12+0,  0x00);
+checkRange(0x12+0,  0x12+3,  0x55);
+checkRange(0x12+3,  0x12+7,  0xAA);
+checkRange(0x12+7,  0x12+10, 0x55);
+checkRange(0x12+10, 0x10000, 0x00);
+
+// Sundry compilation failures.
+
+// Module doesn't have a memory.
+print(
+`
+(assert_invalid
+  (module
+    (func (export "testfn")
+      (memory.fill (i32.const 10) (i32.const 20) (i32.const 30))))
+  "unknown memory 0")
+`);
+
+// Invalid argument types.  TODO: We can add anyref, funcref, etc here.
+{
+    const tys = ['i32', 'f32', 'i64', 'f64'];
+    for (let ty1 of tys) {
+    for (let ty2 of tys) {
+    for (let ty3 of tys) {
+        if (ty1 == 'i32' && ty2 == 'i32' && ty3 == 'i32')
+            continue;  // this is the only valid case
+        print(
+`
+(assert_invalid
+  (module
+    (memory 1 1)
+    (func (export "testfn")
+      (memory.fill (${ty1}.const 10) (${ty2}.const 20) (${ty3}.const 30))))
+  "type mismatch")
+`);
+    }}}
+}
+
+// memory.fill: out of bounds, but should perform a partial fill.
+//
+// Arithmetic overflow of memory offset + len should not affect the behavior, we
+// should still fill up to the limit.
+
+function mem_fill(min, max, shared, backup, write=backup*2) {
+    print(
+`(module
+  (memory ${min} ${max} ${shared})
+  ${checkRangeCode()}
+  (func (export "run") (param $offs i32) (param $val i32) (param $len i32)
+    (memory.fill (local.get $offs) (local.get $val) (local.get $len))))
+`);
+    // A fill past the end should throw *and* have filled all the way up to the end
+    let offs = min*PAGESIZE - backup;
+    let val = 37;
+    print(
+`(assert_trap (invoke "run" (i32.const ${offs}) (i32.const ${val}) (i32.const ${write}))
+              "out of bounds")
+`);
+    checkRange(offs, offs+backup, val);
+    checkRange(0, offs, 0);
+}
+
+mem_fill(1, 1, "", 256);
+mem_fill(1, 1, "", 257);
+mem_fill(1, 1, "", 257, 0xFFFFFFFF); // offs + len overflows 32-bit
+
+if (WITH_SHARED_MEMORY) {
+    mem_fill(2, 4, "shared", 256);
+    mem_fill(2, 4, "shared", 257);
+    mem_fill(2, 4, "shared", 257, 0xFFFFFFFF); // offs + len overflows 32-bit
+}
diff --git a/test/meta/generate_memory_init.js b/test/meta/generate_memory_init.js
new file mode 100644
index 0000000000..095e53f415
--- /dev/null
+++ b/test/meta/generate_memory_init.js
@@ -0,0 +1,259 @@
+// This program generates .wast code that contains all the spec tests for
+// memory.init and data.drop.  See `Makefile`.
+
+print_origin("generate_memory_init.js");
+
+// In-bounds tests.
+
+function mem_test(instruction, expected_result_vector) {
+    print(
+`
+(module
+  (memory (export "memory0") 1 1)
+  (data (i32.const 2) "\\03\\01\\04\\01")
+  (data passive "\\02\\07\\01\\08")
+  (data (i32.const 12) "\\07\\05\\02\\03\\06")
+  (data passive "\\05\\09\\02\\07\\06")
+  (func (export "test")
+    ${instruction})
+  (func (export "load8_u") (param i32) (result i32)
+    (i32.load8_u (local.get 0))))
+
+(invoke "test")
+`);
+    for (let i = 0; i < expected_result_vector.length; i++) {
+        print(`(assert_return (invoke "load8_u" (i32.const ${i})) (i32.const ${expected_result_vector[i]}))`);
+    }
+}
+
+const e = 0;
+
+// This just gives the initial state of the memory, with its active
+// initialisers applied.
+mem_test("nop",
+         [e,e,3,1,4, 1,e,e,e,e, e,e,7,5,2, 3,6,e,e,e, e,e,e,e,e, e,e,e,e,e]);
+
+// Passive init that overwrites all-zero entries
+mem_test("(memory.init 1 (i32.const 7) (i32.const 0) (i32.const 4))",
+         [e,e,3,1,4, 1,e,2,7,1, 8,e,7,5,2, 3,6,e,e,e, e,e,e,e,e, e,e,e,e,e]);
+
+// Passive init that overwrites existing active-init-created entries
+mem_test("(memory.init 3 (i32.const 15) (i32.const 1) (i32.const 3))",
+         [e,e,3,1,4, 1,e,e,e,e, e,e,7,5,2, 9,2,7,e,e, e,e,e,e,e, e,e,e,e,e]);
+
+// Perform active and passive initialisation and then multiple copies
+mem_test("(memory.init 1 (i32.const 7) (i32.const 0) (i32.const 4)) \n" +
+         "data.drop 1 \n" +
+         "(memory.init 3 (i32.const 15) (i32.const 1) (i32.const 3)) \n" +
+         "data.drop 3 \n" +
+         "(memory.copy (i32.const 20) (i32.const 15) (i32.const 5)) \n" +
+         "(memory.copy (i32.const 21) (i32.const 29) (i32.const 1)) \n" +
+         "(memory.copy (i32.const 24) (i32.const 10) (i32.const 1)) \n" +
+         "(memory.copy (i32.const 13) (i32.const 11) (i32.const 4)) \n" +
+         "(memory.copy (i32.const 19) (i32.const 20) (i32.const 5))",
+         [e,e,3,1,4, 1,e,2,7,1, 8,e,7,e,7, 5,2,7,e,9, e,7,e,8,8, e,e,e,e,e]);
+
+// Miscellaneous
+
+let PREAMBLE =
+    `(memory 1)
+     (data passive "\\37")`;
+
+// drop with no memory
+print(
+`(assert_invalid
+   (module
+     (func (export "test")
+       (data.drop 0)))
+   "unknown memory 0")
+`);
+
+// drop with data seg ix out of range
+print(
+`(assert_invalid
+  (module
+    ${PREAMBLE}
+    (func (export "test")
+      (data.drop 4)))
+  "unknown data segment")
+`);
+
+// drop, then drop
+print(
+`(module
+  ${PREAMBLE}
+  (func (export "test")
+    (data.drop 0)
+    (data.drop 0)))
+(assert_trap (invoke "test") "data segment dropped")
+`);
+
+// drop, then init
+print(
+`(module
+  ${PREAMBLE}
+  (func (export "test")
+    (data.drop 0)
+    (memory.init 0 (i32.const 1234) (i32.const 1) (i32.const 1))))
+(assert_trap (invoke "test") "data segment dropped")
+`);
+
+// init with data seg ix indicating an active segment
+print(
+`(module
+   (memory 1)
+   (data (i32.const 0) "\\37")
+   (func (export "test")
+     (memory.init 0 (i32.const 1234) (i32.const 1) (i32.const 1))))
+(assert_trap (invoke "test") "data segment dropped")
+`);
+
+// init with no memory
+print(
+`(assert_invalid
+  (module
+    (func (export "test")
+      (memory.init 1 (i32.const 1234) (i32.const 1) (i32.const 1))))
+  "unknown memory 0")
+`);
+
+// init with data seg ix out of range
+print(
+`(assert_invalid
+  (module
+    ${PREAMBLE}
+    (func (export "test")
+      (memory.init 1 (i32.const 1234) (i32.const 1) (i32.const 1))))
+  "unknown data segment 1")
+`);
+
+// init, using a data seg ix more than once is OK
+print(
+`(module
+  ${PREAMBLE}
+  (func (export "test")
+    (memory.init 0 (i32.const 1) (i32.const 0) (i32.const 1))
+    (memory.init 0 (i32.const 1) (i32.const 0) (i32.const 1))))
+(invoke "test")
+`);
+
+// init: seg ix is valid passive, but length to copy > len of seg
+print(
+`(module
+  ${PREAMBLE}
+  (func (export "test")
+    (memory.init 0 (i32.const 1234) (i32.const 0) (i32.const 5))))
+(assert_trap (invoke "test") "out of bounds")
+`);
+
+// init: seg ix is valid passive, but implies copying beyond end of seg
+print(
+`(module
+  ${PREAMBLE}
+  (func (export "test")
+    (memory.init 0 (i32.const 1234) (i32.const 2) (i32.const 3))))
+(assert_trap (invoke "test") "out of bounds")
+`);
+
+// init: seg ix is valid passive, but implies copying beyond end of dst
+print(
+`(module
+  ${PREAMBLE}
+  (func (export "test")
+    (memory.init 0 (i32.const 0xFFFE) (i32.const 1) (i32.const 3))))
+(assert_trap (invoke "test") "out of bounds")
+`);
+
+// init: seg ix is valid passive, zero len, but src offset out of bounds
+print(
+`(module
+  ${PREAMBLE}
+  (func (export "test")
+    (memory.init 0 (i32.const 1234) (i32.const 4) (i32.const 0))))
+(assert_trap (invoke "test") "out of bounds")
+`);
+
+// init: seg ix is valid passive, zero len, but dst offset out of bounds
+print(
+`(module
+  ${PREAMBLE}
+  (func (export "test")
+    (memory.init 0 (i32.const 0x10000) (i32.const 2) (i32.const 0))))
+(assert_trap (invoke "test") "out of bounds")
+`);
+
+// invalid argument types.  TODO: can add anyfunc etc here.
+{
+    const tys  = ['i32', 'f32', 'i64', 'f64'];
+
+    for (let ty1 of tys) {
+    for (let ty2 of tys) {
+    for (let ty3 of tys) {
+        if (ty1 == 'i32' && ty2 == 'i32' && ty3 == 'i32')
+            continue;  // this is the only valid case
+        print(
+`(assert_invalid
+   (module
+     ${PREAMBLE}
+     (func (export "test")
+       (memory.init 0 (${ty1}.const 1) (${ty2}.const 1) (${ty3}.const 1))))
+   "type mismatch")
+`);
+    }}}
+}
+
+// memory.init: out of bounds of the memory or the segment, but should perform
+// the operation up to the appropriate bound.
+//
+// Arithmetic overflow of memoffset + len or of bufferoffset + len should not
+// affect the behavior.
+
+// Note, the length of the data segment is 16.
+const mem_init_len = 16;
+
+function mem_init(min, max, shared, backup, write) {
+    print(
+`(module
+   (memory ${min} ${max} ${shared})
+   (data passive "\\42\\42\\42\\42\\42\\42\\42\\42\\42\\42\\42\\42\\42\\42\\42\\42")
+   ${checkRangeCode()}
+   (func (export "run") (param $offs i32) (param $len i32)
+     (memory.init 0 (local.get $offs) (i32.const 0) (local.get $len))))
+`);
+    // A fill writing past the end of the memory should throw *and* have filled
+    // all the way up to the end.
+    //
+    // A fill reading past the end of the segment should throw *and* have filled
+    // memory with as much data as was available.
+    let offs = min*PAGESIZE - backup;
+    print(
+`(assert_trap (invoke "run" (i32.const ${offs}) (i32.const ${write}))
+              "out of bounds")
+`);
+    checkRange(0, offs, 0);
+    checkRange(offs, offs+Math.min(backup, mem_init_len), 0x42);
+    checkRange(offs+Math.min(backup, mem_init_len), offs+backup, 0);
+}
+
+// We exceed the bounds of the memory but not of the data segment
+mem_init(1, 1, "", Math.floor(mem_init_len/2), mem_init_len);
+mem_init(1, 1, "", Math.floor(mem_init_len/2)+1, mem_init_len);
+if (WITH_SHARED_MEMORY) {
+    mem_init(2, 4, "shared", Math.floor(mem_init_len/2), mem_init_len);
+    mem_init(2, 4, "shared", Math.floor(mem_init_len/2)+1, mem_init_len);
+}
+
+// We exceed the bounds of the data segment but not the memory
+mem_init(1, 1, "", mem_init_len*4, mem_init_len*2-2);
+mem_init(1, 1, "", mem_init_len*4-1, mem_init_len*2-1);
+if (WITH_SHARED_MEMORY) {
+    mem_init(2, 4, "shared", mem_init_len*4, mem_init_len*2-2);
+    mem_init(2, 4, "shared", mem_init_len*4-1, mem_init_len*2-1);
+}
+
+// We arithmetically overflow the memory limit but not the segment limit
+mem_init(1, "", "", Math.floor(mem_init_len/2), 0xFFFFFF00);
+
+// We arithmetically overflow the segment limit but not the memory limit
+mem_init(1, "", "", PAGESIZE, 0xFFFFFFFC);
+
diff --git a/test/meta/generate_table_copy.js b/test/meta/generate_table_copy.js
new file mode 100644
index 0000000000..a13196271a
--- /dev/null
+++ b/test/meta/generate_table_copy.js
@@ -0,0 +1,319 @@
+// This program generates .wast code that contains all the spec tests for
+// table.copy.  See `Makefile`.
+
+print_origin("generate_table_copy.js");
+
+// This module "a" exports 5 functions ...
+
+function emit_a() {
+    print(
+`
+(module
+  (func (export "ef0") (result i32) (i32.const 0))
+  (func (export "ef1") (result i32) (i32.const 1))
+  (func (export "ef2") (result i32) (i32.const 2))
+  (func (export "ef3") (result i32) (i32.const 3))
+  (func (export "ef4") (result i32) (i32.const 4))
+)
+(register "a")
+`);
+}
+
+// ... and this one imports those 5 functions.  It adds 5 of its own, creates a
+// 30 element table using both active and passive initialisers, with a mixture
+// of the imported and local functions.  |test| is exported.  It uses the
+// supplied |insn| to modify the table somehow.  |check| will then indirect-call
+// the table entry number specified as a parameter.  That will either return a
+// value 0 to 9 indicating the function called, or will throw an exception if
+// the table entry is empty.
+
+function emit_b(insn) {
+    print(
+`
+(module
+  (type (func (result i32)))  ;; type #0
+  (import "a" "ef0" (func (result i32)))    ;; index 0
+  (import "a" "ef1" (func (result i32)))
+  (import "a" "ef2" (func (result i32)))
+  (import "a" "ef3" (func (result i32)))
+  (import "a" "ef4" (func (result i32)))    ;; index 4
+  (table 30 30 funcref)
+  (elem (i32.const 2) 3 1 4 1)
+  (elem passive 2 7 1 8)
+  (elem (i32.const 12) 7 5 2 3 6)
+  (elem passive 5 9 2 7 6)
+  (func (result i32) (i32.const 5))  ;; index 5
+  (func (result i32) (i32.const 6))
+  (func (result i32) (i32.const 7))
+  (func (result i32) (i32.const 8))
+  (func (result i32) (i32.const 9))  ;; index 9
+  (func (export "test")
+    ${insn})
+  (func (export "check") (param i32) (result i32)
+    (call_indirect (type 0) (local.get 0)))
+)
+`);
+}
+
+// This is the test driver.  It constructs the abovementioned module, using the
+// given |instruction| to modify the table, and then probes the table by making
+// indirect calls, one for each element of |expected_result_vector|.  The
+// results are compared to those in the vector.
+
+function tab_test(instruction, expected_result_vector) {
+    emit_b(instruction);
+    print(`(invoke "test")`);
+    for (let i = 0; i < expected_result_vector.length; i++) {
+        let expected = expected_result_vector[i];
+        if (expected === undefined) {
+            print(`(assert_trap (invoke "check" (i32.const ${i})) "uninitialized element")`);
+        } else {
+            print(`(assert_return (invoke "check" (i32.const ${i})) (i32.const ${expected}))`);
+        }
+    }
+}
+
+emit_a();
+
+// Using 'e' for empty (undefined) spaces in the table, to make it easier
+// to count through the vector entries when debugging.
+let e = undefined;
+
+// This just gives the initial state of the table, with its active
+// initialisers applied
+tab_test("nop",
+         [e,e,3,1,4, 1,e,e,e,e, e,e,7,5,2, 3,6,e,e,e, e,e,e,e,e, e,e,e,e,e]);
+
+// Copy non-null over non-null
+tab_test("(table.copy (i32.const 13) (i32.const 2) (i32.const 3))",
+         [e,e,3,1,4, 1,e,e,e,e, e,e,7,3,1, 4,6,e,e,e, e,e,e,e,e, e,e,e,e,e]);
+
+// Copy non-null over null
+tab_test("(table.copy (i32.const 25) (i32.const 15) (i32.const 2))",
+         [e,e,3,1,4, 1,e,e,e,e, e,e,7,5,2, 3,6,e,e,e, e,e,e,e,e, 3,6,e,e,e]);
+
+// Copy null over non-null
+tab_test("(table.copy (i32.const 13) (i32.const 25) (i32.const 3))",
+         [e,e,3,1,4, 1,e,e,e,e, e,e,7,e,e, e,6,e,e,e, e,e,e,e,e, e,e,e,e,e]);
+
+// Copy null over null
+tab_test("(table.copy (i32.const 20) (i32.const 22) (i32.const 4))",
+         [e,e,3,1,4, 1,e,e,e,e, e,e,7,5,2, 3,6,e,e,e, e,e,e,e,e, e,e,e,e,e]);
+
+// Copy null and non-null entries, non overlapping
+tab_test("(table.copy (i32.const 25) (i32.const 1) (i32.const 3))",
+         [e,e,3,1,4, 1,e,e,e,e, e,e,7,5,2, 3,6,e,e,e, e,e,e,e,e, e,3,1,e,e]);
+
+// Copy null and non-null entries, overlapping, backwards
+tab_test("(table.copy (i32.const 10) (i32.const 12) (i32.const 7))",
+         [e,e,3,1,4, 1,e,e,e,e, 7,5,2,3,6, e,e,e,e,e, e,e,e,e,e, e,e,e,e,e]);
+
+// Copy null and non-null entries, overlapping, forwards
+tab_test("(table.copy (i32.const 12) (i32.const 10) (i32.const 7))",
+         [e,e,3,1,4, 1,e,e,e,e, e,e,e,e,7, 5,2,3,6,e, e,e,e,e,e, e,e,e,e,e]);
+
+// Out-of-bounds checks.
+
+function do_test(insn1, insn2, errText)
+{
+    print(`
+(module
+  (table 30 30 funcref)
+  (elem (i32.const 2) 3 1 4 1)
+  (elem passive 2 7 1 8)
+  (elem (i32.const 12) 7 5 2 3 6)
+  (elem passive 5 9 2 7 6)
+  (func (result i32) (i32.const 0))
+  (func (result i32) (i32.const 1))
+  (func (result i32) (i32.const 2))
+  (func (result i32) (i32.const 3))
+  (func (result i32) (i32.const 4))
+  (func (result i32) (i32.const 5))
+  (func (result i32) (i32.const 6))
+  (func (result i32) (i32.const 7))
+  (func (result i32) (i32.const 8))
+  (func (result i32) (i32.const 9))
+  (func (export "test")
+    ${insn1}
+    ${insn2}))
+`);
+
+    if (errText !== undefined) {
+        print(`(assert_trap (invoke "test") "${errText}")`);
+    } else {
+        print(`(invoke "test")`);
+    }
+}
+
+function tab_test2(insn1, insn2, errKind, errText) {
+    do_test(insn1, insn2, errKind, errText);
+}
+
+function tab_test_nofail(insn1, insn2) {
+    do_test(insn1, insn2, undefined, undefined);
+}
+
+// Here we test the boundary-failure cases.  The table's valid indices are 0..29
+// inclusive.
+
+// copy: dst range invalid
+tab_test2("(table.copy (i32.const 28) (i32.const 1) (i32.const 3))",
+         "",
+         "out of bounds");
+
+// copy: dst wraparound end of 32 bit offset space
+tab_test2("(table.copy (i32.const 0xFFFFFFFE) (i32.const 1) (i32.const 2))",
+         "",
+         "out of bounds");
+
+// copy: src range invalid
+tab_test2("(table.copy (i32.const 15) (i32.const 25) (i32.const 6))",
+         "",
+         "out of bounds");
+
+// copy: src wraparound end of 32 bit offset space
+tab_test2("(table.copy (i32.const 15) (i32.const 0xFFFFFFFE) (i32.const 2))",
+         "",
+         "out of bounds");
+
+// copy: zero length with both offsets in-bounds is OK
+tab_test_nofail(
+    "(table.copy (i32.const 15) (i32.const 25) (i32.const 0))",
+    "");
+
+// copy: zero length with dst offset out of bounds at the end of the table is allowed
+tab_test2("(table.copy (i32.const 30) (i32.const 15) (i32.const 0))",
+         "",
+         undefined);
+
+// copy: zero length with src offset out of bounds at the end of the table is allowed
+tab_test2("(table.copy (i32.const 15) (i32.const 30) (i32.const 0))",
+         "",
+         undefined);
+
+// table.copy: out of bounds of the table for the source or target, but should
+// perform the operation up to the appropriate bound.  Major cases:
+//
+// - non-overlapping regions
+// - overlapping regions with src > dest
+// - overlapping regions with src == dest
+// - overlapping regions with src < dest
+// - arithmetic overflow on src addresses
+// - arithmetic overflow on target addresses
+//
+// for each of those,
+//
+// - src address oob
+// - target address oob
+// - both oob
+//
+// Note we do not test the multi-table case here because that is part of the
+// reftypes proposal; tests are in the gc/ subdirectory.
+
+const tbl_copy_len = 16;
+
+function tbl_copy(min, max, srcOffs, targetOffs, len, copyDown=false) {
+    let tblLength = min;
+
+    let targetAvail = tblLength - targetOffs;
+    let srcAvail = tblLength - srcOffs;
+    let targetLim = targetOffs + Math.min(len, targetAvail, srcAvail);
+    let srcLim = srcOffs + Math.min(len, targetAvail, srcAvail);
+
+    print(
+        `(module
+           (type (func (result i32)))
+           (table ${min} ${max} funcref)
+           (elem (i32.const ${srcOffs})
+                 ${(function () {
+                        var s = "";
+                        for (let i=srcOffs, j=0; i < srcLim; i++, j++)
+                            s += " $f" + j;
+                        return s;
+                     })()})
+           (func $f0 (export "f0") (result i32) (i32.const 0))
+           (func $f1 (export "f1") (result i32) (i32.const 1))
+           (func $f2 (export "f2") (result i32) (i32.const 2))
+           (func $f3 (export "f3") (result i32) (i32.const 3))
+           (func $f4 (export "f4") (result i32) (i32.const 4))
+           (func $f5 (export "f5") (result i32) (i32.const 5))
+           (func $f6 (export "f6") (result i32) (i32.const 6))
+           (func $f7 (export "f7") (result i32) (i32.const 7))
+           (func $f8 (export "f8") (result i32) (i32.const 8))
+           (func $f9 (export "f9") (result i32) (i32.const 9))
+           (func $f10 (export "f10") (result i32) (i32.const 10))
+           (func $f11 (export "f11") (result i32) (i32.const 11))
+           (func $f12 (export "f12") (result i32) (i32.const 12))
+           (func $f13 (export "f13") (result i32) (i32.const 13))
+           (func $f14 (export "f14") (result i32) (i32.const 14))
+           (func $f15 (export "f15") (result i32) (i32.const 15))
+           (func (export "test") (param $n i32) (result i32)
+             (call_indirect (type 0) (local.get $n)))
+           (func (export "run") (param $targetOffs i32) (param $srcOffs i32) (param $len i32)
+             (table.copy (local.get $targetOffs) (local.get $srcOffs) (local.get $len))))`);
+
+    let immediateOOB = copyDown && (srcOffs + len > tblLength || targetOffs + len > tblLength);
+
+    print(`(assert_trap (invoke "run" (i32.const ${targetOffs}) (i32.const ${srcOffs}) (i32.const ${len}))
+                        "out of bounds")`);
+
+    var t = 0;
+    var s = 0;
+    var i = 0;
+    function checkTarget() {
+        if (i >= targetOffs && i < targetLim) {
+            print(`(assert_return (invoke "test" (i32.const ${i})) (i32.const ${t++}))`);
+            if (i >= srcOffs && i < srcLim)
+                s++;
+            return true;
+        }
+        return false;
+    }
+    function checkSource() {
+        if (i >= srcOffs && i < srcLim) {
+            print(`(assert_return (invoke "test" (i32.const ${i})) (i32.const ${s++}))`);
+            if (i >= targetOffs && i < targetLim)
+                t++;
+            return true;
+        }
+        return false;
+    }
+
+    for (i=0; i < tblLength; i++ ) {
+        if (immediateOOB) {
+            if (checkSource())
+                continue;
+        } else {
+            if (copyDown && (checkSource() || checkTarget()))
+                continue;
+            if (!copyDown && (checkTarget() || checkSource()))
+                continue;
+        }
+        print(`(assert_trap (invoke "test" (i32.const ${i})) "uninitialized element")`);
+    }
+}
+
+// OOB target address, nonoverlapping
+tbl_copy(tbl_copy_len*2, tbl_copy_len*4, 0, Math.floor(1.5*tbl_copy_len), tbl_copy_len);
+tbl_copy(tbl_copy_len*2, tbl_copy_len*4, 0, Math.floor(1.5*tbl_copy_len)-1, tbl_copy_len-1);
+
+// OOB source address, nonoverlapping
+tbl_copy(tbl_copy_len*2, tbl_copy_len*4, Math.floor(1.5*tbl_copy_len), 0, tbl_copy_len);
+tbl_copy(tbl_copy_len*2, tbl_copy_len*4, Math.floor(1.5*tbl_copy_len)-1, 0, tbl_copy_len-1);
+
+// OOB target address, overlapping, src < target
+tbl_copy(tbl_copy_len*2, tbl_copy_len*4, tbl_copy_len-5, Math.floor(1.5*tbl_copy_len), tbl_copy_len, true);
+
+// OOB source address, overlapping, target < src
+tbl_copy(tbl_copy_len*2, tbl_copy_len*4, Math.floor(1.5*tbl_copy_len), tbl_copy_len-5, tbl_copy_len);
+
+// OOB both, overlapping, including src == target
+tbl_copy(tbl_copy_len*2, tbl_copy_len*4, tbl_copy_len+5, Math.floor(1.5*tbl_copy_len), tbl_copy_len, true);
+tbl_copy(tbl_copy_len*2, tbl_copy_len*4, Math.floor(1.5*tbl_copy_len), tbl_copy_len+5, tbl_copy_len);
+tbl_copy(tbl_copy_len*2, tbl_copy_len*4, tbl_copy_len+5, tbl_copy_len+5, tbl_copy_len);
+
+// Arithmetic overflow on source address.
+tbl_copy(tbl_copy_len*8, tbl_copy_len*8, tbl_copy_len*7, 0, 0xFFFFFFE0);
+
+// Arithmetic overflow on target adddress is an overlapping case.
+tbl_copy(tbl_copy_len*8, tbl_copy_len*8, 0, tbl_copy_len*7, 0xFFFFFFE0, true);
diff --git a/test/meta/generate_table_init.js b/test/meta/generate_table_init.js
new file mode 100644
index 0000000000..8060b44906
--- /dev/null
+++ b/test/meta/generate_table_init.js
@@ -0,0 +1,320 @@
+// This program generates .wast code that contains all the spec tests for
+// table.init and elem.drop.  See `Makefile`.
+
+print_origin("generate_table_init.js");
+
+// This module "a" exports 5 functions ...
+
+function emit_a() {
+    print(
+`
+(module
+  (func (export "ef0") (result i32) (i32.const 0))
+  (func (export "ef1") (result i32) (i32.const 1))
+  (func (export "ef2") (result i32) (i32.const 2))
+  (func (export "ef3") (result i32) (i32.const 3))
+  (func (export "ef4") (result i32) (i32.const 4))
+)
+(register "a")
+`);
+}
+
+// ... and this one imports those 5 functions.  It adds 5 of its own, creates a
+// 30 element table using both active and passive initialisers, with a mixture
+// of the imported and local functions.  |test| is exported.  It uses the
+// supplied |insn| to modify the table somehow.  |check| will then indirect-call
+// the table entry number specified as a parameter.  That will either return a
+// value 0 to 9 indicating the function called, or will throw an exception if
+// the table entry is empty.
+
+function emit_b(insn) {
+    print(
+`
+(module
+  (type (func (result i32)))  ;; type #0
+  (import "a" "ef0" (func (result i32)))    ;; index 0
+  (import "a" "ef1" (func (result i32)))
+  (import "a" "ef2" (func (result i32)))
+  (import "a" "ef3" (func (result i32)))
+  (import "a" "ef4" (func (result i32)))    ;; index 4
+  (table 30 30 funcref)
+  (elem (i32.const 2) 3 1 4 1)
+  (elem passive 2 7 1 8)
+  (elem (i32.const 12) 7 5 2 3 6)
+  (elem passive 5 9 2 7 6)
+  (func (result i32) (i32.const 5))  ;; index 5
+  (func (result i32) (i32.const 6))
+  (func (result i32) (i32.const 7))
+  (func (result i32) (i32.const 8))
+  (func (result i32) (i32.const 9))  ;; index 9
+  (func (export "test")
+    ${insn})
+  (func (export "check") (param i32) (result i32)
+    (call_indirect (type 0) (local.get 0)))
+)
+`);
+}
+
+// This is the test driver.  It constructs the abovementioned module, using the
+// given |instruction| to modify the table, and then probes the table by making
+// indirect calls, one for each element of |expected_result_vector|.  The
+// results are compared to those in the vector.
+
+function tab_test(instruction, expected_result_vector) {
+    emit_b(instruction);
+    print(`(invoke "test")`);
+    for (let i = 0; i < expected_result_vector.length; i++) {
+        let expected = expected_result_vector[i];
+        if (expected === undefined) {
+            print(`(assert_trap (invoke "check" (i32.const ${i})) "uninitialized element")`);
+        } else {
+            print(`(assert_return (invoke "check" (i32.const ${i})) (i32.const ${expected}))`);
+        }
+    }
+}
+
+emit_a();
+
+// Using 'e' for empty (undefined) spaces in the table, to make it easier
+// to count through the vector entries when debugging.
+let e = undefined;
+
+// Passive init that overwrites all-null entries
+tab_test("(table.init 1 (i32.const 7) (i32.const 0) (i32.const 4))",
+         [e,e,3,1,4, 1,e,2,7,1, 8,e,7,5,2, 3,6,e,e,e, e,e,e,e,e, e,e,e,e,e]);
+
+// Passive init that overwrites existing active-init-created entries
+tab_test("(table.init 3 (i32.const 15) (i32.const 1) (i32.const 3))",
+         [e,e,3,1,4, 1,e,e,e,e, e,e,7,5,2, 9,2,7,e,e, e,e,e,e,e, e,e,e,e,e]);
+
+// Perform active and passive initialisation and then multiple copies
+tab_test("(table.init 1 (i32.const 7) (i32.const 0) (i32.const 4)) \n" +
+         "elem.drop 1 \n" +
+         "(table.init 3 (i32.const 15) (i32.const 1) (i32.const 3)) \n" +
+         "elem.drop 3 \n" +
+         "(table.copy (i32.const 20) (i32.const 15) (i32.const 5)) \n" +
+         "(table.copy (i32.const 21) (i32.const 29) (i32.const 1)) \n" +
+         "(table.copy (i32.const 24) (i32.const 10) (i32.const 1)) \n" +
+         "(table.copy (i32.const 13) (i32.const 11) (i32.const 4)) \n" +
+         "(table.copy (i32.const 19) (i32.const 20) (i32.const 5))",
+         [e,e,3,1,4, 1,e,2,7,1, 8,e,7,e,7, 5,2,7,e,9, e,7,e,8,8, e,e,e,e,e]);
+
+
+// elem.drop requires a table, minimally
+print(
+`(assert_invalid
+  (module
+    (func (export "test")
+      (elem.drop 0)))
+  "unknown table 0")
+`);
+
+// table.init requires a table, minimally
+print(
+`(assert_invalid
+  (module
+    (func (export "test")
+      (table.init 0 (i32.const 12) (i32.const 1) (i32.const 1))))
+  "unknown table 0")
+`);
+
+// elem.drop with elem seg ix out of range
+print(
+`(assert_invalid
+  (module
+    (elem passive 0)
+    (func (result i32) (i32.const 0))
+    (func (export "test")
+      (elem.drop 4)))
+  "unknown table 0")
+`);
+
+// init with elem seg ix out of range
+print(
+`(assert_invalid
+  (module
+    (elem passive 0)
+    (func (result i32) (i32.const 0))
+    (func (export "test")
+      (table.init 4 (i32.const 12) (i32.const 1) (i32.const 1))))
+  "unknown table 0")
+`);
+
+function do_test(insn1, insn2, errText)
+{
+    print(`
+(module
+  (table 30 30 funcref)
+  (elem (i32.const 2) 3 1 4 1)
+  (elem passive 2 7 1 8)
+  (elem (i32.const 12) 7 5 2 3 6)
+  (elem passive 5 9 2 7 6)
+  (func (result i32) (i32.const 0))
+  (func (result i32) (i32.const 1))
+  (func (result i32) (i32.const 2))
+  (func (result i32) (i32.const 3))
+  (func (result i32) (i32.const 4))
+  (func (result i32) (i32.const 5))
+  (func (result i32) (i32.const 6))
+  (func (result i32) (i32.const 7))
+  (func (result i32) (i32.const 8))
+  (func (result i32) (i32.const 9))
+  (func (export "test")
+    ${insn1}
+    ${insn2}))
+`);
+
+    if (errText !== undefined) {
+        print(`(assert_trap (invoke "test") "${errText}")`);
+    } else {
+        print(`(invoke "test")`);
+    }
+}
+
+function tab_test2(insn1, insn2, errText) {
+    do_test(insn1, insn2, errText);
+}
+
+function tab_test_nofail(insn1, insn2) {
+    do_test(insn1, insn2, undefined);
+}
+
+// drop with elem seg ix indicating an active segment
+tab_test2("elem.drop 2", "",
+          "elements segment dropped");
+
+// init with elem seg ix indicating an active segment
+tab_test2("(table.init 2 (i32.const 12) (i32.const 1) (i32.const 1))", "",
+         "elements segment dropped");
+
+// init, using an elem seg ix more than once is OK
+tab_test_nofail(
+    "(table.init 1 (i32.const 12) (i32.const 1) (i32.const 1))",
+    "(table.init 1 (i32.const 21) (i32.const 1) (i32.const 1))");
+
+// drop, then drop
+tab_test2("elem.drop 1",
+          "elem.drop 1",
+          "elements segment dropped");
+
+// drop, then init
+tab_test2("elem.drop 1",
+         "(table.init 1 (i32.const 12) (i32.const 1) (i32.const 1))",
+         "elements segment dropped");
+
+// init: seg ix is valid passive, but length to copy > len of seg
+tab_test2("",
+         "(table.init 1 (i32.const 12) (i32.const 0) (i32.const 5))",
+         "out of bounds");
+
+// init: seg ix is valid passive, but implies copying beyond end of seg
+tab_test2("",
+         "(table.init 1 (i32.const 12) (i32.const 2) (i32.const 3))",
+         "out of bounds");
+
+// init: seg ix is valid passive, but implies copying beyond end of dst
+tab_test2("",
+         "(table.init 1 (i32.const 28) (i32.const 1) (i32.const 3))",
+         "out of bounds");
+
+// init: seg ix is valid passive, zero len, and src offset out of bounds at the
+// end of the table - this is allowed
+tab_test2("",
+         "(table.init 1 (i32.const 12) (i32.const 4) (i32.const 0))",
+         undefined);
+
+// init: seg ix is valid passive, zero len, and dst offset out of bounds at the
+// end of the table - this is allowed
+tab_test2("",
+         "(table.init 1 (i32.const 30) (i32.const 2) (i32.const 0))",
+         undefined);
+
+// invalid argument types
+{
+    const tys  = ['i32', 'f32', 'i64', 'f64'];
+
+    for (let ty1 of tys) {
+    for (let ty2 of tys) {
+    for (let ty3 of tys) {
+        if (ty1 == 'i32' && ty2 == 'i32' && ty3 == 'i32')
+            continue;  // this is the only valid case
+        print(
+`(assert_invalid
+   (module
+     (table 10 funcref)
+     (elem passive $f0 $f0 $f0)
+     (func $f0)
+     (func (export "test")
+       (table.init 0 (${ty1}.const 1) (${ty2}.const 1) (${ty3}.const 1))))
+   "type mismatch")
+`);
+    }}}
+}
+
+// table.init: out of bounds of the table or the element segment, but should
+// perform the operation up to the appropriate bound.
+//
+// Arithmetic overflow of tableoffset + len or of segmentoffset + len should not
+// affect the behavior.
+
+// Note, the length of the element segment is 16.
+const tbl_init_len = 16;
+
+function tbl_init(min, max, backup, write, segoffs=0) {
+    print(
+        `(module
+           (type (func (result i32)))
+           (table ${min} ${max} funcref)
+           (elem passive $f0 $f1 $f2 $f3 $f4 $f5 $f6 $f7 $f8 $f9 $f10 $f11 $f12 $f13 $f14 $f15)
+           (func $f0 (export "f0") (result i32) (i32.const 0))
+           (func $f1 (export "f1") (result i32) (i32.const 1))
+           (func $f2 (export "f2") (result i32) (i32.const 2))
+           (func $f3 (export "f3") (result i32) (i32.const 3))
+           (func $f4 (export "f4") (result i32) (i32.const 4))
+           (func $f5 (export "f5") (result i32) (i32.const 5))
+           (func $f6 (export "f6") (result i32) (i32.const 6))
+           (func $f7 (export "f7") (result i32) (i32.const 7))
+           (func $f8 (export "f8") (result i32) (i32.const 8))
+           (func $f9 (export "f9") (result i32) (i32.const 9))
+           (func $f10 (export "f10") (result i32) (i32.const 10))
+           (func $f11 (export "f11") (result i32) (i32.const 11))
+           (func $f12 (export "f12") (result i32) (i32.const 12))
+           (func $f13 (export "f13") (result i32) (i32.const 13))
+           (func $f14 (export "f14") (result i32) (i32.const 14))
+           (func $f15 (export "f15") (result i32) (i32.const 15))
+           (func (export "test") (param $n i32) (result i32)
+             (call_indirect (type 0) (local.get $n)))
+           (func (export "run") (param $offs i32) (param $len i32)
+             (table.init 0 (local.get $offs) (i32.const ${segoffs}) (local.get $len))))`);
+    // A fill writing past the end of the table should throw *and* have filled
+    // all the way up to the end.
+    //
+    // A fill reading past the end of the segment should throw *and* have filled
+    // table with as much data as was available.
+    let offs = min - backup;
+    print(`(assert_trap (invoke "run" (i32.const ${offs}) (i32.const ${write})) "out of bounds")`);
+    for (let i=0; i < Math.min(backup, tbl_init_len - segoffs); i++) {
+        print(`(assert_return (invoke "test" (i32.const ${offs + i})) (i32.const ${i + segoffs}))`);
+    }
+    for (let i=Math.min(backup, tbl_init_len); i < backup; i++) {
+        print(`(assert_trap (invoke "test" (i32.const ${offs + i})) "uninitialized element")`);
+    }
+    for (let i=0; i < offs; i++) {
+        print(`(assert_trap (invoke "test" (i32.const ${i})) "uninitialized element")`);
+    }
+}
+
+// We exceed the bounds of the table but not of the element segment
+tbl_init(tbl_init_len*2, tbl_init_len*4, Math.floor(tbl_init_len/2), tbl_init_len);
+tbl_init(tbl_init_len*2, tbl_init_len*4, Math.floor(tbl_init_len/2)-1, tbl_init_len);
+
+// We exceed the bounds of the element segment but not the table
+tbl_init(tbl_init_len*10, tbl_init_len*20, tbl_init_len*4, tbl_init_len*2);
+tbl_init(tbl_init_len*10, tbl_init_len*20, tbl_init_len*4-1, tbl_init_len*2-1);
+
+// We arithmetically overflow the table limit but not the segment limit
+tbl_init(tbl_init_len*4, tbl_init_len*4, tbl_init_len, 0xFFFFFFF0);
+
+// We arithmetically overflow the segment limit but not the table limit
+tbl_init(tbl_init_len, tbl_init_len, tbl_init_len, 0xFFFFFFFC, Math.floor(tbl_init_len/2));
+

From a1c04b5fe884a9f5fdad811cda8ad64fbeef01aa Mon Sep 17 00:00:00 2001
From: Ben Smith 
Date: Tue, 5 Mar 2019 14:36:03 -0800
Subject: [PATCH 067/199] [test] Add required `funcref` to passive elems (#68)

---
 test/core/table_copy.wast        |  60 +++++-----
 test/core/table_init.wast        | 194 +++++++++++++++----------------
 test/meta/generate_table_copy.js |   8 +-
 test/meta/generate_table_init.js |  16 +--
 4 files changed, 139 insertions(+), 139 deletions(-)

diff --git a/test/core/table_copy.wast b/test/core/table_copy.wast
index 74c95fb424..d705694027 100644
--- a/test/core/table_copy.wast
+++ b/test/core/table_copy.wast
@@ -21,9 +21,9 @@
   (import "a" "ef4" (func (result i32)))    ;; index 4
   (table 30 30 funcref)
   (elem (i32.const 2) 3 1 4 1)
-  (elem passive 2 7 1 8)
+  (elem passive funcref 2 7 1 8)
   (elem (i32.const 12) 7 5 2 3 6)
-  (elem passive 5 9 2 7 6)
+  (elem passive funcref 5 9 2 7 6)
   (func (result i32) (i32.const 5))  ;; index 5
   (func (result i32) (i32.const 6))
   (func (result i32) (i32.const 7))
@@ -76,9 +76,9 @@
   (import "a" "ef4" (func (result i32)))    ;; index 4
   (table 30 30 funcref)
   (elem (i32.const 2) 3 1 4 1)
-  (elem passive 2 7 1 8)
+  (elem passive funcref 2 7 1 8)
   (elem (i32.const 12) 7 5 2 3 6)
-  (elem passive 5 9 2 7 6)
+  (elem passive funcref 5 9 2 7 6)
   (func (result i32) (i32.const 5))  ;; index 5
   (func (result i32) (i32.const 6))
   (func (result i32) (i32.const 7))
@@ -131,9 +131,9 @@
   (import "a" "ef4" (func (result i32)))    ;; index 4
   (table 30 30 funcref)
   (elem (i32.const 2) 3 1 4 1)
-  (elem passive 2 7 1 8)
+  (elem passive funcref 2 7 1 8)
   (elem (i32.const 12) 7 5 2 3 6)
-  (elem passive 5 9 2 7 6)
+  (elem passive funcref 5 9 2 7 6)
   (func (result i32) (i32.const 5))  ;; index 5
   (func (result i32) (i32.const 6))
   (func (result i32) (i32.const 7))
@@ -186,9 +186,9 @@
   (import "a" "ef4" (func (result i32)))    ;; index 4
   (table 30 30 funcref)
   (elem (i32.const 2) 3 1 4 1)
-  (elem passive 2 7 1 8)
+  (elem passive funcref 2 7 1 8)
   (elem (i32.const 12) 7 5 2 3 6)
-  (elem passive 5 9 2 7 6)
+  (elem passive funcref 5 9 2 7 6)
   (func (result i32) (i32.const 5))  ;; index 5
   (func (result i32) (i32.const 6))
   (func (result i32) (i32.const 7))
@@ -241,9 +241,9 @@
   (import "a" "ef4" (func (result i32)))    ;; index 4
   (table 30 30 funcref)
   (elem (i32.const 2) 3 1 4 1)
-  (elem passive 2 7 1 8)
+  (elem passive funcref 2 7 1 8)
   (elem (i32.const 12) 7 5 2 3 6)
-  (elem passive 5 9 2 7 6)
+  (elem passive funcref 5 9 2 7 6)
   (func (result i32) (i32.const 5))  ;; index 5
   (func (result i32) (i32.const 6))
   (func (result i32) (i32.const 7))
@@ -296,9 +296,9 @@
   (import "a" "ef4" (func (result i32)))    ;; index 4
   (table 30 30 funcref)
   (elem (i32.const 2) 3 1 4 1)
-  (elem passive 2 7 1 8)
+  (elem passive funcref 2 7 1 8)
   (elem (i32.const 12) 7 5 2 3 6)
-  (elem passive 5 9 2 7 6)
+  (elem passive funcref 5 9 2 7 6)
   (func (result i32) (i32.const 5))  ;; index 5
   (func (result i32) (i32.const 6))
   (func (result i32) (i32.const 7))
@@ -351,9 +351,9 @@
   (import "a" "ef4" (func (result i32)))    ;; index 4
   (table 30 30 funcref)
   (elem (i32.const 2) 3 1 4 1)
-  (elem passive 2 7 1 8)
+  (elem passive funcref 2 7 1 8)
   (elem (i32.const 12) 7 5 2 3 6)
-  (elem passive 5 9 2 7 6)
+  (elem passive funcref 5 9 2 7 6)
   (func (result i32) (i32.const 5))  ;; index 5
   (func (result i32) (i32.const 6))
   (func (result i32) (i32.const 7))
@@ -406,9 +406,9 @@
   (import "a" "ef4" (func (result i32)))    ;; index 4
   (table 30 30 funcref)
   (elem (i32.const 2) 3 1 4 1)
-  (elem passive 2 7 1 8)
+  (elem passive funcref 2 7 1 8)
   (elem (i32.const 12) 7 5 2 3 6)
-  (elem passive 5 9 2 7 6)
+  (elem passive funcref 5 9 2 7 6)
   (func (result i32) (i32.const 5))  ;; index 5
   (func (result i32) (i32.const 6))
   (func (result i32) (i32.const 7))
@@ -455,9 +455,9 @@
 (module
   (table 30 30 funcref)
   (elem (i32.const 2) 3 1 4 1)
-  (elem passive 2 7 1 8)
+  (elem passive funcref 2 7 1 8)
   (elem (i32.const 12) 7 5 2 3 6)
-  (elem passive 5 9 2 7 6)
+  (elem passive funcref 5 9 2 7 6)
   (func (result i32) (i32.const 0))
   (func (result i32) (i32.const 1))
   (func (result i32) (i32.const 2))
@@ -477,9 +477,9 @@
 (module
   (table 30 30 funcref)
   (elem (i32.const 2) 3 1 4 1)
-  (elem passive 2 7 1 8)
+  (elem passive funcref 2 7 1 8)
   (elem (i32.const 12) 7 5 2 3 6)
-  (elem passive 5 9 2 7 6)
+  (elem passive funcref 5 9 2 7 6)
   (func (result i32) (i32.const 0))
   (func (result i32) (i32.const 1))
   (func (result i32) (i32.const 2))
@@ -499,9 +499,9 @@
 (module
   (table 30 30 funcref)
   (elem (i32.const 2) 3 1 4 1)
-  (elem passive 2 7 1 8)
+  (elem passive funcref 2 7 1 8)
   (elem (i32.const 12) 7 5 2 3 6)
-  (elem passive 5 9 2 7 6)
+  (elem passive funcref 5 9 2 7 6)
   (func (result i32) (i32.const 0))
   (func (result i32) (i32.const 1))
   (func (result i32) (i32.const 2))
@@ -521,9 +521,9 @@
 (module
   (table 30 30 funcref)
   (elem (i32.const 2) 3 1 4 1)
-  (elem passive 2 7 1 8)
+  (elem passive funcref 2 7 1 8)
   (elem (i32.const 12) 7 5 2 3 6)
-  (elem passive 5 9 2 7 6)
+  (elem passive funcref 5 9 2 7 6)
   (func (result i32) (i32.const 0))
   (func (result i32) (i32.const 1))
   (func (result i32) (i32.const 2))
@@ -543,9 +543,9 @@
 (module
   (table 30 30 funcref)
   (elem (i32.const 2) 3 1 4 1)
-  (elem passive 2 7 1 8)
+  (elem passive funcref 2 7 1 8)
   (elem (i32.const 12) 7 5 2 3 6)
-  (elem passive 5 9 2 7 6)
+  (elem passive funcref 5 9 2 7 6)
   (func (result i32) (i32.const 0))
   (func (result i32) (i32.const 1))
   (func (result i32) (i32.const 2))
@@ -565,9 +565,9 @@
 (module
   (table 30 30 funcref)
   (elem (i32.const 2) 3 1 4 1)
-  (elem passive 2 7 1 8)
+  (elem passive funcref 2 7 1 8)
   (elem (i32.const 12) 7 5 2 3 6)
-  (elem passive 5 9 2 7 6)
+  (elem passive funcref 5 9 2 7 6)
   (func (result i32) (i32.const 0))
   (func (result i32) (i32.const 1))
   (func (result i32) (i32.const 2))
@@ -587,9 +587,9 @@
 (module
   (table 30 30 funcref)
   (elem (i32.const 2) 3 1 4 1)
-  (elem passive 2 7 1 8)
+  (elem passive funcref 2 7 1 8)
   (elem (i32.const 12) 7 5 2 3 6)
-  (elem passive 5 9 2 7 6)
+  (elem passive funcref 5 9 2 7 6)
   (func (result i32) (i32.const 0))
   (func (result i32) (i32.const 1))
   (func (result i32) (i32.const 2))
diff --git a/test/core/table_init.wast b/test/core/table_init.wast
index 6cd8cbf745..d967a194f0 100644
--- a/test/core/table_init.wast
+++ b/test/core/table_init.wast
@@ -21,9 +21,9 @@
   (import "a" "ef4" (func (result i32)))    ;; index 4
   (table 30 30 funcref)
   (elem (i32.const 2) 3 1 4 1)
-  (elem passive 2 7 1 8)
+  (elem passive funcref 2 7 1 8)
   (elem (i32.const 12) 7 5 2 3 6)
-  (elem passive 5 9 2 7 6)
+  (elem passive funcref 5 9 2 7 6)
   (func (result i32) (i32.const 5))  ;; index 5
   (func (result i32) (i32.const 6))
   (func (result i32) (i32.const 7))
@@ -76,9 +76,9 @@
   (import "a" "ef4" (func (result i32)))    ;; index 4
   (table 30 30 funcref)
   (elem (i32.const 2) 3 1 4 1)
-  (elem passive 2 7 1 8)
+  (elem passive funcref 2 7 1 8)
   (elem (i32.const 12) 7 5 2 3 6)
-  (elem passive 5 9 2 7 6)
+  (elem passive funcref 5 9 2 7 6)
   (func (result i32) (i32.const 5))  ;; index 5
   (func (result i32) (i32.const 6))
   (func (result i32) (i32.const 7))
@@ -131,9 +131,9 @@
   (import "a" "ef4" (func (result i32)))    ;; index 4
   (table 30 30 funcref)
   (elem (i32.const 2) 3 1 4 1)
-  (elem passive 2 7 1 8)
+  (elem passive funcref 2 7 1 8)
   (elem (i32.const 12) 7 5 2 3 6)
-  (elem passive 5 9 2 7 6)
+  (elem passive funcref 5 9 2 7 6)
   (func (result i32) (i32.const 5))  ;; index 5
   (func (result i32) (i32.const 6))
   (func (result i32) (i32.const 7))
@@ -198,7 +198,7 @@ elem.drop 3
 
 (assert_invalid
   (module
-    (elem passive 0)
+    (elem passive funcref 0)
     (func (result i32) (i32.const 0))
     (func (export "test")
       (elem.drop 4)))
@@ -206,7 +206,7 @@ elem.drop 3
 
 (assert_invalid
   (module
-    (elem passive 0)
+    (elem passive funcref 0)
     (func (result i32) (i32.const 0))
     (func (export "test")
       (table.init 4 (i32.const 12) (i32.const 1) (i32.const 1))))
@@ -216,9 +216,9 @@ elem.drop 3
 (module
   (table 30 30 funcref)
   (elem (i32.const 2) 3 1 4 1)
-  (elem passive 2 7 1 8)
+  (elem passive funcref 2 7 1 8)
   (elem (i32.const 12) 7 5 2 3 6)
-  (elem passive 5 9 2 7 6)
+  (elem passive funcref 5 9 2 7 6)
   (func (result i32) (i32.const 0))
   (func (result i32) (i32.const 1))
   (func (result i32) (i32.const 2))
@@ -238,9 +238,9 @@ elem.drop 3
 (module
   (table 30 30 funcref)
   (elem (i32.const 2) 3 1 4 1)
-  (elem passive 2 7 1 8)
+  (elem passive funcref 2 7 1 8)
   (elem (i32.const 12) 7 5 2 3 6)
-  (elem passive 5 9 2 7 6)
+  (elem passive funcref 5 9 2 7 6)
   (func (result i32) (i32.const 0))
   (func (result i32) (i32.const 1))
   (func (result i32) (i32.const 2))
@@ -260,9 +260,9 @@ elem.drop 3
 (module
   (table 30 30 funcref)
   (elem (i32.const 2) 3 1 4 1)
-  (elem passive 2 7 1 8)
+  (elem passive funcref 2 7 1 8)
   (elem (i32.const 12) 7 5 2 3 6)
-  (elem passive 5 9 2 7 6)
+  (elem passive funcref 5 9 2 7 6)
   (func (result i32) (i32.const 0))
   (func (result i32) (i32.const 1))
   (func (result i32) (i32.const 2))
@@ -282,9 +282,9 @@ elem.drop 3
 (module
   (table 30 30 funcref)
   (elem (i32.const 2) 3 1 4 1)
-  (elem passive 2 7 1 8)
+  (elem passive funcref 2 7 1 8)
   (elem (i32.const 12) 7 5 2 3 6)
-  (elem passive 5 9 2 7 6)
+  (elem passive funcref 5 9 2 7 6)
   (func (result i32) (i32.const 0))
   (func (result i32) (i32.const 1))
   (func (result i32) (i32.const 2))
@@ -304,9 +304,9 @@ elem.drop 3
 (module
   (table 30 30 funcref)
   (elem (i32.const 2) 3 1 4 1)
-  (elem passive 2 7 1 8)
+  (elem passive funcref 2 7 1 8)
   (elem (i32.const 12) 7 5 2 3 6)
-  (elem passive 5 9 2 7 6)
+  (elem passive funcref 5 9 2 7 6)
   (func (result i32) (i32.const 0))
   (func (result i32) (i32.const 1))
   (func (result i32) (i32.const 2))
@@ -326,9 +326,9 @@ elem.drop 3
 (module
   (table 30 30 funcref)
   (elem (i32.const 2) 3 1 4 1)
-  (elem passive 2 7 1 8)
+  (elem passive funcref 2 7 1 8)
   (elem (i32.const 12) 7 5 2 3 6)
-  (elem passive 5 9 2 7 6)
+  (elem passive funcref 5 9 2 7 6)
   (func (result i32) (i32.const 0))
   (func (result i32) (i32.const 1))
   (func (result i32) (i32.const 2))
@@ -348,9 +348,9 @@ elem.drop 3
 (module
   (table 30 30 funcref)
   (elem (i32.const 2) 3 1 4 1)
-  (elem passive 2 7 1 8)
+  (elem passive funcref 2 7 1 8)
   (elem (i32.const 12) 7 5 2 3 6)
-  (elem passive 5 9 2 7 6)
+  (elem passive funcref 5 9 2 7 6)
   (func (result i32) (i32.const 0))
   (func (result i32) (i32.const 1))
   (func (result i32) (i32.const 2))
@@ -370,9 +370,9 @@ elem.drop 3
 (module
   (table 30 30 funcref)
   (elem (i32.const 2) 3 1 4 1)
-  (elem passive 2 7 1 8)
+  (elem passive funcref 2 7 1 8)
   (elem (i32.const 12) 7 5 2 3 6)
-  (elem passive 5 9 2 7 6)
+  (elem passive funcref 5 9 2 7 6)
   (func (result i32) (i32.const 0))
   (func (result i32) (i32.const 1))
   (func (result i32) (i32.const 2))
@@ -392,9 +392,9 @@ elem.drop 3
 (module
   (table 30 30 funcref)
   (elem (i32.const 2) 3 1 4 1)
-  (elem passive 2 7 1 8)
+  (elem passive funcref 2 7 1 8)
   (elem (i32.const 12) 7 5 2 3 6)
-  (elem passive 5 9 2 7 6)
+  (elem passive funcref 5 9 2 7 6)
   (func (result i32) (i32.const 0))
   (func (result i32) (i32.const 1))
   (func (result i32) (i32.const 2))
@@ -414,9 +414,9 @@ elem.drop 3
 (module
   (table 30 30 funcref)
   (elem (i32.const 2) 3 1 4 1)
-  (elem passive 2 7 1 8)
+  (elem passive funcref 2 7 1 8)
   (elem (i32.const 12) 7 5 2 3 6)
-  (elem passive 5 9 2 7 6)
+  (elem passive funcref 5 9 2 7 6)
   (func (result i32) (i32.const 0))
   (func (result i32) (i32.const 1))
   (func (result i32) (i32.const 2))
@@ -435,7 +435,7 @@ elem.drop 3
 (assert_invalid
    (module
      (table 10 funcref)
-     (elem passive $f0 $f0 $f0)
+     (elem passive funcref $f0 $f0 $f0)
      (func $f0)
      (func (export "test")
        (table.init 0 (i32.const 1) (i32.const 1) (f32.const 1))))
@@ -444,7 +444,7 @@ elem.drop 3
 (assert_invalid
    (module
      (table 10 funcref)
-     (elem passive $f0 $f0 $f0)
+     (elem passive funcref $f0 $f0 $f0)
      (func $f0)
      (func (export "test")
        (table.init 0 (i32.const 1) (i32.const 1) (i64.const 1))))
@@ -453,7 +453,7 @@ elem.drop 3
 (assert_invalid
    (module
      (table 10 funcref)
-     (elem passive $f0 $f0 $f0)
+     (elem passive funcref $f0 $f0 $f0)
      (func $f0)
      (func (export "test")
        (table.init 0 (i32.const 1) (i32.const 1) (f64.const 1))))
@@ -462,7 +462,7 @@ elem.drop 3
 (assert_invalid
    (module
      (table 10 funcref)
-     (elem passive $f0 $f0 $f0)
+     (elem passive funcref $f0 $f0 $f0)
      (func $f0)
      (func (export "test")
        (table.init 0 (i32.const 1) (f32.const 1) (i32.const 1))))
@@ -471,7 +471,7 @@ elem.drop 3
 (assert_invalid
    (module
      (table 10 funcref)
-     (elem passive $f0 $f0 $f0)
+     (elem passive funcref $f0 $f0 $f0)
      (func $f0)
      (func (export "test")
        (table.init 0 (i32.const 1) (f32.const 1) (f32.const 1))))
@@ -480,7 +480,7 @@ elem.drop 3
 (assert_invalid
    (module
      (table 10 funcref)
-     (elem passive $f0 $f0 $f0)
+     (elem passive funcref $f0 $f0 $f0)
      (func $f0)
      (func (export "test")
        (table.init 0 (i32.const 1) (f32.const 1) (i64.const 1))))
@@ -489,7 +489,7 @@ elem.drop 3
 (assert_invalid
    (module
      (table 10 funcref)
-     (elem passive $f0 $f0 $f0)
+     (elem passive funcref $f0 $f0 $f0)
      (func $f0)
      (func (export "test")
        (table.init 0 (i32.const 1) (f32.const 1) (f64.const 1))))
@@ -498,7 +498,7 @@ elem.drop 3
 (assert_invalid
    (module
      (table 10 funcref)
-     (elem passive $f0 $f0 $f0)
+     (elem passive funcref $f0 $f0 $f0)
      (func $f0)
      (func (export "test")
        (table.init 0 (i32.const 1) (i64.const 1) (i32.const 1))))
@@ -507,7 +507,7 @@ elem.drop 3
 (assert_invalid
    (module
      (table 10 funcref)
-     (elem passive $f0 $f0 $f0)
+     (elem passive funcref $f0 $f0 $f0)
      (func $f0)
      (func (export "test")
        (table.init 0 (i32.const 1) (i64.const 1) (f32.const 1))))
@@ -516,7 +516,7 @@ elem.drop 3
 (assert_invalid
    (module
      (table 10 funcref)
-     (elem passive $f0 $f0 $f0)
+     (elem passive funcref $f0 $f0 $f0)
      (func $f0)
      (func (export "test")
        (table.init 0 (i32.const 1) (i64.const 1) (i64.const 1))))
@@ -525,7 +525,7 @@ elem.drop 3
 (assert_invalid
    (module
      (table 10 funcref)
-     (elem passive $f0 $f0 $f0)
+     (elem passive funcref $f0 $f0 $f0)
      (func $f0)
      (func (export "test")
        (table.init 0 (i32.const 1) (i64.const 1) (f64.const 1))))
@@ -534,7 +534,7 @@ elem.drop 3
 (assert_invalid
    (module
      (table 10 funcref)
-     (elem passive $f0 $f0 $f0)
+     (elem passive funcref $f0 $f0 $f0)
      (func $f0)
      (func (export "test")
        (table.init 0 (i32.const 1) (f64.const 1) (i32.const 1))))
@@ -543,7 +543,7 @@ elem.drop 3
 (assert_invalid
    (module
      (table 10 funcref)
-     (elem passive $f0 $f0 $f0)
+     (elem passive funcref $f0 $f0 $f0)
      (func $f0)
      (func (export "test")
        (table.init 0 (i32.const 1) (f64.const 1) (f32.const 1))))
@@ -552,7 +552,7 @@ elem.drop 3
 (assert_invalid
    (module
      (table 10 funcref)
-     (elem passive $f0 $f0 $f0)
+     (elem passive funcref $f0 $f0 $f0)
      (func $f0)
      (func (export "test")
        (table.init 0 (i32.const 1) (f64.const 1) (i64.const 1))))
@@ -561,7 +561,7 @@ elem.drop 3
 (assert_invalid
    (module
      (table 10 funcref)
-     (elem passive $f0 $f0 $f0)
+     (elem passive funcref $f0 $f0 $f0)
      (func $f0)
      (func (export "test")
        (table.init 0 (i32.const 1) (f64.const 1) (f64.const 1))))
@@ -570,7 +570,7 @@ elem.drop 3
 (assert_invalid
    (module
      (table 10 funcref)
-     (elem passive $f0 $f0 $f0)
+     (elem passive funcref $f0 $f0 $f0)
      (func $f0)
      (func (export "test")
        (table.init 0 (f32.const 1) (i32.const 1) (i32.const 1))))
@@ -579,7 +579,7 @@ elem.drop 3
 (assert_invalid
    (module
      (table 10 funcref)
-     (elem passive $f0 $f0 $f0)
+     (elem passive funcref $f0 $f0 $f0)
      (func $f0)
      (func (export "test")
        (table.init 0 (f32.const 1) (i32.const 1) (f32.const 1))))
@@ -588,7 +588,7 @@ elem.drop 3
 (assert_invalid
    (module
      (table 10 funcref)
-     (elem passive $f0 $f0 $f0)
+     (elem passive funcref $f0 $f0 $f0)
      (func $f0)
      (func (export "test")
        (table.init 0 (f32.const 1) (i32.const 1) (i64.const 1))))
@@ -597,7 +597,7 @@ elem.drop 3
 (assert_invalid
    (module
      (table 10 funcref)
-     (elem passive $f0 $f0 $f0)
+     (elem passive funcref $f0 $f0 $f0)
      (func $f0)
      (func (export "test")
        (table.init 0 (f32.const 1) (i32.const 1) (f64.const 1))))
@@ -606,7 +606,7 @@ elem.drop 3
 (assert_invalid
    (module
      (table 10 funcref)
-     (elem passive $f0 $f0 $f0)
+     (elem passive funcref $f0 $f0 $f0)
      (func $f0)
      (func (export "test")
        (table.init 0 (f32.const 1) (f32.const 1) (i32.const 1))))
@@ -615,7 +615,7 @@ elem.drop 3
 (assert_invalid
    (module
      (table 10 funcref)
-     (elem passive $f0 $f0 $f0)
+     (elem passive funcref $f0 $f0 $f0)
      (func $f0)
      (func (export "test")
        (table.init 0 (f32.const 1) (f32.const 1) (f32.const 1))))
@@ -624,7 +624,7 @@ elem.drop 3
 (assert_invalid
    (module
      (table 10 funcref)
-     (elem passive $f0 $f0 $f0)
+     (elem passive funcref $f0 $f0 $f0)
      (func $f0)
      (func (export "test")
        (table.init 0 (f32.const 1) (f32.const 1) (i64.const 1))))
@@ -633,7 +633,7 @@ elem.drop 3
 (assert_invalid
    (module
      (table 10 funcref)
-     (elem passive $f0 $f0 $f0)
+     (elem passive funcref $f0 $f0 $f0)
      (func $f0)
      (func (export "test")
        (table.init 0 (f32.const 1) (f32.const 1) (f64.const 1))))
@@ -642,7 +642,7 @@ elem.drop 3
 (assert_invalid
    (module
      (table 10 funcref)
-     (elem passive $f0 $f0 $f0)
+     (elem passive funcref $f0 $f0 $f0)
      (func $f0)
      (func (export "test")
        (table.init 0 (f32.const 1) (i64.const 1) (i32.const 1))))
@@ -651,7 +651,7 @@ elem.drop 3
 (assert_invalid
    (module
      (table 10 funcref)
-     (elem passive $f0 $f0 $f0)
+     (elem passive funcref $f0 $f0 $f0)
      (func $f0)
      (func (export "test")
        (table.init 0 (f32.const 1) (i64.const 1) (f32.const 1))))
@@ -660,7 +660,7 @@ elem.drop 3
 (assert_invalid
    (module
      (table 10 funcref)
-     (elem passive $f0 $f0 $f0)
+     (elem passive funcref $f0 $f0 $f0)
      (func $f0)
      (func (export "test")
        (table.init 0 (f32.const 1) (i64.const 1) (i64.const 1))))
@@ -669,7 +669,7 @@ elem.drop 3
 (assert_invalid
    (module
      (table 10 funcref)
-     (elem passive $f0 $f0 $f0)
+     (elem passive funcref $f0 $f0 $f0)
      (func $f0)
      (func (export "test")
        (table.init 0 (f32.const 1) (i64.const 1) (f64.const 1))))
@@ -678,7 +678,7 @@ elem.drop 3
 (assert_invalid
    (module
      (table 10 funcref)
-     (elem passive $f0 $f0 $f0)
+     (elem passive funcref $f0 $f0 $f0)
      (func $f0)
      (func (export "test")
        (table.init 0 (f32.const 1) (f64.const 1) (i32.const 1))))
@@ -687,7 +687,7 @@ elem.drop 3
 (assert_invalid
    (module
      (table 10 funcref)
-     (elem passive $f0 $f0 $f0)
+     (elem passive funcref $f0 $f0 $f0)
      (func $f0)
      (func (export "test")
        (table.init 0 (f32.const 1) (f64.const 1) (f32.const 1))))
@@ -696,7 +696,7 @@ elem.drop 3
 (assert_invalid
    (module
      (table 10 funcref)
-     (elem passive $f0 $f0 $f0)
+     (elem passive funcref $f0 $f0 $f0)
      (func $f0)
      (func (export "test")
        (table.init 0 (f32.const 1) (f64.const 1) (i64.const 1))))
@@ -705,7 +705,7 @@ elem.drop 3
 (assert_invalid
    (module
      (table 10 funcref)
-     (elem passive $f0 $f0 $f0)
+     (elem passive funcref $f0 $f0 $f0)
      (func $f0)
      (func (export "test")
        (table.init 0 (f32.const 1) (f64.const 1) (f64.const 1))))
@@ -714,7 +714,7 @@ elem.drop 3
 (assert_invalid
    (module
      (table 10 funcref)
-     (elem passive $f0 $f0 $f0)
+     (elem passive funcref $f0 $f0 $f0)
      (func $f0)
      (func (export "test")
        (table.init 0 (i64.const 1) (i32.const 1) (i32.const 1))))
@@ -723,7 +723,7 @@ elem.drop 3
 (assert_invalid
    (module
      (table 10 funcref)
-     (elem passive $f0 $f0 $f0)
+     (elem passive funcref $f0 $f0 $f0)
      (func $f0)
      (func (export "test")
        (table.init 0 (i64.const 1) (i32.const 1) (f32.const 1))))
@@ -732,7 +732,7 @@ elem.drop 3
 (assert_invalid
    (module
      (table 10 funcref)
-     (elem passive $f0 $f0 $f0)
+     (elem passive funcref $f0 $f0 $f0)
      (func $f0)
      (func (export "test")
        (table.init 0 (i64.const 1) (i32.const 1) (i64.const 1))))
@@ -741,7 +741,7 @@ elem.drop 3
 (assert_invalid
    (module
      (table 10 funcref)
-     (elem passive $f0 $f0 $f0)
+     (elem passive funcref $f0 $f0 $f0)
      (func $f0)
      (func (export "test")
        (table.init 0 (i64.const 1) (i32.const 1) (f64.const 1))))
@@ -750,7 +750,7 @@ elem.drop 3
 (assert_invalid
    (module
      (table 10 funcref)
-     (elem passive $f0 $f0 $f0)
+     (elem passive funcref $f0 $f0 $f0)
      (func $f0)
      (func (export "test")
        (table.init 0 (i64.const 1) (f32.const 1) (i32.const 1))))
@@ -759,7 +759,7 @@ elem.drop 3
 (assert_invalid
    (module
      (table 10 funcref)
-     (elem passive $f0 $f0 $f0)
+     (elem passive funcref $f0 $f0 $f0)
      (func $f0)
      (func (export "test")
        (table.init 0 (i64.const 1) (f32.const 1) (f32.const 1))))
@@ -768,7 +768,7 @@ elem.drop 3
 (assert_invalid
    (module
      (table 10 funcref)
-     (elem passive $f0 $f0 $f0)
+     (elem passive funcref $f0 $f0 $f0)
      (func $f0)
      (func (export "test")
        (table.init 0 (i64.const 1) (f32.const 1) (i64.const 1))))
@@ -777,7 +777,7 @@ elem.drop 3
 (assert_invalid
    (module
      (table 10 funcref)
-     (elem passive $f0 $f0 $f0)
+     (elem passive funcref $f0 $f0 $f0)
      (func $f0)
      (func (export "test")
        (table.init 0 (i64.const 1) (f32.const 1) (f64.const 1))))
@@ -786,7 +786,7 @@ elem.drop 3
 (assert_invalid
    (module
      (table 10 funcref)
-     (elem passive $f0 $f0 $f0)
+     (elem passive funcref $f0 $f0 $f0)
      (func $f0)
      (func (export "test")
        (table.init 0 (i64.const 1) (i64.const 1) (i32.const 1))))
@@ -795,7 +795,7 @@ elem.drop 3
 (assert_invalid
    (module
      (table 10 funcref)
-     (elem passive $f0 $f0 $f0)
+     (elem passive funcref $f0 $f0 $f0)
      (func $f0)
      (func (export "test")
        (table.init 0 (i64.const 1) (i64.const 1) (f32.const 1))))
@@ -804,7 +804,7 @@ elem.drop 3
 (assert_invalid
    (module
      (table 10 funcref)
-     (elem passive $f0 $f0 $f0)
+     (elem passive funcref $f0 $f0 $f0)
      (func $f0)
      (func (export "test")
        (table.init 0 (i64.const 1) (i64.const 1) (i64.const 1))))
@@ -813,7 +813,7 @@ elem.drop 3
 (assert_invalid
    (module
      (table 10 funcref)
-     (elem passive $f0 $f0 $f0)
+     (elem passive funcref $f0 $f0 $f0)
      (func $f0)
      (func (export "test")
        (table.init 0 (i64.const 1) (i64.const 1) (f64.const 1))))
@@ -822,7 +822,7 @@ elem.drop 3
 (assert_invalid
    (module
      (table 10 funcref)
-     (elem passive $f0 $f0 $f0)
+     (elem passive funcref $f0 $f0 $f0)
      (func $f0)
      (func (export "test")
        (table.init 0 (i64.const 1) (f64.const 1) (i32.const 1))))
@@ -831,7 +831,7 @@ elem.drop 3
 (assert_invalid
    (module
      (table 10 funcref)
-     (elem passive $f0 $f0 $f0)
+     (elem passive funcref $f0 $f0 $f0)
      (func $f0)
      (func (export "test")
        (table.init 0 (i64.const 1) (f64.const 1) (f32.const 1))))
@@ -840,7 +840,7 @@ elem.drop 3
 (assert_invalid
    (module
      (table 10 funcref)
-     (elem passive $f0 $f0 $f0)
+     (elem passive funcref $f0 $f0 $f0)
      (func $f0)
      (func (export "test")
        (table.init 0 (i64.const 1) (f64.const 1) (i64.const 1))))
@@ -849,7 +849,7 @@ elem.drop 3
 (assert_invalid
    (module
      (table 10 funcref)
-     (elem passive $f0 $f0 $f0)
+     (elem passive funcref $f0 $f0 $f0)
      (func $f0)
      (func (export "test")
        (table.init 0 (i64.const 1) (f64.const 1) (f64.const 1))))
@@ -858,7 +858,7 @@ elem.drop 3
 (assert_invalid
    (module
      (table 10 funcref)
-     (elem passive $f0 $f0 $f0)
+     (elem passive funcref $f0 $f0 $f0)
      (func $f0)
      (func (export "test")
        (table.init 0 (f64.const 1) (i32.const 1) (i32.const 1))))
@@ -867,7 +867,7 @@ elem.drop 3
 (assert_invalid
    (module
      (table 10 funcref)
-     (elem passive $f0 $f0 $f0)
+     (elem passive funcref $f0 $f0 $f0)
      (func $f0)
      (func (export "test")
        (table.init 0 (f64.const 1) (i32.const 1) (f32.const 1))))
@@ -876,7 +876,7 @@ elem.drop 3
 (assert_invalid
    (module
      (table 10 funcref)
-     (elem passive $f0 $f0 $f0)
+     (elem passive funcref $f0 $f0 $f0)
      (func $f0)
      (func (export "test")
        (table.init 0 (f64.const 1) (i32.const 1) (i64.const 1))))
@@ -885,7 +885,7 @@ elem.drop 3
 (assert_invalid
    (module
      (table 10 funcref)
-     (elem passive $f0 $f0 $f0)
+     (elem passive funcref $f0 $f0 $f0)
      (func $f0)
      (func (export "test")
        (table.init 0 (f64.const 1) (i32.const 1) (f64.const 1))))
@@ -894,7 +894,7 @@ elem.drop 3
 (assert_invalid
    (module
      (table 10 funcref)
-     (elem passive $f0 $f0 $f0)
+     (elem passive funcref $f0 $f0 $f0)
      (func $f0)
      (func (export "test")
        (table.init 0 (f64.const 1) (f32.const 1) (i32.const 1))))
@@ -903,7 +903,7 @@ elem.drop 3
 (assert_invalid
    (module
      (table 10 funcref)
-     (elem passive $f0 $f0 $f0)
+     (elem passive funcref $f0 $f0 $f0)
      (func $f0)
      (func (export "test")
        (table.init 0 (f64.const 1) (f32.const 1) (f32.const 1))))
@@ -912,7 +912,7 @@ elem.drop 3
 (assert_invalid
    (module
      (table 10 funcref)
-     (elem passive $f0 $f0 $f0)
+     (elem passive funcref $f0 $f0 $f0)
      (func $f0)
      (func (export "test")
        (table.init 0 (f64.const 1) (f32.const 1) (i64.const 1))))
@@ -921,7 +921,7 @@ elem.drop 3
 (assert_invalid
    (module
      (table 10 funcref)
-     (elem passive $f0 $f0 $f0)
+     (elem passive funcref $f0 $f0 $f0)
      (func $f0)
      (func (export "test")
        (table.init 0 (f64.const 1) (f32.const 1) (f64.const 1))))
@@ -930,7 +930,7 @@ elem.drop 3
 (assert_invalid
    (module
      (table 10 funcref)
-     (elem passive $f0 $f0 $f0)
+     (elem passive funcref $f0 $f0 $f0)
      (func $f0)
      (func (export "test")
        (table.init 0 (f64.const 1) (i64.const 1) (i32.const 1))))
@@ -939,7 +939,7 @@ elem.drop 3
 (assert_invalid
    (module
      (table 10 funcref)
-     (elem passive $f0 $f0 $f0)
+     (elem passive funcref $f0 $f0 $f0)
      (func $f0)
      (func (export "test")
        (table.init 0 (f64.const 1) (i64.const 1) (f32.const 1))))
@@ -948,7 +948,7 @@ elem.drop 3
 (assert_invalid
    (module
      (table 10 funcref)
-     (elem passive $f0 $f0 $f0)
+     (elem passive funcref $f0 $f0 $f0)
      (func $f0)
      (func (export "test")
        (table.init 0 (f64.const 1) (i64.const 1) (i64.const 1))))
@@ -957,7 +957,7 @@ elem.drop 3
 (assert_invalid
    (module
      (table 10 funcref)
-     (elem passive $f0 $f0 $f0)
+     (elem passive funcref $f0 $f0 $f0)
      (func $f0)
      (func (export "test")
        (table.init 0 (f64.const 1) (i64.const 1) (f64.const 1))))
@@ -966,7 +966,7 @@ elem.drop 3
 (assert_invalid
    (module
      (table 10 funcref)
-     (elem passive $f0 $f0 $f0)
+     (elem passive funcref $f0 $f0 $f0)
      (func $f0)
      (func (export "test")
        (table.init 0 (f64.const 1) (f64.const 1) (i32.const 1))))
@@ -975,7 +975,7 @@ elem.drop 3
 (assert_invalid
    (module
      (table 10 funcref)
-     (elem passive $f0 $f0 $f0)
+     (elem passive funcref $f0 $f0 $f0)
      (func $f0)
      (func (export "test")
        (table.init 0 (f64.const 1) (f64.const 1) (f32.const 1))))
@@ -984,7 +984,7 @@ elem.drop 3
 (assert_invalid
    (module
      (table 10 funcref)
-     (elem passive $f0 $f0 $f0)
+     (elem passive funcref $f0 $f0 $f0)
      (func $f0)
      (func (export "test")
        (table.init 0 (f64.const 1) (f64.const 1) (i64.const 1))))
@@ -993,7 +993,7 @@ elem.drop 3
 (assert_invalid
    (module
      (table 10 funcref)
-     (elem passive $f0 $f0 $f0)
+     (elem passive funcref $f0 $f0 $f0)
      (func $f0)
      (func (export "test")
        (table.init 0 (f64.const 1) (f64.const 1) (f64.const 1))))
@@ -1002,7 +1002,7 @@ elem.drop 3
 (module
            (type (func (result i32)))
            (table 32 64 funcref)
-           (elem passive $f0 $f1 $f2 $f3 $f4 $f5 $f6 $f7 $f8 $f9 $f10 $f11 $f12 $f13 $f14 $f15)
+           (elem passive funcref $f0 $f1 $f2 $f3 $f4 $f5 $f6 $f7 $f8 $f9 $f10 $f11 $f12 $f13 $f14 $f15)
            (func $f0 (export "f0") (result i32) (i32.const 0))
            (func $f1 (export "f1") (result i32) (i32.const 1))
            (func $f2 (export "f2") (result i32) (i32.const 2))
@@ -1059,7 +1059,7 @@ elem.drop 3
 (module
            (type (func (result i32)))
            (table 32 64 funcref)
-           (elem passive $f0 $f1 $f2 $f3 $f4 $f5 $f6 $f7 $f8 $f9 $f10 $f11 $f12 $f13 $f14 $f15)
+           (elem passive funcref $f0 $f1 $f2 $f3 $f4 $f5 $f6 $f7 $f8 $f9 $f10 $f11 $f12 $f13 $f14 $f15)
            (func $f0 (export "f0") (result i32) (i32.const 0))
            (func $f1 (export "f1") (result i32) (i32.const 1))
            (func $f2 (export "f2") (result i32) (i32.const 2))
@@ -1116,7 +1116,7 @@ elem.drop 3
 (module
            (type (func (result i32)))
            (table 160 320 funcref)
-           (elem passive $f0 $f1 $f2 $f3 $f4 $f5 $f6 $f7 $f8 $f9 $f10 $f11 $f12 $f13 $f14 $f15)
+           (elem passive funcref $f0 $f1 $f2 $f3 $f4 $f5 $f6 $f7 $f8 $f9 $f10 $f11 $f12 $f13 $f14 $f15)
            (func $f0 (export "f0") (result i32) (i32.const 0))
            (func $f1 (export "f1") (result i32) (i32.const 1))
            (func $f2 (export "f2") (result i32) (i32.const 2))
@@ -1301,7 +1301,7 @@ elem.drop 3
 (module
            (type (func (result i32)))
            (table 160 320 funcref)
-           (elem passive $f0 $f1 $f2 $f3 $f4 $f5 $f6 $f7 $f8 $f9 $f10 $f11 $f12 $f13 $f14 $f15)
+           (elem passive funcref $f0 $f1 $f2 $f3 $f4 $f5 $f6 $f7 $f8 $f9 $f10 $f11 $f12 $f13 $f14 $f15)
            (func $f0 (export "f0") (result i32) (i32.const 0))
            (func $f1 (export "f1") (result i32) (i32.const 1))
            (func $f2 (export "f2") (result i32) (i32.const 2))
@@ -1486,7 +1486,7 @@ elem.drop 3
 (module
            (type (func (result i32)))
            (table 64 64 funcref)
-           (elem passive $f0 $f1 $f2 $f3 $f4 $f5 $f6 $f7 $f8 $f9 $f10 $f11 $f12 $f13 $f14 $f15)
+           (elem passive funcref $f0 $f1 $f2 $f3 $f4 $f5 $f6 $f7 $f8 $f9 $f10 $f11 $f12 $f13 $f14 $f15)
            (func $f0 (export "f0") (result i32) (i32.const 0))
            (func $f1 (export "f1") (result i32) (i32.const 1))
            (func $f2 (export "f2") (result i32) (i32.const 2))
@@ -1575,7 +1575,7 @@ elem.drop 3
 (module
            (type (func (result i32)))
            (table 16 16 funcref)
-           (elem passive $f0 $f1 $f2 $f3 $f4 $f5 $f6 $f7 $f8 $f9 $f10 $f11 $f12 $f13 $f14 $f15)
+           (elem passive funcref $f0 $f1 $f2 $f3 $f4 $f5 $f6 $f7 $f8 $f9 $f10 $f11 $f12 $f13 $f14 $f15)
            (func $f0 (export "f0") (result i32) (i32.const 0))
            (func $f1 (export "f1") (result i32) (i32.const 1))
            (func $f2 (export "f2") (result i32) (i32.const 2))
diff --git a/test/meta/generate_table_copy.js b/test/meta/generate_table_copy.js
index a13196271a..743bed8e61 100644
--- a/test/meta/generate_table_copy.js
+++ b/test/meta/generate_table_copy.js
@@ -39,9 +39,9 @@ function emit_b(insn) {
   (import "a" "ef4" (func (result i32)))    ;; index 4
   (table 30 30 funcref)
   (elem (i32.const 2) 3 1 4 1)
-  (elem passive 2 7 1 8)
+  (elem passive funcref 2 7 1 8)
   (elem (i32.const 12) 7 5 2 3 6)
-  (elem passive 5 9 2 7 6)
+  (elem passive funcref 5 9 2 7 6)
   (func (result i32) (i32.const 5))  ;; index 5
   (func (result i32) (i32.const 6))
   (func (result i32) (i32.const 7))
@@ -120,9 +120,9 @@ function do_test(insn1, insn2, errText)
 (module
   (table 30 30 funcref)
   (elem (i32.const 2) 3 1 4 1)
-  (elem passive 2 7 1 8)
+  (elem passive funcref 2 7 1 8)
   (elem (i32.const 12) 7 5 2 3 6)
-  (elem passive 5 9 2 7 6)
+  (elem passive funcref 5 9 2 7 6)
   (func (result i32) (i32.const 0))
   (func (result i32) (i32.const 1))
   (func (result i32) (i32.const 2))
diff --git a/test/meta/generate_table_init.js b/test/meta/generate_table_init.js
index 8060b44906..52cce96367 100644
--- a/test/meta/generate_table_init.js
+++ b/test/meta/generate_table_init.js
@@ -39,9 +39,9 @@ function emit_b(insn) {
   (import "a" "ef4" (func (result i32)))    ;; index 4
   (table 30 30 funcref)
   (elem (i32.const 2) 3 1 4 1)
-  (elem passive 2 7 1 8)
+  (elem passive funcref 2 7 1 8)
   (elem (i32.const 12) 7 5 2 3 6)
-  (elem passive 5 9 2 7 6)
+  (elem passive funcref 5 9 2 7 6)
   (func (result i32) (i32.const 5))  ;; index 5
   (func (result i32) (i32.const 6))
   (func (result i32) (i32.const 7))
@@ -122,7 +122,7 @@ print(
 print(
 `(assert_invalid
   (module
-    (elem passive 0)
+    (elem passive funcref 0)
     (func (result i32) (i32.const 0))
     (func (export "test")
       (elem.drop 4)))
@@ -133,7 +133,7 @@ print(
 print(
 `(assert_invalid
   (module
-    (elem passive 0)
+    (elem passive funcref 0)
     (func (result i32) (i32.const 0))
     (func (export "test")
       (table.init 4 (i32.const 12) (i32.const 1) (i32.const 1))))
@@ -146,9 +146,9 @@ function do_test(insn1, insn2, errText)
 (module
   (table 30 30 funcref)
   (elem (i32.const 2) 3 1 4 1)
-  (elem passive 2 7 1 8)
+  (elem passive funcref 2 7 1 8)
   (elem (i32.const 12) 7 5 2 3 6)
-  (elem passive 5 9 2 7 6)
+  (elem passive funcref 5 9 2 7 6)
   (func (result i32) (i32.const 0))
   (func (result i32) (i32.const 1))
   (func (result i32) (i32.const 2))
@@ -242,7 +242,7 @@ tab_test2("",
 `(assert_invalid
    (module
      (table 10 funcref)
-     (elem passive $f0 $f0 $f0)
+     (elem passive funcref $f0 $f0 $f0)
      (func $f0)
      (func (export "test")
        (table.init 0 (${ty1}.const 1) (${ty2}.const 1) (${ty3}.const 1))))
@@ -265,7 +265,7 @@ function tbl_init(min, max, backup, write, segoffs=0) {
         `(module
            (type (func (result i32)))
            (table ${min} ${max} funcref)
-           (elem passive $f0 $f1 $f2 $f3 $f4 $f5 $f6 $f7 $f8 $f9 $f10 $f11 $f12 $f13 $f14 $f15)
+           (elem passive funcref $f0 $f1 $f2 $f3 $f4 $f5 $f6 $f7 $f8 $f9 $f10 $f11 $f12 $f13 $f14 $f15)
            (func $f0 (export "f0") (result i32) (i32.const 0))
            (func $f1 (export "f1") (result i32) (i32.const 1))
            (func $f2 (export "f2") (result i32) (i32.const 2))

From 6c802facfc4cce9dc8207960f824601861fad0dc Mon Sep 17 00:00:00 2001
From: Ben Smith 
Date: Tue, 5 Mar 2019 15:19:41 -0800
Subject: [PATCH 068/199] [test] Minor cleanup to generated output (#69)

---
 test/core/memory_copy.wast        |  550 +++++------
 test/core/memory_fill.wast        |  256 ++---
 test/core/memory_init.wast        |  964 +++++++++----------
 test/core/table_copy.wast         |  575 +++++------
 test/core/table_init.wast         | 1469 ++++++++++++++---------------
 test/meta/common.js               |   18 +-
 test/meta/generate_memory_copy.js |  432 +++++----
 test/meta/generate_memory_fill.js |   25 +-
 test/meta/generate_memory_init.js |   40 +-
 test/meta/generate_table_copy.js  |   69 +-
 test/meta/generate_table_init.js  |  137 ++-
 11 files changed, 2195 insertions(+), 2340 deletions(-)

diff --git a/test/core/memory_copy.wast b/test/core/memory_copy.wast
index e9ea04a9e1..b5f25c009b 100644
--- a/test/core/memory_copy.wast
+++ b/test/core/memory_copy.wast
@@ -7,7 +7,7 @@
   (data (i32.const 2) "\03\01\04\01")
   (data (i32.const 12) "\07\05\02\03\06")
   (func (export "test")
-    nop)
+    (nop))
   (func (export "load8_u") (param i32) (result i32)
     (i32.load8_u (local.get 0))))
 
@@ -4449,7 +4449,6 @@
       (memory.copy (i32.const 10) (i32.const 20) (i32.const 30))))
   "unknown memory 0")
 
-
 (assert_invalid
   (module
     (memory 1 1)
@@ -4457,7 +4456,6 @@
       (memory.copy (i32.const 10) (i32.const 20) (f32.const 30))))
   "type mismatch")
 
-
 (assert_invalid
   (module
     (memory 1 1)
@@ -4465,7 +4463,6 @@
       (memory.copy (i32.const 10) (i32.const 20) (i64.const 30))))
   "type mismatch")
 
-
 (assert_invalid
   (module
     (memory 1 1)
@@ -4473,7 +4470,6 @@
       (memory.copy (i32.const 10) (i32.const 20) (f64.const 30))))
   "type mismatch")
 
-
 (assert_invalid
   (module
     (memory 1 1)
@@ -4481,7 +4477,6 @@
       (memory.copy (i32.const 10) (f32.const 20) (i32.const 30))))
   "type mismatch")
 
-
 (assert_invalid
   (module
     (memory 1 1)
@@ -4489,7 +4484,6 @@
       (memory.copy (i32.const 10) (f32.const 20) (f32.const 30))))
   "type mismatch")
 
-
 (assert_invalid
   (module
     (memory 1 1)
@@ -4497,7 +4491,6 @@
       (memory.copy (i32.const 10) (f32.const 20) (i64.const 30))))
   "type mismatch")
 
-
 (assert_invalid
   (module
     (memory 1 1)
@@ -4505,7 +4498,6 @@
       (memory.copy (i32.const 10) (f32.const 20) (f64.const 30))))
   "type mismatch")
 
-
 (assert_invalid
   (module
     (memory 1 1)
@@ -4513,7 +4505,6 @@
       (memory.copy (i32.const 10) (i64.const 20) (i32.const 30))))
   "type mismatch")
 
-
 (assert_invalid
   (module
     (memory 1 1)
@@ -4521,7 +4512,6 @@
       (memory.copy (i32.const 10) (i64.const 20) (f32.const 30))))
   "type mismatch")
 
-
 (assert_invalid
   (module
     (memory 1 1)
@@ -4529,7 +4519,6 @@
       (memory.copy (i32.const 10) (i64.const 20) (i64.const 30))))
   "type mismatch")
 
-
 (assert_invalid
   (module
     (memory 1 1)
@@ -4537,7 +4526,6 @@
       (memory.copy (i32.const 10) (i64.const 20) (f64.const 30))))
   "type mismatch")
 
-
 (assert_invalid
   (module
     (memory 1 1)
@@ -4545,7 +4533,6 @@
       (memory.copy (i32.const 10) (f64.const 20) (i32.const 30))))
   "type mismatch")
 
-
 (assert_invalid
   (module
     (memory 1 1)
@@ -4553,7 +4540,6 @@
       (memory.copy (i32.const 10) (f64.const 20) (f32.const 30))))
   "type mismatch")
 
-
 (assert_invalid
   (module
     (memory 1 1)
@@ -4561,7 +4547,6 @@
       (memory.copy (i32.const 10) (f64.const 20) (i64.const 30))))
   "type mismatch")
 
-
 (assert_invalid
   (module
     (memory 1 1)
@@ -4569,7 +4554,6 @@
       (memory.copy (i32.const 10) (f64.const 20) (f64.const 30))))
   "type mismatch")
 
-
 (assert_invalid
   (module
     (memory 1 1)
@@ -4577,7 +4561,6 @@
       (memory.copy (f32.const 10) (i32.const 20) (i32.const 30))))
   "type mismatch")
 
-
 (assert_invalid
   (module
     (memory 1 1)
@@ -4585,7 +4568,6 @@
       (memory.copy (f32.const 10) (i32.const 20) (f32.const 30))))
   "type mismatch")
 
-
 (assert_invalid
   (module
     (memory 1 1)
@@ -4593,7 +4575,6 @@
       (memory.copy (f32.const 10) (i32.const 20) (i64.const 30))))
   "type mismatch")
 
-
 (assert_invalid
   (module
     (memory 1 1)
@@ -4601,7 +4582,6 @@
       (memory.copy (f32.const 10) (i32.const 20) (f64.const 30))))
   "type mismatch")
 
-
 (assert_invalid
   (module
     (memory 1 1)
@@ -4609,7 +4589,6 @@
       (memory.copy (f32.const 10) (f32.const 20) (i32.const 30))))
   "type mismatch")
 
-
 (assert_invalid
   (module
     (memory 1 1)
@@ -4617,7 +4596,6 @@
       (memory.copy (f32.const 10) (f32.const 20) (f32.const 30))))
   "type mismatch")
 
-
 (assert_invalid
   (module
     (memory 1 1)
@@ -4625,7 +4603,6 @@
       (memory.copy (f32.const 10) (f32.const 20) (i64.const 30))))
   "type mismatch")
 
-
 (assert_invalid
   (module
     (memory 1 1)
@@ -4633,7 +4610,6 @@
       (memory.copy (f32.const 10) (f32.const 20) (f64.const 30))))
   "type mismatch")
 
-
 (assert_invalid
   (module
     (memory 1 1)
@@ -4641,7 +4617,6 @@
       (memory.copy (f32.const 10) (i64.const 20) (i32.const 30))))
   "type mismatch")
 
-
 (assert_invalid
   (module
     (memory 1 1)
@@ -4649,7 +4624,6 @@
       (memory.copy (f32.const 10) (i64.const 20) (f32.const 30))))
   "type mismatch")
 
-
 (assert_invalid
   (module
     (memory 1 1)
@@ -4657,7 +4631,6 @@
       (memory.copy (f32.const 10) (i64.const 20) (i64.const 30))))
   "type mismatch")
 
-
 (assert_invalid
   (module
     (memory 1 1)
@@ -4665,7 +4638,6 @@
       (memory.copy (f32.const 10) (i64.const 20) (f64.const 30))))
   "type mismatch")
 
-
 (assert_invalid
   (module
     (memory 1 1)
@@ -4673,7 +4645,6 @@
       (memory.copy (f32.const 10) (f64.const 20) (i32.const 30))))
   "type mismatch")
 
-
 (assert_invalid
   (module
     (memory 1 1)
@@ -4681,7 +4652,6 @@
       (memory.copy (f32.const 10) (f64.const 20) (f32.const 30))))
   "type mismatch")
 
-
 (assert_invalid
   (module
     (memory 1 1)
@@ -4689,7 +4659,6 @@
       (memory.copy (f32.const 10) (f64.const 20) (i64.const 30))))
   "type mismatch")
 
-
 (assert_invalid
   (module
     (memory 1 1)
@@ -4697,7 +4666,6 @@
       (memory.copy (f32.const 10) (f64.const 20) (f64.const 30))))
   "type mismatch")
 
-
 (assert_invalid
   (module
     (memory 1 1)
@@ -4705,7 +4673,6 @@
       (memory.copy (i64.const 10) (i32.const 20) (i32.const 30))))
   "type mismatch")
 
-
 (assert_invalid
   (module
     (memory 1 1)
@@ -4713,7 +4680,6 @@
       (memory.copy (i64.const 10) (i32.const 20) (f32.const 30))))
   "type mismatch")
 
-
 (assert_invalid
   (module
     (memory 1 1)
@@ -4721,7 +4687,6 @@
       (memory.copy (i64.const 10) (i32.const 20) (i64.const 30))))
   "type mismatch")
 
-
 (assert_invalid
   (module
     (memory 1 1)
@@ -4729,7 +4694,6 @@
       (memory.copy (i64.const 10) (i32.const 20) (f64.const 30))))
   "type mismatch")
 
-
 (assert_invalid
   (module
     (memory 1 1)
@@ -4737,7 +4701,6 @@
       (memory.copy (i64.const 10) (f32.const 20) (i32.const 30))))
   "type mismatch")
 
-
 (assert_invalid
   (module
     (memory 1 1)
@@ -4745,7 +4708,6 @@
       (memory.copy (i64.const 10) (f32.const 20) (f32.const 30))))
   "type mismatch")
 
-
 (assert_invalid
   (module
     (memory 1 1)
@@ -4753,7 +4715,6 @@
       (memory.copy (i64.const 10) (f32.const 20) (i64.const 30))))
   "type mismatch")
 
-
 (assert_invalid
   (module
     (memory 1 1)
@@ -4761,7 +4722,6 @@
       (memory.copy (i64.const 10) (f32.const 20) (f64.const 30))))
   "type mismatch")
 
-
 (assert_invalid
   (module
     (memory 1 1)
@@ -4769,7 +4729,6 @@
       (memory.copy (i64.const 10) (i64.const 20) (i32.const 30))))
   "type mismatch")
 
-
 (assert_invalid
   (module
     (memory 1 1)
@@ -4777,7 +4736,6 @@
       (memory.copy (i64.const 10) (i64.const 20) (f32.const 30))))
   "type mismatch")
 
-
 (assert_invalid
   (module
     (memory 1 1)
@@ -4785,7 +4743,6 @@
       (memory.copy (i64.const 10) (i64.const 20) (i64.const 30))))
   "type mismatch")
 
-
 (assert_invalid
   (module
     (memory 1 1)
@@ -4793,7 +4750,6 @@
       (memory.copy (i64.const 10) (i64.const 20) (f64.const 30))))
   "type mismatch")
 
-
 (assert_invalid
   (module
     (memory 1 1)
@@ -4801,7 +4757,6 @@
       (memory.copy (i64.const 10) (f64.const 20) (i32.const 30))))
   "type mismatch")
 
-
 (assert_invalid
   (module
     (memory 1 1)
@@ -4809,7 +4764,6 @@
       (memory.copy (i64.const 10) (f64.const 20) (f32.const 30))))
   "type mismatch")
 
-
 (assert_invalid
   (module
     (memory 1 1)
@@ -4817,7 +4771,6 @@
       (memory.copy (i64.const 10) (f64.const 20) (i64.const 30))))
   "type mismatch")
 
-
 (assert_invalid
   (module
     (memory 1 1)
@@ -4825,7 +4778,6 @@
       (memory.copy (i64.const 10) (f64.const 20) (f64.const 30))))
   "type mismatch")
 
-
 (assert_invalid
   (module
     (memory 1 1)
@@ -4833,7 +4785,6 @@
       (memory.copy (f64.const 10) (i32.const 20) (i32.const 30))))
   "type mismatch")
 
-
 (assert_invalid
   (module
     (memory 1 1)
@@ -4841,7 +4792,6 @@
       (memory.copy (f64.const 10) (i32.const 20) (f32.const 30))))
   "type mismatch")
 
-
 (assert_invalid
   (module
     (memory 1 1)
@@ -4849,7 +4799,6 @@
       (memory.copy (f64.const 10) (i32.const 20) (i64.const 30))))
   "type mismatch")
 
-
 (assert_invalid
   (module
     (memory 1 1)
@@ -4857,7 +4806,6 @@
       (memory.copy (f64.const 10) (i32.const 20) (f64.const 30))))
   "type mismatch")
 
-
 (assert_invalid
   (module
     (memory 1 1)
@@ -4865,7 +4813,6 @@
       (memory.copy (f64.const 10) (f32.const 20) (i32.const 30))))
   "type mismatch")
 
-
 (assert_invalid
   (module
     (memory 1 1)
@@ -4873,7 +4820,6 @@
       (memory.copy (f64.const 10) (f32.const 20) (f32.const 30))))
   "type mismatch")
 
-
 (assert_invalid
   (module
     (memory 1 1)
@@ -4881,7 +4827,6 @@
       (memory.copy (f64.const 10) (f32.const 20) (i64.const 30))))
   "type mismatch")
 
-
 (assert_invalid
   (module
     (memory 1 1)
@@ -4889,7 +4834,6 @@
       (memory.copy (f64.const 10) (f32.const 20) (f64.const 30))))
   "type mismatch")
 
-
 (assert_invalid
   (module
     (memory 1 1)
@@ -4897,7 +4841,6 @@
       (memory.copy (f64.const 10) (i64.const 20) (i32.const 30))))
   "type mismatch")
 
-
 (assert_invalid
   (module
     (memory 1 1)
@@ -4905,7 +4848,6 @@
       (memory.copy (f64.const 10) (i64.const 20) (f32.const 30))))
   "type mismatch")
 
-
 (assert_invalid
   (module
     (memory 1 1)
@@ -4913,7 +4855,6 @@
       (memory.copy (f64.const 10) (i64.const 20) (i64.const 30))))
   "type mismatch")
 
-
 (assert_invalid
   (module
     (memory 1 1)
@@ -4921,7 +4862,6 @@
       (memory.copy (f64.const 10) (i64.const 20) (f64.const 30))))
   "type mismatch")
 
-
 (assert_invalid
   (module
     (memory 1 1)
@@ -4929,7 +4869,6 @@
       (memory.copy (f64.const 10) (f64.const 20) (i32.const 30))))
   "type mismatch")
 
-
 (assert_invalid
   (module
     (memory 1 1)
@@ -4937,7 +4876,6 @@
       (memory.copy (f64.const 10) (f64.const 20) (f32.const 30))))
   "type mismatch")
 
-
 (assert_invalid
   (module
     (memory 1 1)
@@ -4945,7 +4883,6 @@
       (memory.copy (f64.const 10) (f64.const 20) (i64.const 30))))
   "type mismatch")
 
-
 (assert_invalid
   (module
     (memory 1 1)
@@ -4961,15 +4898,15 @@
     (memory.copy (i32.const 9) (i32.const 10) (i32.const 5)))
   
   (func (export "checkRange") (param $from i32) (param $to i32) (param $expected i32) (result i32)
-   (loop $cont
-     (if (i32.eq (local.get $from) (local.get $to))
-         (then
-           (return (i32.const -1))))
-     (if (i32.eq (i32.load8_u (local.get $from)) (local.get $expected))
-         (then
-           (local.set $from (i32.add (local.get $from) (i32.const 1)))
-           (br $cont))))
-   (return (local.get $from)))
+    (loop $cont
+      (if (i32.eq (local.get $from) (local.get $to))
+        (then
+          (return (i32.const -1))))
+      (if (i32.eq (i32.load8_u (local.get $from)) (local.get $expected))
+        (then
+          (local.set $from (i32.add (local.get $from) (i32.const 1)))
+          (br $cont))))
+    (return (local.get $from)))
 )
 (invoke "test")
 
@@ -4987,15 +4924,15 @@
     (memory.copy (i32.const 16) (i32.const 15) (i32.const 5)))
   
   (func (export "checkRange") (param $from i32) (param $to i32) (param $expected i32) (result i32)
-   (loop $cont
-     (if (i32.eq (local.get $from) (local.get $to))
-         (then
-           (return (i32.const -1))))
-     (if (i32.eq (i32.load8_u (local.get $from)) (local.get $expected))
-         (then
-           (local.set $from (i32.add (local.get $from) (i32.const 1)))
-           (br $cont))))
-   (return (local.get $from)))
+    (loop $cont
+      (if (i32.eq (local.get $from) (local.get $to))
+        (then
+          (return (i32.const -1))))
+      (if (i32.eq (i32.load8_u (local.get $from)) (local.get $expected))
+        (then
+          (local.set $from (i32.add (local.get $from) (i32.const 1)))
+          (br $cont))))
+    (return (local.get $from)))
 )
 (invoke "test")
 
@@ -5012,28 +4949,24 @@
     (memory.copy (i32.const 0xFF00) (i32.const 0x8000) (i32.const 257))))
 (assert_trap (invoke "test") "out of bounds")
 
-
 (module
   (memory 1 1)
   (func (export "test")
     (memory.copy (i32.const 0xFFFFFF00) (i32.const 0x4000) (i32.const 257))))
 (assert_trap (invoke "test") "out of bounds")
 
-
 (module
   (memory 1 1)
   (func (export "test")
     (memory.copy (i32.const 0x8000) (i32.const 0xFF00) (i32.const 257))))
 (assert_trap (invoke "test") "out of bounds")
 
-
 (module
  (memory 1 1)
  (func (export "test")
    (memory.copy (i32.const 0x4000) (i32.const 0xFFFFFF00) (i32.const 257))))
 (assert_trap (invoke "test") "out of bounds")
 
-
 (module
   (memory 1 1)
   (func (export "test")
@@ -5042,15 +4975,15 @@
     (memory.copy (i32.const 0x9000) (i32.const 0x7000) (i32.const 0)))
   
   (func (export "checkRange") (param $from i32) (param $to i32) (param $expected i32) (result i32)
-   (loop $cont
-     (if (i32.eq (local.get $from) (local.get $to))
-         (then
-           (return (i32.const -1))))
-     (if (i32.eq (i32.load8_u (local.get $from)) (local.get $expected))
-         (then
-           (local.set $from (i32.add (local.get $from) (i32.const 1)))
-           (br $cont))))
-   (return (local.get $from)))
+    (loop $cont
+      (if (i32.eq (local.get $from) (local.get $to))
+        (then
+          (return (i32.const -1))))
+      (if (i32.eq (i32.load8_u (local.get $from)) (local.get $expected))
+        (then
+          (local.set $from (i32.add (local.get $from) (i32.const 1)))
+          (br $cont))))
+    (return (local.get $from)))
 )
 (invoke "test")
 
@@ -5058,236 +4991,233 @@
                (i32.const -1))
 (assert_return (invoke "checkRange" (i32.const 32768) (i32.const 65536) (i32.const 170))
                (i32.const -1))
-
 (module
   (memory 1 1)
   (func (export "test")
     (memory.copy (i32.const 0x10000) (i32.const 0x7000) (i32.const 0))))
 (invoke "test")
 
-
 (module
   (memory 1 1)
   (func (export "test")
     (memory.copy (i32.const 0x9000) (i32.const 0x10000) (i32.const 0))))
 (invoke "test")
 
-
 (module
-       (memory 1 1)
-       (func (export "test")
-         (memory.fill (i32.const 17767) (i32.const 1) (i32.const 1344))
-         (memory.fill (i32.const 39017) (i32.const 2) (i32.const 1055))
-         (memory.fill (i32.const 56401) (i32.const 3) (i32.const 988))
-         (memory.fill (i32.const 37962) (i32.const 4) (i32.const 322))
-         (memory.fill (i32.const 7977) (i32.const 5) (i32.const 1994))
-         (memory.fill (i32.const 22714) (i32.const 6) (i32.const 3036))
-         (memory.fill (i32.const 16882) (i32.const 7) (i32.const 2372))
-         (memory.fill (i32.const 43491) (i32.const 8) (i32.const 835))
-         (memory.fill (i32.const 124) (i32.const 9) (i32.const 1393))
-         (memory.fill (i32.const 2132) (i32.const 10) (i32.const 2758))
-         (memory.fill (i32.const 8987) (i32.const 11) (i32.const 3098))
-         (memory.fill (i32.const 52711) (i32.const 12) (i32.const 741))
-         (memory.fill (i32.const 3958) (i32.const 13) (i32.const 2823))
-         (memory.fill (i32.const 49715) (i32.const 14) (i32.const 1280))
-         (memory.fill (i32.const 50377) (i32.const 15) (i32.const 1466))
-         (memory.fill (i32.const 20493) (i32.const 16) (i32.const 3158))
-         (memory.fill (i32.const 47665) (i32.const 17) (i32.const 544))
-         (memory.fill (i32.const 12451) (i32.const 18) (i32.const 2669))
-         (memory.fill (i32.const 24869) (i32.const 19) (i32.const 2651))
-         (memory.fill (i32.const 45317) (i32.const 20) (i32.const 1570))
-         (memory.fill (i32.const 43096) (i32.const 21) (i32.const 1691))
-         (memory.fill (i32.const 33886) (i32.const 22) (i32.const 646))
-         (memory.fill (i32.const 48555) (i32.const 23) (i32.const 1858))
-         (memory.fill (i32.const 53453) (i32.const 24) (i32.const 2657))
-         (memory.fill (i32.const 30363) (i32.const 25) (i32.const 981))
-         (memory.fill (i32.const 9300) (i32.const 26) (i32.const 1807))
-         (memory.fill (i32.const 50190) (i32.const 27) (i32.const 487))
-         (memory.fill (i32.const 62753) (i32.const 28) (i32.const 530))
-         (memory.fill (i32.const 36316) (i32.const 29) (i32.const 943))
-         (memory.fill (i32.const 6768) (i32.const 30) (i32.const 381))
-         (memory.fill (i32.const 51262) (i32.const 31) (i32.const 3089))
-         (memory.fill (i32.const 49729) (i32.const 32) (i32.const 658))
-         (memory.fill (i32.const 44540) (i32.const 33) (i32.const 1702))
-         (memory.fill (i32.const 33342) (i32.const 34) (i32.const 1092))
-         (memory.fill (i32.const 50814) (i32.const 35) (i32.const 1410))
-         (memory.fill (i32.const 47594) (i32.const 36) (i32.const 2204))
-         (memory.fill (i32.const 54123) (i32.const 37) (i32.const 2394))
-         (memory.fill (i32.const 55183) (i32.const 38) (i32.const 250))
-         (memory.fill (i32.const 22620) (i32.const 39) (i32.const 2097))
-         (memory.fill (i32.const 17132) (i32.const 40) (i32.const 3264))
-         (memory.fill (i32.const 54331) (i32.const 41) (i32.const 3299))
-         (memory.fill (i32.const 39474) (i32.const 42) (i32.const 2796))
-         (memory.fill (i32.const 36156) (i32.const 43) (i32.const 2070))
-         (memory.fill (i32.const 35308) (i32.const 44) (i32.const 2763))
-         (memory.fill (i32.const 32731) (i32.const 45) (i32.const 312))
-         (memory.fill (i32.const 63746) (i32.const 46) (i32.const 192))
-         (memory.fill (i32.const 30974) (i32.const 47) (i32.const 596))
-         (memory.fill (i32.const 16635) (i32.const 48) (i32.const 501))
-         (memory.fill (i32.const 57002) (i32.const 49) (i32.const 686))
-         (memory.fill (i32.const 34299) (i32.const 50) (i32.const 385))
-         (memory.fill (i32.const 60881) (i32.const 51) (i32.const 903))
-         (memory.fill (i32.const 61445) (i32.const 52) (i32.const 2390))
-         (memory.fill (i32.const 46972) (i32.const 53) (i32.const 1441))
-         (memory.fill (i32.const 25973) (i32.const 54) (i32.const 3162))
-         (memory.fill (i32.const 5566) (i32.const 55) (i32.const 2135))
-         (memory.fill (i32.const 35977) (i32.const 56) (i32.const 519))
-         (memory.fill (i32.const 44892) (i32.const 57) (i32.const 3280))
-         (memory.fill (i32.const 46760) (i32.const 58) (i32.const 1678))
-         (memory.fill (i32.const 46607) (i32.const 59) (i32.const 3168))
-         (memory.fill (i32.const 22449) (i32.const 60) (i32.const 1441))
-         (memory.fill (i32.const 58609) (i32.const 61) (i32.const 663))
-         (memory.fill (i32.const 32261) (i32.const 62) (i32.const 1671))
-         (memory.fill (i32.const 3063) (i32.const 63) (i32.const 721))
-         (memory.fill (i32.const 34025) (i32.const 64) (i32.const 84))
-         (memory.fill (i32.const 33338) (i32.const 65) (i32.const 2029))
-         (memory.fill (i32.const 36810) (i32.const 66) (i32.const 29))
-         (memory.fill (i32.const 19147) (i32.const 67) (i32.const 3034))
-         (memory.fill (i32.const 12616) (i32.const 68) (i32.const 1043))
-         (memory.fill (i32.const 18276) (i32.const 69) (i32.const 3324))
-         (memory.fill (i32.const 4639) (i32.const 70) (i32.const 1091))
-         (memory.fill (i32.const 16158) (i32.const 71) (i32.const 1997))
-         (memory.fill (i32.const 18204) (i32.const 72) (i32.const 2259))
-         (memory.fill (i32.const 50532) (i32.const 73) (i32.const 3189))
-         (memory.fill (i32.const 11028) (i32.const 74) (i32.const 1968))
-         (memory.fill (i32.const 15962) (i32.const 75) (i32.const 1455))
-         (memory.fill (i32.const 45406) (i32.const 76) (i32.const 1177))
-         (memory.fill (i32.const 54137) (i32.const 77) (i32.const 1568))
-         (memory.fill (i32.const 33083) (i32.const 78) (i32.const 1642))
-         (memory.fill (i32.const 61028) (i32.const 79) (i32.const 3284))
-         (memory.fill (i32.const 51729) (i32.const 80) (i32.const 223))
-         (memory.fill (i32.const 4361) (i32.const 81) (i32.const 2171))
-         (memory.fill (i32.const 57514) (i32.const 82) (i32.const 1322))
-         (memory.fill (i32.const 55724) (i32.const 83) (i32.const 2648))
-         (memory.fill (i32.const 24091) (i32.const 84) (i32.const 1045))
-         (memory.fill (i32.const 43183) (i32.const 85) (i32.const 3097))
-         (memory.fill (i32.const 32307) (i32.const 86) (i32.const 2796))
-         (memory.fill (i32.const 3811) (i32.const 87) (i32.const 2010))
-         (memory.fill (i32.const 54856) (i32.const 88) (i32.const 0))
-         (memory.fill (i32.const 49941) (i32.const 89) (i32.const 2069))
-         (memory.fill (i32.const 20411) (i32.const 90) (i32.const 2896))
-         (memory.fill (i32.const 33826) (i32.const 91) (i32.const 192))
-         (memory.fill (i32.const 9402) (i32.const 92) (i32.const 2195))
-         (memory.fill (i32.const 12413) (i32.const 93) (i32.const 24))
-         (memory.fill (i32.const 14091) (i32.const 94) (i32.const 577))
-         (memory.fill (i32.const 44058) (i32.const 95) (i32.const 2089))
-         (memory.fill (i32.const 36735) (i32.const 96) (i32.const 3436))
-         (memory.fill (i32.const 23288) (i32.const 97) (i32.const 2765))
-         (memory.fill (i32.const 6392) (i32.const 98) (i32.const 830))
-         (memory.fill (i32.const 33307) (i32.const 99) (i32.const 1938))
-         (memory.fill (i32.const 21941) (i32.const 100) (i32.const 2750))
-         (memory.copy (i32.const 59214) (i32.const 54248) (i32.const 2098))
-         (memory.copy (i32.const 63026) (i32.const 39224) (i32.const 230))
-         (memory.copy (i32.const 51833) (i32.const 23629) (i32.const 2300))
-         (memory.copy (i32.const 6708) (i32.const 23996) (i32.const 639))
-         (memory.copy (i32.const 6990) (i32.const 33399) (i32.const 1097))
-         (memory.copy (i32.const 19403) (i32.const 10348) (i32.const 3197))
-         (memory.copy (i32.const 27308) (i32.const 54406) (i32.const 100))
-         (memory.copy (i32.const 27221) (i32.const 43682) (i32.const 1717))
-         (memory.copy (i32.const 60528) (i32.const 8629) (i32.const 119))
-         (memory.copy (i32.const 5947) (i32.const 2308) (i32.const 658))
-         (memory.copy (i32.const 4787) (i32.const 51631) (i32.const 2269))
-         (memory.copy (i32.const 12617) (i32.const 19197) (i32.const 833))
-         (memory.copy (i32.const 11854) (i32.const 46505) (i32.const 3300))
-         (memory.copy (i32.const 11376) (i32.const 45012) (i32.const 2281))
-         (memory.copy (i32.const 34186) (i32.const 6697) (i32.const 2572))
-         (memory.copy (i32.const 4936) (i32.const 1690) (i32.const 1328))
-         (memory.copy (i32.const 63164) (i32.const 7637) (i32.const 1670))
-         (memory.copy (i32.const 44568) (i32.const 18344) (i32.const 33))
-         (memory.copy (i32.const 43918) (i32.const 22348) (i32.const 1427))
-         (memory.copy (i32.const 46637) (i32.const 49819) (i32.const 1434))
-         (memory.copy (i32.const 63684) (i32.const 8755) (i32.const 834))
-         (memory.copy (i32.const 33485) (i32.const 20131) (i32.const 3317))
-         (memory.copy (i32.const 40575) (i32.const 54317) (i32.const 3201))
-         (memory.copy (i32.const 25812) (i32.const 59254) (i32.const 2452))
-         (memory.copy (i32.const 19678) (i32.const 56882) (i32.const 346))
-         (memory.copy (i32.const 15852) (i32.const 35914) (i32.const 2430))
-         (memory.copy (i32.const 11824) (i32.const 35574) (i32.const 300))
-         (memory.copy (i32.const 59427) (i32.const 13957) (i32.const 3153))
-         (memory.copy (i32.const 34299) (i32.const 60594) (i32.const 1281))
-         (memory.copy (i32.const 8964) (i32.const 12276) (i32.const 943))
-         (memory.copy (i32.const 2827) (i32.const 10425) (i32.const 1887))
-         (memory.copy (i32.const 43194) (i32.const 43910) (i32.const 738))
-         (memory.copy (i32.const 63038) (i32.const 18949) (i32.const 122))
-         (memory.copy (i32.const 24044) (i32.const 44761) (i32.const 1755))
-         (memory.copy (i32.const 22608) (i32.const 14755) (i32.const 702))
-         (memory.copy (i32.const 11284) (i32.const 26579) (i32.const 1830))
-         (memory.copy (i32.const 23092) (i32.const 20471) (i32.const 1064))
-         (memory.copy (i32.const 57248) (i32.const 54770) (i32.const 2631))
-         (memory.copy (i32.const 25492) (i32.const 1025) (i32.const 3113))
-         (memory.copy (i32.const 49588) (i32.const 44220) (i32.const 975))
-         (memory.copy (i32.const 28280) (i32.const 41722) (i32.const 2336))
-         (memory.copy (i32.const 61289) (i32.const 230) (i32.const 2872))
-         (memory.copy (i32.const 22480) (i32.const 52506) (i32.const 2197))
-         (memory.copy (i32.const 40553) (i32.const 9578) (i32.const 1958))
-         (memory.copy (i32.const 29004) (i32.const 20862) (i32.const 2186))
-         (memory.copy (i32.const 53029) (i32.const 43955) (i32.const 1037))
-         (memory.copy (i32.const 25476) (i32.const 35667) (i32.const 1650))
-         (memory.copy (i32.const 58516) (i32.const 45819) (i32.const 1986))
-         (memory.copy (i32.const 38297) (i32.const 5776) (i32.const 1955))
-         (memory.copy (i32.const 28503) (i32.const 55364) (i32.const 2368))
-         (memory.copy (i32.const 62619) (i32.const 18108) (i32.const 1356))
-         (memory.copy (i32.const 50149) (i32.const 13861) (i32.const 382))
-         (memory.copy (i32.const 16904) (i32.const 36341) (i32.const 1900))
-         (memory.copy (i32.const 48098) (i32.const 11358) (i32.const 2807))
-         (memory.copy (i32.const 28512) (i32.const 40362) (i32.const 323))
-         (memory.copy (i32.const 35506) (i32.const 27856) (i32.const 1670))
-         (memory.copy (i32.const 62970) (i32.const 53332) (i32.const 1341))
-         (memory.copy (i32.const 14133) (i32.const 46312) (i32.const 644))
-         (memory.copy (i32.const 29030) (i32.const 19074) (i32.const 496))
-         (memory.copy (i32.const 44952) (i32.const 47577) (i32.const 2784))
-         (memory.copy (i32.const 39559) (i32.const 44661) (i32.const 1350))
-         (memory.copy (i32.const 10352) (i32.const 29274) (i32.const 1475))
-         (memory.copy (i32.const 46911) (i32.const 46178) (i32.const 1467))
-         (memory.copy (i32.const 4905) (i32.const 28740) (i32.const 1895))
-         (memory.copy (i32.const 38012) (i32.const 57253) (i32.const 1751))
-         (memory.copy (i32.const 26446) (i32.const 27223) (i32.const 1127))
-         (memory.copy (i32.const 58835) (i32.const 24657) (i32.const 1063))
-         (memory.copy (i32.const 61356) (i32.const 38790) (i32.const 766))
-         (memory.copy (i32.const 44160) (i32.const 2284) (i32.const 1520))
-         (memory.copy (i32.const 32740) (i32.const 47237) (i32.const 3014))
-         (memory.copy (i32.const 11148) (i32.const 21260) (i32.const 1011))
-         (memory.copy (i32.const 7665) (i32.const 31612) (i32.const 3034))
-         (memory.copy (i32.const 18044) (i32.const 12987) (i32.const 3320))
-         (memory.copy (i32.const 57306) (i32.const 55905) (i32.const 308))
-         (memory.copy (i32.const 24675) (i32.const 16815) (i32.const 1155))
-         (memory.copy (i32.const 19900) (i32.const 10115) (i32.const 722))
-         (memory.copy (i32.const 2921) (i32.const 5935) (i32.const 2370))
-         (memory.copy (i32.const 32255) (i32.const 50095) (i32.const 2926))
-         (memory.copy (i32.const 15126) (i32.const 17299) (i32.const 2607))
-         (memory.copy (i32.const 45575) (i32.const 28447) (i32.const 2045))
-         (memory.copy (i32.const 55149) (i32.const 36113) (i32.const 2596))
-         (memory.copy (i32.const 28461) (i32.const 54157) (i32.const 1168))
-         (memory.copy (i32.const 47951) (i32.const 53385) (i32.const 3137))
-         (memory.copy (i32.const 30646) (i32.const 45155) (i32.const 2649))
-         (memory.copy (i32.const 5057) (i32.const 4295) (i32.const 52))
-         (memory.copy (i32.const 6692) (i32.const 24195) (i32.const 441))
-         (memory.copy (i32.const 32984) (i32.const 27117) (i32.const 3445))
-         (memory.copy (i32.const 32530) (i32.const 59372) (i32.const 2785))
-         (memory.copy (i32.const 34361) (i32.const 8962) (i32.const 2406))
-         (memory.copy (i32.const 17893) (i32.const 54538) (i32.const 3381))
-         (memory.copy (i32.const 22685) (i32.const 44151) (i32.const 136))
-         (memory.copy (i32.const 59089) (i32.const 7077) (i32.const 1045))
-         (memory.copy (i32.const 42945) (i32.const 55028) (i32.const 2389))
-         (memory.copy (i32.const 44693) (i32.const 20138) (i32.const 877))
-         (memory.copy (i32.const 36810) (i32.const 25196) (i32.const 3447))
-         (memory.copy (i32.const 45742) (i32.const 31888) (i32.const 854))
-         (memory.copy (i32.const 24236) (i32.const 31866) (i32.const 1377))
-         (memory.copy (i32.const 33778) (i32.const 692) (i32.const 1594))
-         (memory.copy (i32.const 60618) (i32.const 18585) (i32.const 2987))
-         (memory.copy (i32.const 50370) (i32.const 41271) (i32.const 1406))
-       )
+  (memory 1 1)
+  (func (export "test")
+    (memory.fill (i32.const 17767) (i32.const 1) (i32.const 1344))
+    (memory.fill (i32.const 39017) (i32.const 2) (i32.const 1055))
+    (memory.fill (i32.const 56401) (i32.const 3) (i32.const 988))
+    (memory.fill (i32.const 37962) (i32.const 4) (i32.const 322))
+    (memory.fill (i32.const 7977) (i32.const 5) (i32.const 1994))
+    (memory.fill (i32.const 22714) (i32.const 6) (i32.const 3036))
+    (memory.fill (i32.const 16882) (i32.const 7) (i32.const 2372))
+    (memory.fill (i32.const 43491) (i32.const 8) (i32.const 835))
+    (memory.fill (i32.const 124) (i32.const 9) (i32.const 1393))
+    (memory.fill (i32.const 2132) (i32.const 10) (i32.const 2758))
+    (memory.fill (i32.const 8987) (i32.const 11) (i32.const 3098))
+    (memory.fill (i32.const 52711) (i32.const 12) (i32.const 741))
+    (memory.fill (i32.const 3958) (i32.const 13) (i32.const 2823))
+    (memory.fill (i32.const 49715) (i32.const 14) (i32.const 1280))
+    (memory.fill (i32.const 50377) (i32.const 15) (i32.const 1466))
+    (memory.fill (i32.const 20493) (i32.const 16) (i32.const 3158))
+    (memory.fill (i32.const 47665) (i32.const 17) (i32.const 544))
+    (memory.fill (i32.const 12451) (i32.const 18) (i32.const 2669))
+    (memory.fill (i32.const 24869) (i32.const 19) (i32.const 2651))
+    (memory.fill (i32.const 45317) (i32.const 20) (i32.const 1570))
+    (memory.fill (i32.const 43096) (i32.const 21) (i32.const 1691))
+    (memory.fill (i32.const 33886) (i32.const 22) (i32.const 646))
+    (memory.fill (i32.const 48555) (i32.const 23) (i32.const 1858))
+    (memory.fill (i32.const 53453) (i32.const 24) (i32.const 2657))
+    (memory.fill (i32.const 30363) (i32.const 25) (i32.const 981))
+    (memory.fill (i32.const 9300) (i32.const 26) (i32.const 1807))
+    (memory.fill (i32.const 50190) (i32.const 27) (i32.const 487))
+    (memory.fill (i32.const 62753) (i32.const 28) (i32.const 530))
+    (memory.fill (i32.const 36316) (i32.const 29) (i32.const 943))
+    (memory.fill (i32.const 6768) (i32.const 30) (i32.const 381))
+    (memory.fill (i32.const 51262) (i32.const 31) (i32.const 3089))
+    (memory.fill (i32.const 49729) (i32.const 32) (i32.const 658))
+    (memory.fill (i32.const 44540) (i32.const 33) (i32.const 1702))
+    (memory.fill (i32.const 33342) (i32.const 34) (i32.const 1092))
+    (memory.fill (i32.const 50814) (i32.const 35) (i32.const 1410))
+    (memory.fill (i32.const 47594) (i32.const 36) (i32.const 2204))
+    (memory.fill (i32.const 54123) (i32.const 37) (i32.const 2394))
+    (memory.fill (i32.const 55183) (i32.const 38) (i32.const 250))
+    (memory.fill (i32.const 22620) (i32.const 39) (i32.const 2097))
+    (memory.fill (i32.const 17132) (i32.const 40) (i32.const 3264))
+    (memory.fill (i32.const 54331) (i32.const 41) (i32.const 3299))
+    (memory.fill (i32.const 39474) (i32.const 42) (i32.const 2796))
+    (memory.fill (i32.const 36156) (i32.const 43) (i32.const 2070))
+    (memory.fill (i32.const 35308) (i32.const 44) (i32.const 2763))
+    (memory.fill (i32.const 32731) (i32.const 45) (i32.const 312))
+    (memory.fill (i32.const 63746) (i32.const 46) (i32.const 192))
+    (memory.fill (i32.const 30974) (i32.const 47) (i32.const 596))
+    (memory.fill (i32.const 16635) (i32.const 48) (i32.const 501))
+    (memory.fill (i32.const 57002) (i32.const 49) (i32.const 686))
+    (memory.fill (i32.const 34299) (i32.const 50) (i32.const 385))
+    (memory.fill (i32.const 60881) (i32.const 51) (i32.const 903))
+    (memory.fill (i32.const 61445) (i32.const 52) (i32.const 2390))
+    (memory.fill (i32.const 46972) (i32.const 53) (i32.const 1441))
+    (memory.fill (i32.const 25973) (i32.const 54) (i32.const 3162))
+    (memory.fill (i32.const 5566) (i32.const 55) (i32.const 2135))
+    (memory.fill (i32.const 35977) (i32.const 56) (i32.const 519))
+    (memory.fill (i32.const 44892) (i32.const 57) (i32.const 3280))
+    (memory.fill (i32.const 46760) (i32.const 58) (i32.const 1678))
+    (memory.fill (i32.const 46607) (i32.const 59) (i32.const 3168))
+    (memory.fill (i32.const 22449) (i32.const 60) (i32.const 1441))
+    (memory.fill (i32.const 58609) (i32.const 61) (i32.const 663))
+    (memory.fill (i32.const 32261) (i32.const 62) (i32.const 1671))
+    (memory.fill (i32.const 3063) (i32.const 63) (i32.const 721))
+    (memory.fill (i32.const 34025) (i32.const 64) (i32.const 84))
+    (memory.fill (i32.const 33338) (i32.const 65) (i32.const 2029))
+    (memory.fill (i32.const 36810) (i32.const 66) (i32.const 29))
+    (memory.fill (i32.const 19147) (i32.const 67) (i32.const 3034))
+    (memory.fill (i32.const 12616) (i32.const 68) (i32.const 1043))
+    (memory.fill (i32.const 18276) (i32.const 69) (i32.const 3324))
+    (memory.fill (i32.const 4639) (i32.const 70) (i32.const 1091))
+    (memory.fill (i32.const 16158) (i32.const 71) (i32.const 1997))
+    (memory.fill (i32.const 18204) (i32.const 72) (i32.const 2259))
+    (memory.fill (i32.const 50532) (i32.const 73) (i32.const 3189))
+    (memory.fill (i32.const 11028) (i32.const 74) (i32.const 1968))
+    (memory.fill (i32.const 15962) (i32.const 75) (i32.const 1455))
+    (memory.fill (i32.const 45406) (i32.const 76) (i32.const 1177))
+    (memory.fill (i32.const 54137) (i32.const 77) (i32.const 1568))
+    (memory.fill (i32.const 33083) (i32.const 78) (i32.const 1642))
+    (memory.fill (i32.const 61028) (i32.const 79) (i32.const 3284))
+    (memory.fill (i32.const 51729) (i32.const 80) (i32.const 223))
+    (memory.fill (i32.const 4361) (i32.const 81) (i32.const 2171))
+    (memory.fill (i32.const 57514) (i32.const 82) (i32.const 1322))
+    (memory.fill (i32.const 55724) (i32.const 83) (i32.const 2648))
+    (memory.fill (i32.const 24091) (i32.const 84) (i32.const 1045))
+    (memory.fill (i32.const 43183) (i32.const 85) (i32.const 3097))
+    (memory.fill (i32.const 32307) (i32.const 86) (i32.const 2796))
+    (memory.fill (i32.const 3811) (i32.const 87) (i32.const 2010))
+    (memory.fill (i32.const 54856) (i32.const 88) (i32.const 0))
+    (memory.fill (i32.const 49941) (i32.const 89) (i32.const 2069))
+    (memory.fill (i32.const 20411) (i32.const 90) (i32.const 2896))
+    (memory.fill (i32.const 33826) (i32.const 91) (i32.const 192))
+    (memory.fill (i32.const 9402) (i32.const 92) (i32.const 2195))
+    (memory.fill (i32.const 12413) (i32.const 93) (i32.const 24))
+    (memory.fill (i32.const 14091) (i32.const 94) (i32.const 577))
+    (memory.fill (i32.const 44058) (i32.const 95) (i32.const 2089))
+    (memory.fill (i32.const 36735) (i32.const 96) (i32.const 3436))
+    (memory.fill (i32.const 23288) (i32.const 97) (i32.const 2765))
+    (memory.fill (i32.const 6392) (i32.const 98) (i32.const 830))
+    (memory.fill (i32.const 33307) (i32.const 99) (i32.const 1938))
+    (memory.fill (i32.const 21941) (i32.const 100) (i32.const 2750))
+    (memory.copy (i32.const 59214) (i32.const 54248) (i32.const 2098))
+    (memory.copy (i32.const 63026) (i32.const 39224) (i32.const 230))
+    (memory.copy (i32.const 51833) (i32.const 23629) (i32.const 2300))
+    (memory.copy (i32.const 6708) (i32.const 23996) (i32.const 639))
+    (memory.copy (i32.const 6990) (i32.const 33399) (i32.const 1097))
+    (memory.copy (i32.const 19403) (i32.const 10348) (i32.const 3197))
+    (memory.copy (i32.const 27308) (i32.const 54406) (i32.const 100))
+    (memory.copy (i32.const 27221) (i32.const 43682) (i32.const 1717))
+    (memory.copy (i32.const 60528) (i32.const 8629) (i32.const 119))
+    (memory.copy (i32.const 5947) (i32.const 2308) (i32.const 658))
+    (memory.copy (i32.const 4787) (i32.const 51631) (i32.const 2269))
+    (memory.copy (i32.const 12617) (i32.const 19197) (i32.const 833))
+    (memory.copy (i32.const 11854) (i32.const 46505) (i32.const 3300))
+    (memory.copy (i32.const 11376) (i32.const 45012) (i32.const 2281))
+    (memory.copy (i32.const 34186) (i32.const 6697) (i32.const 2572))
+    (memory.copy (i32.const 4936) (i32.const 1690) (i32.const 1328))
+    (memory.copy (i32.const 63164) (i32.const 7637) (i32.const 1670))
+    (memory.copy (i32.const 44568) (i32.const 18344) (i32.const 33))
+    (memory.copy (i32.const 43918) (i32.const 22348) (i32.const 1427))
+    (memory.copy (i32.const 46637) (i32.const 49819) (i32.const 1434))
+    (memory.copy (i32.const 63684) (i32.const 8755) (i32.const 834))
+    (memory.copy (i32.const 33485) (i32.const 20131) (i32.const 3317))
+    (memory.copy (i32.const 40575) (i32.const 54317) (i32.const 3201))
+    (memory.copy (i32.const 25812) (i32.const 59254) (i32.const 2452))
+    (memory.copy (i32.const 19678) (i32.const 56882) (i32.const 346))
+    (memory.copy (i32.const 15852) (i32.const 35914) (i32.const 2430))
+    (memory.copy (i32.const 11824) (i32.const 35574) (i32.const 300))
+    (memory.copy (i32.const 59427) (i32.const 13957) (i32.const 3153))
+    (memory.copy (i32.const 34299) (i32.const 60594) (i32.const 1281))
+    (memory.copy (i32.const 8964) (i32.const 12276) (i32.const 943))
+    (memory.copy (i32.const 2827) (i32.const 10425) (i32.const 1887))
+    (memory.copy (i32.const 43194) (i32.const 43910) (i32.const 738))
+    (memory.copy (i32.const 63038) (i32.const 18949) (i32.const 122))
+    (memory.copy (i32.const 24044) (i32.const 44761) (i32.const 1755))
+    (memory.copy (i32.const 22608) (i32.const 14755) (i32.const 702))
+    (memory.copy (i32.const 11284) (i32.const 26579) (i32.const 1830))
+    (memory.copy (i32.const 23092) (i32.const 20471) (i32.const 1064))
+    (memory.copy (i32.const 57248) (i32.const 54770) (i32.const 2631))
+    (memory.copy (i32.const 25492) (i32.const 1025) (i32.const 3113))
+    (memory.copy (i32.const 49588) (i32.const 44220) (i32.const 975))
+    (memory.copy (i32.const 28280) (i32.const 41722) (i32.const 2336))
+    (memory.copy (i32.const 61289) (i32.const 230) (i32.const 2872))
+    (memory.copy (i32.const 22480) (i32.const 52506) (i32.const 2197))
+    (memory.copy (i32.const 40553) (i32.const 9578) (i32.const 1958))
+    (memory.copy (i32.const 29004) (i32.const 20862) (i32.const 2186))
+    (memory.copy (i32.const 53029) (i32.const 43955) (i32.const 1037))
+    (memory.copy (i32.const 25476) (i32.const 35667) (i32.const 1650))
+    (memory.copy (i32.const 58516) (i32.const 45819) (i32.const 1986))
+    (memory.copy (i32.const 38297) (i32.const 5776) (i32.const 1955))
+    (memory.copy (i32.const 28503) (i32.const 55364) (i32.const 2368))
+    (memory.copy (i32.const 62619) (i32.const 18108) (i32.const 1356))
+    (memory.copy (i32.const 50149) (i32.const 13861) (i32.const 382))
+    (memory.copy (i32.const 16904) (i32.const 36341) (i32.const 1900))
+    (memory.copy (i32.const 48098) (i32.const 11358) (i32.const 2807))
+    (memory.copy (i32.const 28512) (i32.const 40362) (i32.const 323))
+    (memory.copy (i32.const 35506) (i32.const 27856) (i32.const 1670))
+    (memory.copy (i32.const 62970) (i32.const 53332) (i32.const 1341))
+    (memory.copy (i32.const 14133) (i32.const 46312) (i32.const 644))
+    (memory.copy (i32.const 29030) (i32.const 19074) (i32.const 496))
+    (memory.copy (i32.const 44952) (i32.const 47577) (i32.const 2784))
+    (memory.copy (i32.const 39559) (i32.const 44661) (i32.const 1350))
+    (memory.copy (i32.const 10352) (i32.const 29274) (i32.const 1475))
+    (memory.copy (i32.const 46911) (i32.const 46178) (i32.const 1467))
+    (memory.copy (i32.const 4905) (i32.const 28740) (i32.const 1895))
+    (memory.copy (i32.const 38012) (i32.const 57253) (i32.const 1751))
+    (memory.copy (i32.const 26446) (i32.const 27223) (i32.const 1127))
+    (memory.copy (i32.const 58835) (i32.const 24657) (i32.const 1063))
+    (memory.copy (i32.const 61356) (i32.const 38790) (i32.const 766))
+    (memory.copy (i32.const 44160) (i32.const 2284) (i32.const 1520))
+    (memory.copy (i32.const 32740) (i32.const 47237) (i32.const 3014))
+    (memory.copy (i32.const 11148) (i32.const 21260) (i32.const 1011))
+    (memory.copy (i32.const 7665) (i32.const 31612) (i32.const 3034))
+    (memory.copy (i32.const 18044) (i32.const 12987) (i32.const 3320))
+    (memory.copy (i32.const 57306) (i32.const 55905) (i32.const 308))
+    (memory.copy (i32.const 24675) (i32.const 16815) (i32.const 1155))
+    (memory.copy (i32.const 19900) (i32.const 10115) (i32.const 722))
+    (memory.copy (i32.const 2921) (i32.const 5935) (i32.const 2370))
+    (memory.copy (i32.const 32255) (i32.const 50095) (i32.const 2926))
+    (memory.copy (i32.const 15126) (i32.const 17299) (i32.const 2607))
+    (memory.copy (i32.const 45575) (i32.const 28447) (i32.const 2045))
+    (memory.copy (i32.const 55149) (i32.const 36113) (i32.const 2596))
+    (memory.copy (i32.const 28461) (i32.const 54157) (i32.const 1168))
+    (memory.copy (i32.const 47951) (i32.const 53385) (i32.const 3137))
+    (memory.copy (i32.const 30646) (i32.const 45155) (i32.const 2649))
+    (memory.copy (i32.const 5057) (i32.const 4295) (i32.const 52))
+    (memory.copy (i32.const 6692) (i32.const 24195) (i32.const 441))
+    (memory.copy (i32.const 32984) (i32.const 27117) (i32.const 3445))
+    (memory.copy (i32.const 32530) (i32.const 59372) (i32.const 2785))
+    (memory.copy (i32.const 34361) (i32.const 8962) (i32.const 2406))
+    (memory.copy (i32.const 17893) (i32.const 54538) (i32.const 3381))
+    (memory.copy (i32.const 22685) (i32.const 44151) (i32.const 136))
+    (memory.copy (i32.const 59089) (i32.const 7077) (i32.const 1045))
+    (memory.copy (i32.const 42945) (i32.const 55028) (i32.const 2389))
+    (memory.copy (i32.const 44693) (i32.const 20138) (i32.const 877))
+    (memory.copy (i32.const 36810) (i32.const 25196) (i32.const 3447))
+    (memory.copy (i32.const 45742) (i32.const 31888) (i32.const 854))
+    (memory.copy (i32.const 24236) (i32.const 31866) (i32.const 1377))
+    (memory.copy (i32.const 33778) (i32.const 692) (i32.const 1594))
+    (memory.copy (i32.const 60618) (i32.const 18585) (i32.const 2987))
+    (memory.copy (i32.const 50370) (i32.const 41271) (i32.const 1406))
+  )
   
   (func (export "checkRange") (param $from i32) (param $to i32) (param $expected i32) (result i32)
-   (loop $cont
-     (if (i32.eq (local.get $from) (local.get $to))
-         (then
-           (return (i32.const -1))))
-     (if (i32.eq (i32.load8_u (local.get $from)) (local.get $expected))
-         (then
-           (local.set $from (i32.add (local.get $from) (i32.const 1)))
-           (br $cont))))
-   (return (local.get $from)))
+    (loop $cont
+      (if (i32.eq (local.get $from) (local.get $to))
+        (then
+          (return (i32.const -1))))
+      (if (i32.eq (i32.load8_u (local.get $from)) (local.get $expected))
+        (then
+          (local.set $from (i32.add (local.get $from) (i32.const 1)))
+          (br $cont))))
+    (return (local.get $from)))
 )
 (invoke "test")
 
diff --git a/test/core/memory_fill.wast b/test/core/memory_fill.wast
index efa68ea23e..8cc21af317 100644
--- a/test/core/memory_fill.wast
+++ b/test/core/memory_fill.wast
@@ -3,19 +3,18 @@
 ;;
 
 (module
-  
   (memory 1 1)
   
   (func (export "checkRange") (param $from i32) (param $to i32) (param $expected i32) (result i32)
-   (loop $cont
-     (if (i32.eq (local.get $from) (local.get $to))
-         (then
-           (return (i32.const -1))))
-     (if (i32.eq (i32.load8_u (local.get $from)) (local.get $expected))
-         (then
-           (local.set $from (i32.add (local.get $from) (i32.const 1)))
-           (br $cont))))
-   (return (local.get $from)))
+    (loop $cont
+      (if (i32.eq (local.get $from) (local.get $to))
+        (then
+          (return (i32.const -1))))
+      (if (i32.eq (i32.load8_u (local.get $from)) (local.get $expected))
+        (then
+          (local.set $from (i32.add (local.get $from) (i32.const 1)))
+          (br $cont))))
+    (return (local.get $from)))
 
   (func (export "test")
     (memory.fill (i32.const 0xFF00) (i32.const 0x55) (i32.const 256))))
@@ -25,61 +24,55 @@
                (i32.const -1))
 (assert_return (invoke "checkRange" (i32.const 65280) (i32.const 65536) (i32.const 85))
                (i32.const -1))
-
 (module
-  
   (memory 1 1)
   
   (func (export "checkRange") (param $from i32) (param $to i32) (param $expected i32) (result i32)
-   (loop $cont
-     (if (i32.eq (local.get $from) (local.get $to))
-         (then
-           (return (i32.const -1))))
-     (if (i32.eq (i32.load8_u (local.get $from)) (local.get $expected))
-         (then
-           (local.set $from (i32.add (local.get $from) (i32.const 1)))
-           (br $cont))))
-   (return (local.get $from)))
+    (loop $cont
+      (if (i32.eq (local.get $from) (local.get $to))
+        (then
+          (return (i32.const -1))))
+      (if (i32.eq (i32.load8_u (local.get $from)) (local.get $expected))
+        (then
+          (local.set $from (i32.add (local.get $from) (i32.const 1)))
+          (br $cont))))
+    (return (local.get $from)))
 
   (func (export "test")
     (memory.fill (i32.const 0xFF00) (i32.const 0x55) (i32.const 257))))
 (assert_trap (invoke "test") "out of bounds memory access")
 
-
 (module
-  
   (memory 1 1)
   
   (func (export "checkRange") (param $from i32) (param $to i32) (param $expected i32) (result i32)
-   (loop $cont
-     (if (i32.eq (local.get $from) (local.get $to))
-         (then
-           (return (i32.const -1))))
-     (if (i32.eq (i32.load8_u (local.get $from)) (local.get $expected))
-         (then
-           (local.set $from (i32.add (local.get $from) (i32.const 1)))
-           (br $cont))))
-   (return (local.get $from)))
+    (loop $cont
+      (if (i32.eq (local.get $from) (local.get $to))
+        (then
+          (return (i32.const -1))))
+      (if (i32.eq (i32.load8_u (local.get $from)) (local.get $expected))
+        (then
+          (local.set $from (i32.add (local.get $from) (i32.const 1)))
+          (br $cont))))
+    (return (local.get $from)))
 
   (func (export "test")
     (memory.fill (i32.const 0xFFFFFF00) (i32.const 0x55) (i32.const 257))))
 (assert_trap (invoke "test") "out of bounds memory access")
 
-
 (module
-  
   (memory 1 1)
   
   (func (export "checkRange") (param $from i32) (param $to i32) (param $expected i32) (result i32)
-   (loop $cont
-     (if (i32.eq (local.get $from) (local.get $to))
-         (then
-           (return (i32.const -1))))
-     (if (i32.eq (i32.load8_u (local.get $from)) (local.get $expected))
-         (then
-           (local.set $from (i32.add (local.get $from) (i32.const 1)))
-           (br $cont))))
-   (return (local.get $from)))
+    (loop $cont
+      (if (i32.eq (local.get $from) (local.get $to))
+        (then
+          (return (i32.const -1))))
+      (if (i32.eq (i32.load8_u (local.get $from)) (local.get $expected))
+        (then
+          (local.set $from (i32.add (local.get $from) (i32.const 1)))
+          (br $cont))))
+    (return (local.get $from)))
 
   (func (export "test")
     (memory.fill (i32.const 0x12) (i32.const 0x55) (i32.const 0))))
@@ -87,41 +80,37 @@
 
 (assert_return (invoke "checkRange" (i32.const 0) (i32.const 65536) (i32.const 0))
                (i32.const -1))
-
 (module
-  
   (memory 1 1)
   
   (func (export "checkRange") (param $from i32) (param $to i32) (param $expected i32) (result i32)
-   (loop $cont
-     (if (i32.eq (local.get $from) (local.get $to))
-         (then
-           (return (i32.const -1))))
-     (if (i32.eq (i32.load8_u (local.get $from)) (local.get $expected))
-         (then
-           (local.set $from (i32.add (local.get $from) (i32.const 1)))
-           (br $cont))))
-   (return (local.get $from)))
+    (loop $cont
+      (if (i32.eq (local.get $from) (local.get $to))
+        (then
+          (return (i32.const -1))))
+      (if (i32.eq (i32.load8_u (local.get $from)) (local.get $expected))
+        (then
+          (local.set $from (i32.add (local.get $from) (i32.const 1)))
+          (br $cont))))
+    (return (local.get $from)))
 
   (func (export "test")
     (memory.fill (i32.const 0x10000) (i32.const 0x55) (i32.const 0))))
 (invoke "test")
 
-
 (module
-  
   (memory 1 1)
   
   (func (export "checkRange") (param $from i32) (param $to i32) (param $expected i32) (result i32)
-   (loop $cont
-     (if (i32.eq (local.get $from) (local.get $to))
-         (then
-           (return (i32.const -1))))
-     (if (i32.eq (i32.load8_u (local.get $from)) (local.get $expected))
-         (then
-           (local.set $from (i32.add (local.get $from) (i32.const 1)))
-           (br $cont))))
-   (return (local.get $from)))
+    (loop $cont
+      (if (i32.eq (local.get $from) (local.get $to))
+        (then
+          (return (i32.const -1))))
+      (if (i32.eq (i32.load8_u (local.get $from)) (local.get $expected))
+        (then
+          (local.set $from (i32.add (local.get $from) (i32.const 1)))
+          (br $cont))))
+    (return (local.get $from)))
 
   (func (export "test")
     (memory.fill (i32.const 0x1) (i32.const 0xAA) (i32.const 0xFFFE))))
@@ -135,19 +124,18 @@
                (i32.const -1))
 
 (module
-  
   (memory 1 1)
   
   (func (export "checkRange") (param $from i32) (param $to i32) (param $expected i32) (result i32)
-   (loop $cont
-     (if (i32.eq (local.get $from) (local.get $to))
-         (then
-           (return (i32.const -1))))
-     (if (i32.eq (i32.load8_u (local.get $from)) (local.get $expected))
-         (then
-           (local.set $from (i32.add (local.get $from) (i32.const 1)))
-           (br $cont))))
-   (return (local.get $from)))
+    (loop $cont
+      (if (i32.eq (local.get $from) (local.get $to))
+        (then
+          (return (i32.const -1))))
+      (if (i32.eq (i32.load8_u (local.get $from)) (local.get $expected))
+        (then
+          (local.set $from (i32.add (local.get $from) (i32.const 1)))
+          (br $cont))))
+    (return (local.get $from)))
 
   (func (export "test")
      (memory.fill (i32.const 0x12) (i32.const 0x55) (i32.const 10))
@@ -164,14 +152,12 @@
                (i32.const -1))
 (assert_return (invoke "checkRange" (i32.const 28) (i32.const 65536) (i32.const 0))
                (i32.const -1))
-
 (assert_invalid
   (module
     (func (export "testfn")
       (memory.fill (i32.const 10) (i32.const 20) (i32.const 30))))
   "unknown memory 0")
 
-
 (assert_invalid
   (module
     (memory 1 1)
@@ -179,7 +165,6 @@
       (memory.fill (i32.const 10) (i32.const 20) (f32.const 30))))
   "type mismatch")
 
-
 (assert_invalid
   (module
     (memory 1 1)
@@ -187,7 +172,6 @@
       (memory.fill (i32.const 10) (i32.const 20) (i64.const 30))))
   "type mismatch")
 
-
 (assert_invalid
   (module
     (memory 1 1)
@@ -195,7 +179,6 @@
       (memory.fill (i32.const 10) (i32.const 20) (f64.const 30))))
   "type mismatch")
 
-
 (assert_invalid
   (module
     (memory 1 1)
@@ -203,7 +186,6 @@
       (memory.fill (i32.const 10) (f32.const 20) (i32.const 30))))
   "type mismatch")
 
-
 (assert_invalid
   (module
     (memory 1 1)
@@ -211,7 +193,6 @@
       (memory.fill (i32.const 10) (f32.const 20) (f32.const 30))))
   "type mismatch")
 
-
 (assert_invalid
   (module
     (memory 1 1)
@@ -219,7 +200,6 @@
       (memory.fill (i32.const 10) (f32.const 20) (i64.const 30))))
   "type mismatch")
 
-
 (assert_invalid
   (module
     (memory 1 1)
@@ -227,7 +207,6 @@
       (memory.fill (i32.const 10) (f32.const 20) (f64.const 30))))
   "type mismatch")
 
-
 (assert_invalid
   (module
     (memory 1 1)
@@ -235,7 +214,6 @@
       (memory.fill (i32.const 10) (i64.const 20) (i32.const 30))))
   "type mismatch")
 
-
 (assert_invalid
   (module
     (memory 1 1)
@@ -243,7 +221,6 @@
       (memory.fill (i32.const 10) (i64.const 20) (f32.const 30))))
   "type mismatch")
 
-
 (assert_invalid
   (module
     (memory 1 1)
@@ -251,7 +228,6 @@
       (memory.fill (i32.const 10) (i64.const 20) (i64.const 30))))
   "type mismatch")
 
-
 (assert_invalid
   (module
     (memory 1 1)
@@ -259,7 +235,6 @@
       (memory.fill (i32.const 10) (i64.const 20) (f64.const 30))))
   "type mismatch")
 
-
 (assert_invalid
   (module
     (memory 1 1)
@@ -267,7 +242,6 @@
       (memory.fill (i32.const 10) (f64.const 20) (i32.const 30))))
   "type mismatch")
 
-
 (assert_invalid
   (module
     (memory 1 1)
@@ -275,7 +249,6 @@
       (memory.fill (i32.const 10) (f64.const 20) (f32.const 30))))
   "type mismatch")
 
-
 (assert_invalid
   (module
     (memory 1 1)
@@ -283,7 +256,6 @@
       (memory.fill (i32.const 10) (f64.const 20) (i64.const 30))))
   "type mismatch")
 
-
 (assert_invalid
   (module
     (memory 1 1)
@@ -291,7 +263,6 @@
       (memory.fill (i32.const 10) (f64.const 20) (f64.const 30))))
   "type mismatch")
 
-
 (assert_invalid
   (module
     (memory 1 1)
@@ -299,7 +270,6 @@
       (memory.fill (f32.const 10) (i32.const 20) (i32.const 30))))
   "type mismatch")
 
-
 (assert_invalid
   (module
     (memory 1 1)
@@ -307,7 +277,6 @@
       (memory.fill (f32.const 10) (i32.const 20) (f32.const 30))))
   "type mismatch")
 
-
 (assert_invalid
   (module
     (memory 1 1)
@@ -315,7 +284,6 @@
       (memory.fill (f32.const 10) (i32.const 20) (i64.const 30))))
   "type mismatch")
 
-
 (assert_invalid
   (module
     (memory 1 1)
@@ -323,7 +291,6 @@
       (memory.fill (f32.const 10) (i32.const 20) (f64.const 30))))
   "type mismatch")
 
-
 (assert_invalid
   (module
     (memory 1 1)
@@ -331,7 +298,6 @@
       (memory.fill (f32.const 10) (f32.const 20) (i32.const 30))))
   "type mismatch")
 
-
 (assert_invalid
   (module
     (memory 1 1)
@@ -339,7 +305,6 @@
       (memory.fill (f32.const 10) (f32.const 20) (f32.const 30))))
   "type mismatch")
 
-
 (assert_invalid
   (module
     (memory 1 1)
@@ -347,7 +312,6 @@
       (memory.fill (f32.const 10) (f32.const 20) (i64.const 30))))
   "type mismatch")
 
-
 (assert_invalid
   (module
     (memory 1 1)
@@ -355,7 +319,6 @@
       (memory.fill (f32.const 10) (f32.const 20) (f64.const 30))))
   "type mismatch")
 
-
 (assert_invalid
   (module
     (memory 1 1)
@@ -363,7 +326,6 @@
       (memory.fill (f32.const 10) (i64.const 20) (i32.const 30))))
   "type mismatch")
 
-
 (assert_invalid
   (module
     (memory 1 1)
@@ -371,7 +333,6 @@
       (memory.fill (f32.const 10) (i64.const 20) (f32.const 30))))
   "type mismatch")
 
-
 (assert_invalid
   (module
     (memory 1 1)
@@ -379,7 +340,6 @@
       (memory.fill (f32.const 10) (i64.const 20) (i64.const 30))))
   "type mismatch")
 
-
 (assert_invalid
   (module
     (memory 1 1)
@@ -387,7 +347,6 @@
       (memory.fill (f32.const 10) (i64.const 20) (f64.const 30))))
   "type mismatch")
 
-
 (assert_invalid
   (module
     (memory 1 1)
@@ -395,7 +354,6 @@
       (memory.fill (f32.const 10) (f64.const 20) (i32.const 30))))
   "type mismatch")
 
-
 (assert_invalid
   (module
     (memory 1 1)
@@ -403,7 +361,6 @@
       (memory.fill (f32.const 10) (f64.const 20) (f32.const 30))))
   "type mismatch")
 
-
 (assert_invalid
   (module
     (memory 1 1)
@@ -411,7 +368,6 @@
       (memory.fill (f32.const 10) (f64.const 20) (i64.const 30))))
   "type mismatch")
 
-
 (assert_invalid
   (module
     (memory 1 1)
@@ -419,7 +375,6 @@
       (memory.fill (f32.const 10) (f64.const 20) (f64.const 30))))
   "type mismatch")
 
-
 (assert_invalid
   (module
     (memory 1 1)
@@ -427,7 +382,6 @@
       (memory.fill (i64.const 10) (i32.const 20) (i32.const 30))))
   "type mismatch")
 
-
 (assert_invalid
   (module
     (memory 1 1)
@@ -435,7 +389,6 @@
       (memory.fill (i64.const 10) (i32.const 20) (f32.const 30))))
   "type mismatch")
 
-
 (assert_invalid
   (module
     (memory 1 1)
@@ -443,7 +396,6 @@
       (memory.fill (i64.const 10) (i32.const 20) (i64.const 30))))
   "type mismatch")
 
-
 (assert_invalid
   (module
     (memory 1 1)
@@ -451,7 +403,6 @@
       (memory.fill (i64.const 10) (i32.const 20) (f64.const 30))))
   "type mismatch")
 
-
 (assert_invalid
   (module
     (memory 1 1)
@@ -459,7 +410,6 @@
       (memory.fill (i64.const 10) (f32.const 20) (i32.const 30))))
   "type mismatch")
 
-
 (assert_invalid
   (module
     (memory 1 1)
@@ -467,7 +417,6 @@
       (memory.fill (i64.const 10) (f32.const 20) (f32.const 30))))
   "type mismatch")
 
-
 (assert_invalid
   (module
     (memory 1 1)
@@ -475,7 +424,6 @@
       (memory.fill (i64.const 10) (f32.const 20) (i64.const 30))))
   "type mismatch")
 
-
 (assert_invalid
   (module
     (memory 1 1)
@@ -483,7 +431,6 @@
       (memory.fill (i64.const 10) (f32.const 20) (f64.const 30))))
   "type mismatch")
 
-
 (assert_invalid
   (module
     (memory 1 1)
@@ -491,7 +438,6 @@
       (memory.fill (i64.const 10) (i64.const 20) (i32.const 30))))
   "type mismatch")
 
-
 (assert_invalid
   (module
     (memory 1 1)
@@ -499,7 +445,6 @@
       (memory.fill (i64.const 10) (i64.const 20) (f32.const 30))))
   "type mismatch")
 
-
 (assert_invalid
   (module
     (memory 1 1)
@@ -507,7 +452,6 @@
       (memory.fill (i64.const 10) (i64.const 20) (i64.const 30))))
   "type mismatch")
 
-
 (assert_invalid
   (module
     (memory 1 1)
@@ -515,7 +459,6 @@
       (memory.fill (i64.const 10) (i64.const 20) (f64.const 30))))
   "type mismatch")
 
-
 (assert_invalid
   (module
     (memory 1 1)
@@ -523,7 +466,6 @@
       (memory.fill (i64.const 10) (f64.const 20) (i32.const 30))))
   "type mismatch")
 
-
 (assert_invalid
   (module
     (memory 1 1)
@@ -531,7 +473,6 @@
       (memory.fill (i64.const 10) (f64.const 20) (f32.const 30))))
   "type mismatch")
 
-
 (assert_invalid
   (module
     (memory 1 1)
@@ -539,7 +480,6 @@
       (memory.fill (i64.const 10) (f64.const 20) (i64.const 30))))
   "type mismatch")
 
-
 (assert_invalid
   (module
     (memory 1 1)
@@ -547,7 +487,6 @@
       (memory.fill (i64.const 10) (f64.const 20) (f64.const 30))))
   "type mismatch")
 
-
 (assert_invalid
   (module
     (memory 1 1)
@@ -555,7 +494,6 @@
       (memory.fill (f64.const 10) (i32.const 20) (i32.const 30))))
   "type mismatch")
 
-
 (assert_invalid
   (module
     (memory 1 1)
@@ -563,7 +501,6 @@
       (memory.fill (f64.const 10) (i32.const 20) (f32.const 30))))
   "type mismatch")
 
-
 (assert_invalid
   (module
     (memory 1 1)
@@ -571,7 +508,6 @@
       (memory.fill (f64.const 10) (i32.const 20) (i64.const 30))))
   "type mismatch")
 
-
 (assert_invalid
   (module
     (memory 1 1)
@@ -579,7 +515,6 @@
       (memory.fill (f64.const 10) (i32.const 20) (f64.const 30))))
   "type mismatch")
 
-
 (assert_invalid
   (module
     (memory 1 1)
@@ -587,7 +522,6 @@
       (memory.fill (f64.const 10) (f32.const 20) (i32.const 30))))
   "type mismatch")
 
-
 (assert_invalid
   (module
     (memory 1 1)
@@ -595,7 +529,6 @@
       (memory.fill (f64.const 10) (f32.const 20) (f32.const 30))))
   "type mismatch")
 
-
 (assert_invalid
   (module
     (memory 1 1)
@@ -603,7 +536,6 @@
       (memory.fill (f64.const 10) (f32.const 20) (i64.const 30))))
   "type mismatch")
 
-
 (assert_invalid
   (module
     (memory 1 1)
@@ -611,7 +543,6 @@
       (memory.fill (f64.const 10) (f32.const 20) (f64.const 30))))
   "type mismatch")
 
-
 (assert_invalid
   (module
     (memory 1 1)
@@ -619,7 +550,6 @@
       (memory.fill (f64.const 10) (i64.const 20) (i32.const 30))))
   "type mismatch")
 
-
 (assert_invalid
   (module
     (memory 1 1)
@@ -627,7 +557,6 @@
       (memory.fill (f64.const 10) (i64.const 20) (f32.const 30))))
   "type mismatch")
 
-
 (assert_invalid
   (module
     (memory 1 1)
@@ -635,7 +564,6 @@
       (memory.fill (f64.const 10) (i64.const 20) (i64.const 30))))
   "type mismatch")
 
-
 (assert_invalid
   (module
     (memory 1 1)
@@ -643,7 +571,6 @@
       (memory.fill (f64.const 10) (i64.const 20) (f64.const 30))))
   "type mismatch")
 
-
 (assert_invalid
   (module
     (memory 1 1)
@@ -651,7 +578,6 @@
       (memory.fill (f64.const 10) (f64.const 20) (i32.const 30))))
   "type mismatch")
 
-
 (assert_invalid
   (module
     (memory 1 1)
@@ -659,7 +585,6 @@
       (memory.fill (f64.const 10) (f64.const 20) (f32.const 30))))
   "type mismatch")
 
-
 (assert_invalid
   (module
     (memory 1 1)
@@ -667,7 +592,6 @@
       (memory.fill (f64.const 10) (f64.const 20) (i64.const 30))))
   "type mismatch")
 
-
 (assert_invalid
   (module
     (memory 1 1)
@@ -679,15 +603,15 @@
   (memory 1 1 )
   
   (func (export "checkRange") (param $from i32) (param $to i32) (param $expected i32) (result i32)
-   (loop $cont
-     (if (i32.eq (local.get $from) (local.get $to))
-         (then
-           (return (i32.const -1))))
-     (if (i32.eq (i32.load8_u (local.get $from)) (local.get $expected))
-         (then
-           (local.set $from (i32.add (local.get $from) (i32.const 1)))
-           (br $cont))))
-   (return (local.get $from)))
+    (loop $cont
+      (if (i32.eq (local.get $from) (local.get $to))
+        (then
+          (return (i32.const -1))))
+      (if (i32.eq (i32.load8_u (local.get $from)) (local.get $expected))
+        (then
+          (local.set $from (i32.add (local.get $from) (i32.const 1)))
+          (br $cont))))
+    (return (local.get $from)))
 
   (func (export "run") (param $offs i32) (param $val i32) (param $len i32)
     (memory.fill (local.get $offs) (local.get $val) (local.get $len))))
@@ -703,15 +627,15 @@
   (memory 1 1 )
   
   (func (export "checkRange") (param $from i32) (param $to i32) (param $expected i32) (result i32)
-   (loop $cont
-     (if (i32.eq (local.get $from) (local.get $to))
-         (then
-           (return (i32.const -1))))
-     (if (i32.eq (i32.load8_u (local.get $from)) (local.get $expected))
-         (then
-           (local.set $from (i32.add (local.get $from) (i32.const 1)))
-           (br $cont))))
-   (return (local.get $from)))
+    (loop $cont
+      (if (i32.eq (local.get $from) (local.get $to))
+        (then
+          (return (i32.const -1))))
+      (if (i32.eq (i32.load8_u (local.get $from)) (local.get $expected))
+        (then
+          (local.set $from (i32.add (local.get $from) (i32.const 1)))
+          (br $cont))))
+    (return (local.get $from)))
 
   (func (export "run") (param $offs i32) (param $val i32) (param $len i32)
     (memory.fill (local.get $offs) (local.get $val) (local.get $len))))
@@ -727,15 +651,15 @@
   (memory 1 1 )
   
   (func (export "checkRange") (param $from i32) (param $to i32) (param $expected i32) (result i32)
-   (loop $cont
-     (if (i32.eq (local.get $from) (local.get $to))
-         (then
-           (return (i32.const -1))))
-     (if (i32.eq (i32.load8_u (local.get $from)) (local.get $expected))
-         (then
-           (local.set $from (i32.add (local.get $from) (i32.const 1)))
-           (br $cont))))
-   (return (local.get $from)))
+    (loop $cont
+      (if (i32.eq (local.get $from) (local.get $to))
+        (then
+          (return (i32.const -1))))
+      (if (i32.eq (i32.load8_u (local.get $from)) (local.get $expected))
+        (then
+          (local.set $from (i32.add (local.get $from) (i32.const 1)))
+          (br $cont))))
+    (return (local.get $from)))
 
   (func (export "run") (param $offs i32) (param $val i32) (param $len i32)
     (memory.fill (local.get $offs) (local.get $val) (local.get $len))))
diff --git a/test/core/memory_init.wast b/test/core/memory_init.wast
index e30dc05e79..59c9fe8606 100644
--- a/test/core/memory_init.wast
+++ b/test/core/memory_init.wast
@@ -9,7 +9,7 @@
   (data (i32.const 12) "\07\05\02\03\06")
   (data passive "\05\09\02\07\06")
   (func (export "test")
-    nop)
+    (nop))
   (func (export "load8_u") (param i32) (result i32)
     (i32.load8_u (local.get 0))))
 
@@ -141,15 +141,15 @@
   (data (i32.const 12) "\07\05\02\03\06")
   (data passive "\05\09\02\07\06")
   (func (export "test")
-    (memory.init 1 (i32.const 7) (i32.const 0) (i32.const 4)) 
-data.drop 1 
-(memory.init 3 (i32.const 15) (i32.const 1) (i32.const 3)) 
-data.drop 3 
-(memory.copy (i32.const 20) (i32.const 15) (i32.const 5)) 
-(memory.copy (i32.const 21) (i32.const 29) (i32.const 1)) 
-(memory.copy (i32.const 24) (i32.const 10) (i32.const 1)) 
-(memory.copy (i32.const 13) (i32.const 11) (i32.const 4)) 
-(memory.copy (i32.const 19) (i32.const 20) (i32.const 5)))
+    (memory.init 1 (i32.const 7) (i32.const 0) (i32.const 4))
+    (data.drop 1)
+    (memory.init 3 (i32.const 15) (i32.const 1) (i32.const 3))
+    (data.drop 3)
+    (memory.copy (i32.const 20) (i32.const 15) (i32.const 5))
+    (memory.copy (i32.const 21) (i32.const 29) (i32.const 1))
+    (memory.copy (i32.const 24) (i32.const 10) (i32.const 1))
+    (memory.copy (i32.const 13) (i32.const 11) (i32.const 4))
+    (memory.copy (i32.const 19) (i32.const 20) (i32.const 5)))
   (func (export "load8_u") (param i32) (result i32)
     (i32.load8_u (local.get 0))))
 
@@ -194,14 +194,14 @@ data.drop 3
 (assert_invalid
   (module
     (memory 1)
-     (data passive "\37")
+    (data passive "\37")
     (func (export "test")
       (data.drop 4)))
   "unknown data segment")
 
 (module
   (memory 1)
-     (data passive "\37")
+    (data passive "\37")
   (func (export "test")
     (data.drop 0)
     (data.drop 0)))
@@ -209,7 +209,7 @@ data.drop 3
 
 (module
   (memory 1)
-     (data passive "\37")
+    (data passive "\37")
   (func (export "test")
     (data.drop 0)
     (memory.init 0 (i32.const 1234) (i32.const 1) (i32.const 1))))
@@ -231,14 +231,14 @@ data.drop 3
 (assert_invalid
   (module
     (memory 1)
-     (data passive "\37")
+    (data passive "\37")
     (func (export "test")
       (memory.init 1 (i32.const 1234) (i32.const 1) (i32.const 1))))
   "unknown data segment 1")
 
 (module
   (memory 1)
-     (data passive "\37")
+    (data passive "\37")
   (func (export "test")
     (memory.init 0 (i32.const 1) (i32.const 0) (i32.const 1))
     (memory.init 0 (i32.const 1) (i32.const 0) (i32.const 1))))
@@ -246,560 +246,560 @@ data.drop 3
 
 (module
   (memory 1)
-     (data passive "\37")
+    (data passive "\37")
   (func (export "test")
     (memory.init 0 (i32.const 1234) (i32.const 0) (i32.const 5))))
 (assert_trap (invoke "test") "out of bounds")
 
 (module
   (memory 1)
-     (data passive "\37")
+    (data passive "\37")
   (func (export "test")
     (memory.init 0 (i32.const 1234) (i32.const 2) (i32.const 3))))
 (assert_trap (invoke "test") "out of bounds")
 
 (module
   (memory 1)
-     (data passive "\37")
+    (data passive "\37")
   (func (export "test")
     (memory.init 0 (i32.const 0xFFFE) (i32.const 1) (i32.const 3))))
 (assert_trap (invoke "test") "out of bounds")
 
 (module
   (memory 1)
-     (data passive "\37")
+    (data passive "\37")
   (func (export "test")
     (memory.init 0 (i32.const 1234) (i32.const 4) (i32.const 0))))
 (assert_trap (invoke "test") "out of bounds")
 
 (module
   (memory 1)
-     (data passive "\37")
+    (data passive "\37")
   (func (export "test")
     (memory.init 0 (i32.const 0x10000) (i32.const 2) (i32.const 0))))
 (assert_trap (invoke "test") "out of bounds")
 
 (assert_invalid
-   (module
-     (memory 1)
-     (data passive "\37")
-     (func (export "test")
-       (memory.init 0 (i32.const 1) (i32.const 1) (f32.const 1))))
-   "type mismatch")
+  (module
+    (memory 1)
+    (data passive "\37")
+    (func (export "test")
+      (memory.init 0 (i32.const 1) (i32.const 1) (f32.const 1))))
+  "type mismatch")
 
 (assert_invalid
-   (module
-     (memory 1)
-     (data passive "\37")
-     (func (export "test")
-       (memory.init 0 (i32.const 1) (i32.const 1) (i64.const 1))))
-   "type mismatch")
+  (module
+    (memory 1)
+    (data passive "\37")
+    (func (export "test")
+      (memory.init 0 (i32.const 1) (i32.const 1) (i64.const 1))))
+  "type mismatch")
 
 (assert_invalid
-   (module
-     (memory 1)
-     (data passive "\37")
-     (func (export "test")
-       (memory.init 0 (i32.const 1) (i32.const 1) (f64.const 1))))
-   "type mismatch")
+  (module
+    (memory 1)
+    (data passive "\37")
+    (func (export "test")
+      (memory.init 0 (i32.const 1) (i32.const 1) (f64.const 1))))
+  "type mismatch")
 
 (assert_invalid
-   (module
-     (memory 1)
-     (data passive "\37")
-     (func (export "test")
-       (memory.init 0 (i32.const 1) (f32.const 1) (i32.const 1))))
-   "type mismatch")
+  (module
+    (memory 1)
+    (data passive "\37")
+    (func (export "test")
+      (memory.init 0 (i32.const 1) (f32.const 1) (i32.const 1))))
+  "type mismatch")
 
 (assert_invalid
-   (module
-     (memory 1)
-     (data passive "\37")
-     (func (export "test")
-       (memory.init 0 (i32.const 1) (f32.const 1) (f32.const 1))))
-   "type mismatch")
+  (module
+    (memory 1)
+    (data passive "\37")
+    (func (export "test")
+      (memory.init 0 (i32.const 1) (f32.const 1) (f32.const 1))))
+  "type mismatch")
 
 (assert_invalid
-   (module
-     (memory 1)
-     (data passive "\37")
-     (func (export "test")
-       (memory.init 0 (i32.const 1) (f32.const 1) (i64.const 1))))
-   "type mismatch")
+  (module
+    (memory 1)
+    (data passive "\37")
+    (func (export "test")
+      (memory.init 0 (i32.const 1) (f32.const 1) (i64.const 1))))
+  "type mismatch")
 
 (assert_invalid
-   (module
-     (memory 1)
-     (data passive "\37")
-     (func (export "test")
-       (memory.init 0 (i32.const 1) (f32.const 1) (f64.const 1))))
-   "type mismatch")
+  (module
+    (memory 1)
+    (data passive "\37")
+    (func (export "test")
+      (memory.init 0 (i32.const 1) (f32.const 1) (f64.const 1))))
+  "type mismatch")
 
 (assert_invalid
-   (module
-     (memory 1)
-     (data passive "\37")
-     (func (export "test")
-       (memory.init 0 (i32.const 1) (i64.const 1) (i32.const 1))))
-   "type mismatch")
+  (module
+    (memory 1)
+    (data passive "\37")
+    (func (export "test")
+      (memory.init 0 (i32.const 1) (i64.const 1) (i32.const 1))))
+  "type mismatch")
 
 (assert_invalid
-   (module
-     (memory 1)
-     (data passive "\37")
-     (func (export "test")
-       (memory.init 0 (i32.const 1) (i64.const 1) (f32.const 1))))
-   "type mismatch")
+  (module
+    (memory 1)
+    (data passive "\37")
+    (func (export "test")
+      (memory.init 0 (i32.const 1) (i64.const 1) (f32.const 1))))
+  "type mismatch")
 
 (assert_invalid
-   (module
-     (memory 1)
-     (data passive "\37")
-     (func (export "test")
-       (memory.init 0 (i32.const 1) (i64.const 1) (i64.const 1))))
-   "type mismatch")
+  (module
+    (memory 1)
+    (data passive "\37")
+    (func (export "test")
+      (memory.init 0 (i32.const 1) (i64.const 1) (i64.const 1))))
+  "type mismatch")
 
 (assert_invalid
-   (module
-     (memory 1)
-     (data passive "\37")
-     (func (export "test")
-       (memory.init 0 (i32.const 1) (i64.const 1) (f64.const 1))))
-   "type mismatch")
+  (module
+    (memory 1)
+    (data passive "\37")
+    (func (export "test")
+      (memory.init 0 (i32.const 1) (i64.const 1) (f64.const 1))))
+  "type mismatch")
 
 (assert_invalid
-   (module
-     (memory 1)
-     (data passive "\37")
-     (func (export "test")
-       (memory.init 0 (i32.const 1) (f64.const 1) (i32.const 1))))
-   "type mismatch")
+  (module
+    (memory 1)
+    (data passive "\37")
+    (func (export "test")
+      (memory.init 0 (i32.const 1) (f64.const 1) (i32.const 1))))
+  "type mismatch")
 
 (assert_invalid
-   (module
-     (memory 1)
-     (data passive "\37")
-     (func (export "test")
-       (memory.init 0 (i32.const 1) (f64.const 1) (f32.const 1))))
-   "type mismatch")
+  (module
+    (memory 1)
+    (data passive "\37")
+    (func (export "test")
+      (memory.init 0 (i32.const 1) (f64.const 1) (f32.const 1))))
+  "type mismatch")
 
 (assert_invalid
-   (module
-     (memory 1)
-     (data passive "\37")
-     (func (export "test")
-       (memory.init 0 (i32.const 1) (f64.const 1) (i64.const 1))))
-   "type mismatch")
+  (module
+    (memory 1)
+    (data passive "\37")
+    (func (export "test")
+      (memory.init 0 (i32.const 1) (f64.const 1) (i64.const 1))))
+  "type mismatch")
 
 (assert_invalid
-   (module
-     (memory 1)
-     (data passive "\37")
-     (func (export "test")
-       (memory.init 0 (i32.const 1) (f64.const 1) (f64.const 1))))
-   "type mismatch")
+  (module
+    (memory 1)
+    (data passive "\37")
+    (func (export "test")
+      (memory.init 0 (i32.const 1) (f64.const 1) (f64.const 1))))
+  "type mismatch")
 
 (assert_invalid
-   (module
-     (memory 1)
-     (data passive "\37")
-     (func (export "test")
-       (memory.init 0 (f32.const 1) (i32.const 1) (i32.const 1))))
-   "type mismatch")
+  (module
+    (memory 1)
+    (data passive "\37")
+    (func (export "test")
+      (memory.init 0 (f32.const 1) (i32.const 1) (i32.const 1))))
+  "type mismatch")
 
 (assert_invalid
-   (module
-     (memory 1)
-     (data passive "\37")
-     (func (export "test")
-       (memory.init 0 (f32.const 1) (i32.const 1) (f32.const 1))))
-   "type mismatch")
+  (module
+    (memory 1)
+    (data passive "\37")
+    (func (export "test")
+      (memory.init 0 (f32.const 1) (i32.const 1) (f32.const 1))))
+  "type mismatch")
 
 (assert_invalid
-   (module
-     (memory 1)
-     (data passive "\37")
-     (func (export "test")
-       (memory.init 0 (f32.const 1) (i32.const 1) (i64.const 1))))
-   "type mismatch")
+  (module
+    (memory 1)
+    (data passive "\37")
+    (func (export "test")
+      (memory.init 0 (f32.const 1) (i32.const 1) (i64.const 1))))
+  "type mismatch")
 
 (assert_invalid
-   (module
-     (memory 1)
-     (data passive "\37")
-     (func (export "test")
-       (memory.init 0 (f32.const 1) (i32.const 1) (f64.const 1))))
-   "type mismatch")
+  (module
+    (memory 1)
+    (data passive "\37")
+    (func (export "test")
+      (memory.init 0 (f32.const 1) (i32.const 1) (f64.const 1))))
+  "type mismatch")
 
 (assert_invalid
-   (module
-     (memory 1)
-     (data passive "\37")
-     (func (export "test")
-       (memory.init 0 (f32.const 1) (f32.const 1) (i32.const 1))))
-   "type mismatch")
+  (module
+    (memory 1)
+    (data passive "\37")
+    (func (export "test")
+      (memory.init 0 (f32.const 1) (f32.const 1) (i32.const 1))))
+  "type mismatch")
 
 (assert_invalid
-   (module
-     (memory 1)
-     (data passive "\37")
-     (func (export "test")
-       (memory.init 0 (f32.const 1) (f32.const 1) (f32.const 1))))
-   "type mismatch")
+  (module
+    (memory 1)
+    (data passive "\37")
+    (func (export "test")
+      (memory.init 0 (f32.const 1) (f32.const 1) (f32.const 1))))
+  "type mismatch")
 
 (assert_invalid
-   (module
-     (memory 1)
-     (data passive "\37")
-     (func (export "test")
-       (memory.init 0 (f32.const 1) (f32.const 1) (i64.const 1))))
-   "type mismatch")
+  (module
+    (memory 1)
+    (data passive "\37")
+    (func (export "test")
+      (memory.init 0 (f32.const 1) (f32.const 1) (i64.const 1))))
+  "type mismatch")
 
 (assert_invalid
-   (module
-     (memory 1)
-     (data passive "\37")
-     (func (export "test")
-       (memory.init 0 (f32.const 1) (f32.const 1) (f64.const 1))))
-   "type mismatch")
+  (module
+    (memory 1)
+    (data passive "\37")
+    (func (export "test")
+      (memory.init 0 (f32.const 1) (f32.const 1) (f64.const 1))))
+  "type mismatch")
 
 (assert_invalid
-   (module
-     (memory 1)
-     (data passive "\37")
-     (func (export "test")
-       (memory.init 0 (f32.const 1) (i64.const 1) (i32.const 1))))
-   "type mismatch")
+  (module
+    (memory 1)
+    (data passive "\37")
+    (func (export "test")
+      (memory.init 0 (f32.const 1) (i64.const 1) (i32.const 1))))
+  "type mismatch")
 
 (assert_invalid
-   (module
-     (memory 1)
-     (data passive "\37")
-     (func (export "test")
-       (memory.init 0 (f32.const 1) (i64.const 1) (f32.const 1))))
-   "type mismatch")
+  (module
+    (memory 1)
+    (data passive "\37")
+    (func (export "test")
+      (memory.init 0 (f32.const 1) (i64.const 1) (f32.const 1))))
+  "type mismatch")
 
 (assert_invalid
-   (module
-     (memory 1)
-     (data passive "\37")
-     (func (export "test")
-       (memory.init 0 (f32.const 1) (i64.const 1) (i64.const 1))))
-   "type mismatch")
+  (module
+    (memory 1)
+    (data passive "\37")
+    (func (export "test")
+      (memory.init 0 (f32.const 1) (i64.const 1) (i64.const 1))))
+  "type mismatch")
 
 (assert_invalid
-   (module
-     (memory 1)
-     (data passive "\37")
-     (func (export "test")
-       (memory.init 0 (f32.const 1) (i64.const 1) (f64.const 1))))
-   "type mismatch")
+  (module
+    (memory 1)
+    (data passive "\37")
+    (func (export "test")
+      (memory.init 0 (f32.const 1) (i64.const 1) (f64.const 1))))
+  "type mismatch")
 
 (assert_invalid
-   (module
-     (memory 1)
-     (data passive "\37")
-     (func (export "test")
-       (memory.init 0 (f32.const 1) (f64.const 1) (i32.const 1))))
-   "type mismatch")
+  (module
+    (memory 1)
+    (data passive "\37")
+    (func (export "test")
+      (memory.init 0 (f32.const 1) (f64.const 1) (i32.const 1))))
+  "type mismatch")
 
 (assert_invalid
-   (module
-     (memory 1)
-     (data passive "\37")
-     (func (export "test")
-       (memory.init 0 (f32.const 1) (f64.const 1) (f32.const 1))))
-   "type mismatch")
+  (module
+    (memory 1)
+    (data passive "\37")
+    (func (export "test")
+      (memory.init 0 (f32.const 1) (f64.const 1) (f32.const 1))))
+  "type mismatch")
 
 (assert_invalid
-   (module
-     (memory 1)
-     (data passive "\37")
-     (func (export "test")
-       (memory.init 0 (f32.const 1) (f64.const 1) (i64.const 1))))
-   "type mismatch")
+  (module
+    (memory 1)
+    (data passive "\37")
+    (func (export "test")
+      (memory.init 0 (f32.const 1) (f64.const 1) (i64.const 1))))
+  "type mismatch")
 
 (assert_invalid
-   (module
-     (memory 1)
-     (data passive "\37")
-     (func (export "test")
-       (memory.init 0 (f32.const 1) (f64.const 1) (f64.const 1))))
-   "type mismatch")
+  (module
+    (memory 1)
+    (data passive "\37")
+    (func (export "test")
+      (memory.init 0 (f32.const 1) (f64.const 1) (f64.const 1))))
+  "type mismatch")
 
 (assert_invalid
-   (module
-     (memory 1)
-     (data passive "\37")
-     (func (export "test")
-       (memory.init 0 (i64.const 1) (i32.const 1) (i32.const 1))))
-   "type mismatch")
+  (module
+    (memory 1)
+    (data passive "\37")
+    (func (export "test")
+      (memory.init 0 (i64.const 1) (i32.const 1) (i32.const 1))))
+  "type mismatch")
 
 (assert_invalid
-   (module
-     (memory 1)
-     (data passive "\37")
-     (func (export "test")
-       (memory.init 0 (i64.const 1) (i32.const 1) (f32.const 1))))
-   "type mismatch")
+  (module
+    (memory 1)
+    (data passive "\37")
+    (func (export "test")
+      (memory.init 0 (i64.const 1) (i32.const 1) (f32.const 1))))
+  "type mismatch")
 
 (assert_invalid
-   (module
-     (memory 1)
-     (data passive "\37")
-     (func (export "test")
-       (memory.init 0 (i64.const 1) (i32.const 1) (i64.const 1))))
-   "type mismatch")
+  (module
+    (memory 1)
+    (data passive "\37")
+    (func (export "test")
+      (memory.init 0 (i64.const 1) (i32.const 1) (i64.const 1))))
+  "type mismatch")
 
 (assert_invalid
-   (module
-     (memory 1)
-     (data passive "\37")
-     (func (export "test")
-       (memory.init 0 (i64.const 1) (i32.const 1) (f64.const 1))))
-   "type mismatch")
+  (module
+    (memory 1)
+    (data passive "\37")
+    (func (export "test")
+      (memory.init 0 (i64.const 1) (i32.const 1) (f64.const 1))))
+  "type mismatch")
 
 (assert_invalid
-   (module
-     (memory 1)
-     (data passive "\37")
-     (func (export "test")
-       (memory.init 0 (i64.const 1) (f32.const 1) (i32.const 1))))
-   "type mismatch")
+  (module
+    (memory 1)
+    (data passive "\37")
+    (func (export "test")
+      (memory.init 0 (i64.const 1) (f32.const 1) (i32.const 1))))
+  "type mismatch")
 
 (assert_invalid
-   (module
-     (memory 1)
-     (data passive "\37")
-     (func (export "test")
-       (memory.init 0 (i64.const 1) (f32.const 1) (f32.const 1))))
-   "type mismatch")
+  (module
+    (memory 1)
+    (data passive "\37")
+    (func (export "test")
+      (memory.init 0 (i64.const 1) (f32.const 1) (f32.const 1))))
+  "type mismatch")
 
 (assert_invalid
-   (module
-     (memory 1)
-     (data passive "\37")
-     (func (export "test")
-       (memory.init 0 (i64.const 1) (f32.const 1) (i64.const 1))))
-   "type mismatch")
+  (module
+    (memory 1)
+    (data passive "\37")
+    (func (export "test")
+      (memory.init 0 (i64.const 1) (f32.const 1) (i64.const 1))))
+  "type mismatch")
 
 (assert_invalid
-   (module
-     (memory 1)
-     (data passive "\37")
-     (func (export "test")
-       (memory.init 0 (i64.const 1) (f32.const 1) (f64.const 1))))
-   "type mismatch")
+  (module
+    (memory 1)
+    (data passive "\37")
+    (func (export "test")
+      (memory.init 0 (i64.const 1) (f32.const 1) (f64.const 1))))
+  "type mismatch")
 
 (assert_invalid
-   (module
-     (memory 1)
-     (data passive "\37")
-     (func (export "test")
-       (memory.init 0 (i64.const 1) (i64.const 1) (i32.const 1))))
-   "type mismatch")
+  (module
+    (memory 1)
+    (data passive "\37")
+    (func (export "test")
+      (memory.init 0 (i64.const 1) (i64.const 1) (i32.const 1))))
+  "type mismatch")
 
 (assert_invalid
-   (module
-     (memory 1)
-     (data passive "\37")
-     (func (export "test")
-       (memory.init 0 (i64.const 1) (i64.const 1) (f32.const 1))))
-   "type mismatch")
+  (module
+    (memory 1)
+    (data passive "\37")
+    (func (export "test")
+      (memory.init 0 (i64.const 1) (i64.const 1) (f32.const 1))))
+  "type mismatch")
 
 (assert_invalid
-   (module
-     (memory 1)
-     (data passive "\37")
-     (func (export "test")
-       (memory.init 0 (i64.const 1) (i64.const 1) (i64.const 1))))
-   "type mismatch")
+  (module
+    (memory 1)
+    (data passive "\37")
+    (func (export "test")
+      (memory.init 0 (i64.const 1) (i64.const 1) (i64.const 1))))
+  "type mismatch")
 
 (assert_invalid
-   (module
-     (memory 1)
-     (data passive "\37")
-     (func (export "test")
-       (memory.init 0 (i64.const 1) (i64.const 1) (f64.const 1))))
-   "type mismatch")
+  (module
+    (memory 1)
+    (data passive "\37")
+    (func (export "test")
+      (memory.init 0 (i64.const 1) (i64.const 1) (f64.const 1))))
+  "type mismatch")
 
 (assert_invalid
-   (module
-     (memory 1)
-     (data passive "\37")
-     (func (export "test")
-       (memory.init 0 (i64.const 1) (f64.const 1) (i32.const 1))))
-   "type mismatch")
+  (module
+    (memory 1)
+    (data passive "\37")
+    (func (export "test")
+      (memory.init 0 (i64.const 1) (f64.const 1) (i32.const 1))))
+  "type mismatch")
 
 (assert_invalid
-   (module
-     (memory 1)
-     (data passive "\37")
-     (func (export "test")
-       (memory.init 0 (i64.const 1) (f64.const 1) (f32.const 1))))
-   "type mismatch")
+  (module
+    (memory 1)
+    (data passive "\37")
+    (func (export "test")
+      (memory.init 0 (i64.const 1) (f64.const 1) (f32.const 1))))
+  "type mismatch")
 
 (assert_invalid
-   (module
-     (memory 1)
-     (data passive "\37")
-     (func (export "test")
-       (memory.init 0 (i64.const 1) (f64.const 1) (i64.const 1))))
-   "type mismatch")
+  (module
+    (memory 1)
+    (data passive "\37")
+    (func (export "test")
+      (memory.init 0 (i64.const 1) (f64.const 1) (i64.const 1))))
+  "type mismatch")
 
 (assert_invalid
-   (module
-     (memory 1)
-     (data passive "\37")
-     (func (export "test")
-       (memory.init 0 (i64.const 1) (f64.const 1) (f64.const 1))))
-   "type mismatch")
+  (module
+    (memory 1)
+    (data passive "\37")
+    (func (export "test")
+      (memory.init 0 (i64.const 1) (f64.const 1) (f64.const 1))))
+  "type mismatch")
 
 (assert_invalid
-   (module
-     (memory 1)
-     (data passive "\37")
-     (func (export "test")
-       (memory.init 0 (f64.const 1) (i32.const 1) (i32.const 1))))
-   "type mismatch")
+  (module
+    (memory 1)
+    (data passive "\37")
+    (func (export "test")
+      (memory.init 0 (f64.const 1) (i32.const 1) (i32.const 1))))
+  "type mismatch")
 
 (assert_invalid
-   (module
-     (memory 1)
-     (data passive "\37")
-     (func (export "test")
-       (memory.init 0 (f64.const 1) (i32.const 1) (f32.const 1))))
-   "type mismatch")
+  (module
+    (memory 1)
+    (data passive "\37")
+    (func (export "test")
+      (memory.init 0 (f64.const 1) (i32.const 1) (f32.const 1))))
+  "type mismatch")
 
 (assert_invalid
-   (module
-     (memory 1)
-     (data passive "\37")
-     (func (export "test")
-       (memory.init 0 (f64.const 1) (i32.const 1) (i64.const 1))))
-   "type mismatch")
+  (module
+    (memory 1)
+    (data passive "\37")
+    (func (export "test")
+      (memory.init 0 (f64.const 1) (i32.const 1) (i64.const 1))))
+  "type mismatch")
 
 (assert_invalid
-   (module
-     (memory 1)
-     (data passive "\37")
-     (func (export "test")
-       (memory.init 0 (f64.const 1) (i32.const 1) (f64.const 1))))
-   "type mismatch")
+  (module
+    (memory 1)
+    (data passive "\37")
+    (func (export "test")
+      (memory.init 0 (f64.const 1) (i32.const 1) (f64.const 1))))
+  "type mismatch")
 
 (assert_invalid
-   (module
-     (memory 1)
-     (data passive "\37")
-     (func (export "test")
-       (memory.init 0 (f64.const 1) (f32.const 1) (i32.const 1))))
-   "type mismatch")
+  (module
+    (memory 1)
+    (data passive "\37")
+    (func (export "test")
+      (memory.init 0 (f64.const 1) (f32.const 1) (i32.const 1))))
+  "type mismatch")
 
 (assert_invalid
-   (module
-     (memory 1)
-     (data passive "\37")
-     (func (export "test")
-       (memory.init 0 (f64.const 1) (f32.const 1) (f32.const 1))))
-   "type mismatch")
+  (module
+    (memory 1)
+    (data passive "\37")
+    (func (export "test")
+      (memory.init 0 (f64.const 1) (f32.const 1) (f32.const 1))))
+  "type mismatch")
 
 (assert_invalid
-   (module
-     (memory 1)
-     (data passive "\37")
-     (func (export "test")
-       (memory.init 0 (f64.const 1) (f32.const 1) (i64.const 1))))
-   "type mismatch")
+  (module
+    (memory 1)
+    (data passive "\37")
+    (func (export "test")
+      (memory.init 0 (f64.const 1) (f32.const 1) (i64.const 1))))
+  "type mismatch")
 
 (assert_invalid
-   (module
-     (memory 1)
-     (data passive "\37")
-     (func (export "test")
-       (memory.init 0 (f64.const 1) (f32.const 1) (f64.const 1))))
-   "type mismatch")
+  (module
+    (memory 1)
+    (data passive "\37")
+    (func (export "test")
+      (memory.init 0 (f64.const 1) (f32.const 1) (f64.const 1))))
+  "type mismatch")
 
 (assert_invalid
-   (module
-     (memory 1)
-     (data passive "\37")
-     (func (export "test")
-       (memory.init 0 (f64.const 1) (i64.const 1) (i32.const 1))))
-   "type mismatch")
+  (module
+    (memory 1)
+    (data passive "\37")
+    (func (export "test")
+      (memory.init 0 (f64.const 1) (i64.const 1) (i32.const 1))))
+  "type mismatch")
 
 (assert_invalid
-   (module
-     (memory 1)
-     (data passive "\37")
-     (func (export "test")
-       (memory.init 0 (f64.const 1) (i64.const 1) (f32.const 1))))
-   "type mismatch")
+  (module
+    (memory 1)
+    (data passive "\37")
+    (func (export "test")
+      (memory.init 0 (f64.const 1) (i64.const 1) (f32.const 1))))
+  "type mismatch")
 
 (assert_invalid
-   (module
-     (memory 1)
-     (data passive "\37")
-     (func (export "test")
-       (memory.init 0 (f64.const 1) (i64.const 1) (i64.const 1))))
-   "type mismatch")
+  (module
+    (memory 1)
+    (data passive "\37")
+    (func (export "test")
+      (memory.init 0 (f64.const 1) (i64.const 1) (i64.const 1))))
+  "type mismatch")
 
 (assert_invalid
-   (module
-     (memory 1)
-     (data passive "\37")
-     (func (export "test")
-       (memory.init 0 (f64.const 1) (i64.const 1) (f64.const 1))))
-   "type mismatch")
+  (module
+    (memory 1)
+    (data passive "\37")
+    (func (export "test")
+      (memory.init 0 (f64.const 1) (i64.const 1) (f64.const 1))))
+  "type mismatch")
 
 (assert_invalid
-   (module
-     (memory 1)
-     (data passive "\37")
-     (func (export "test")
-       (memory.init 0 (f64.const 1) (f64.const 1) (i32.const 1))))
-   "type mismatch")
+  (module
+    (memory 1)
+    (data passive "\37")
+    (func (export "test")
+      (memory.init 0 (f64.const 1) (f64.const 1) (i32.const 1))))
+  "type mismatch")
 
 (assert_invalid
-   (module
-     (memory 1)
-     (data passive "\37")
-     (func (export "test")
-       (memory.init 0 (f64.const 1) (f64.const 1) (f32.const 1))))
-   "type mismatch")
+  (module
+    (memory 1)
+    (data passive "\37")
+    (func (export "test")
+      (memory.init 0 (f64.const 1) (f64.const 1) (f32.const 1))))
+  "type mismatch")
 
 (assert_invalid
-   (module
-     (memory 1)
-     (data passive "\37")
-     (func (export "test")
-       (memory.init 0 (f64.const 1) (f64.const 1) (i64.const 1))))
-   "type mismatch")
+  (module
+    (memory 1)
+    (data passive "\37")
+    (func (export "test")
+      (memory.init 0 (f64.const 1) (f64.const 1) (i64.const 1))))
+  "type mismatch")
 
 (assert_invalid
-   (module
-     (memory 1)
-     (data passive "\37")
-     (func (export "test")
-       (memory.init 0 (f64.const 1) (f64.const 1) (f64.const 1))))
-   "type mismatch")
+  (module
+    (memory 1)
+    (data passive "\37")
+    (func (export "test")
+      (memory.init 0 (f64.const 1) (f64.const 1) (f64.const 1))))
+  "type mismatch")
 
 (module
-   (memory 1 1 )
-   (data passive "\42\42\42\42\42\42\42\42\42\42\42\42\42\42\42\42")
+  (memory 1 1 )
+  (data passive "\42\42\42\42\42\42\42\42\42\42\42\42\42\42\42\42")
    
   (func (export "checkRange") (param $from i32) (param $to i32) (param $expected i32) (result i32)
-   (loop $cont
-     (if (i32.eq (local.get $from) (local.get $to))
-         (then
-           (return (i32.const -1))))
-     (if (i32.eq (i32.load8_u (local.get $from)) (local.get $expected))
-         (then
-           (local.set $from (i32.add (local.get $from) (i32.const 1)))
-           (br $cont))))
-   (return (local.get $from)))
-
-   (func (export "run") (param $offs i32) (param $len i32)
-     (memory.init 0 (local.get $offs) (i32.const 0) (local.get $len))))
+    (loop $cont
+      (if (i32.eq (local.get $from) (local.get $to))
+        (then
+          (return (i32.const -1))))
+      (if (i32.eq (i32.load8_u (local.get $from)) (local.get $expected))
+        (then
+          (local.set $from (i32.add (local.get $from) (i32.const 1)))
+          (br $cont))))
+    (return (local.get $from)))
+
+  (func (export "run") (param $offs i32) (param $len i32)
+    (memory.init 0 (local.get $offs) (i32.const 0) (local.get $len))))
 
 (assert_trap (invoke "run" (i32.const 65528) (i32.const 16))
               "out of bounds")
@@ -811,22 +811,22 @@ data.drop 3
 (assert_return (invoke "checkRange" (i32.const 65536) (i32.const 65536) (i32.const 0))
                (i32.const -1))
 (module
-   (memory 1 1 )
-   (data passive "\42\42\42\42\42\42\42\42\42\42\42\42\42\42\42\42")
+  (memory 1 1 )
+  (data passive "\42\42\42\42\42\42\42\42\42\42\42\42\42\42\42\42")
    
   (func (export "checkRange") (param $from i32) (param $to i32) (param $expected i32) (result i32)
-   (loop $cont
-     (if (i32.eq (local.get $from) (local.get $to))
-         (then
-           (return (i32.const -1))))
-     (if (i32.eq (i32.load8_u (local.get $from)) (local.get $expected))
-         (then
-           (local.set $from (i32.add (local.get $from) (i32.const 1)))
-           (br $cont))))
-   (return (local.get $from)))
-
-   (func (export "run") (param $offs i32) (param $len i32)
-     (memory.init 0 (local.get $offs) (i32.const 0) (local.get $len))))
+    (loop $cont
+      (if (i32.eq (local.get $from) (local.get $to))
+        (then
+          (return (i32.const -1))))
+      (if (i32.eq (i32.load8_u (local.get $from)) (local.get $expected))
+        (then
+          (local.set $from (i32.add (local.get $from) (i32.const 1)))
+          (br $cont))))
+    (return (local.get $from)))
+
+  (func (export "run") (param $offs i32) (param $len i32)
+    (memory.init 0 (local.get $offs) (i32.const 0) (local.get $len))))
 
 (assert_trap (invoke "run" (i32.const 65527) (i32.const 16))
               "out of bounds")
@@ -838,22 +838,22 @@ data.drop 3
 (assert_return (invoke "checkRange" (i32.const 65536) (i32.const 65536) (i32.const 0))
                (i32.const -1))
 (module
-   (memory 1 1 )
-   (data passive "\42\42\42\42\42\42\42\42\42\42\42\42\42\42\42\42")
+  (memory 1 1 )
+  (data passive "\42\42\42\42\42\42\42\42\42\42\42\42\42\42\42\42")
    
   (func (export "checkRange") (param $from i32) (param $to i32) (param $expected i32) (result i32)
-   (loop $cont
-     (if (i32.eq (local.get $from) (local.get $to))
-         (then
-           (return (i32.const -1))))
-     (if (i32.eq (i32.load8_u (local.get $from)) (local.get $expected))
-         (then
-           (local.set $from (i32.add (local.get $from) (i32.const 1)))
-           (br $cont))))
-   (return (local.get $from)))
-
-   (func (export "run") (param $offs i32) (param $len i32)
-     (memory.init 0 (local.get $offs) (i32.const 0) (local.get $len))))
+    (loop $cont
+      (if (i32.eq (local.get $from) (local.get $to))
+        (then
+          (return (i32.const -1))))
+      (if (i32.eq (i32.load8_u (local.get $from)) (local.get $expected))
+        (then
+          (local.set $from (i32.add (local.get $from) (i32.const 1)))
+          (br $cont))))
+    (return (local.get $from)))
+
+  (func (export "run") (param $offs i32) (param $len i32)
+    (memory.init 0 (local.get $offs) (i32.const 0) (local.get $len))))
 
 (assert_trap (invoke "run" (i32.const 65472) (i32.const 30))
               "out of bounds")
@@ -865,22 +865,22 @@ data.drop 3
 (assert_return (invoke "checkRange" (i32.const 65488) (i32.const 65536) (i32.const 0))
                (i32.const -1))
 (module
-   (memory 1 1 )
-   (data passive "\42\42\42\42\42\42\42\42\42\42\42\42\42\42\42\42")
+  (memory 1 1 )
+  (data passive "\42\42\42\42\42\42\42\42\42\42\42\42\42\42\42\42")
    
   (func (export "checkRange") (param $from i32) (param $to i32) (param $expected i32) (result i32)
-   (loop $cont
-     (if (i32.eq (local.get $from) (local.get $to))
-         (then
-           (return (i32.const -1))))
-     (if (i32.eq (i32.load8_u (local.get $from)) (local.get $expected))
-         (then
-           (local.set $from (i32.add (local.get $from) (i32.const 1)))
-           (br $cont))))
-   (return (local.get $from)))
-
-   (func (export "run") (param $offs i32) (param $len i32)
-     (memory.init 0 (local.get $offs) (i32.const 0) (local.get $len))))
+    (loop $cont
+      (if (i32.eq (local.get $from) (local.get $to))
+        (then
+          (return (i32.const -1))))
+      (if (i32.eq (i32.load8_u (local.get $from)) (local.get $expected))
+        (then
+          (local.set $from (i32.add (local.get $from) (i32.const 1)))
+          (br $cont))))
+    (return (local.get $from)))
+
+  (func (export "run") (param $offs i32) (param $len i32)
+    (memory.init 0 (local.get $offs) (i32.const 0) (local.get $len))))
 
 (assert_trap (invoke "run" (i32.const 65473) (i32.const 31))
               "out of bounds")
@@ -892,22 +892,22 @@ data.drop 3
 (assert_return (invoke "checkRange" (i32.const 65489) (i32.const 65536) (i32.const 0))
                (i32.const -1))
 (module
-   (memory 1  )
-   (data passive "\42\42\42\42\42\42\42\42\42\42\42\42\42\42\42\42")
+  (memory 1  )
+  (data passive "\42\42\42\42\42\42\42\42\42\42\42\42\42\42\42\42")
    
   (func (export "checkRange") (param $from i32) (param $to i32) (param $expected i32) (result i32)
-   (loop $cont
-     (if (i32.eq (local.get $from) (local.get $to))
-         (then
-           (return (i32.const -1))))
-     (if (i32.eq (i32.load8_u (local.get $from)) (local.get $expected))
-         (then
-           (local.set $from (i32.add (local.get $from) (i32.const 1)))
-           (br $cont))))
-   (return (local.get $from)))
-
-   (func (export "run") (param $offs i32) (param $len i32)
-     (memory.init 0 (local.get $offs) (i32.const 0) (local.get $len))))
+    (loop $cont
+      (if (i32.eq (local.get $from) (local.get $to))
+        (then
+          (return (i32.const -1))))
+      (if (i32.eq (i32.load8_u (local.get $from)) (local.get $expected))
+        (then
+          (local.set $from (i32.add (local.get $from) (i32.const 1)))
+          (br $cont))))
+    (return (local.get $from)))
+
+  (func (export "run") (param $offs i32) (param $len i32)
+    (memory.init 0 (local.get $offs) (i32.const 0) (local.get $len))))
 
 (assert_trap (invoke "run" (i32.const 65528) (i32.const 4294967040))
               "out of bounds")
@@ -919,22 +919,22 @@ data.drop 3
 (assert_return (invoke "checkRange" (i32.const 65536) (i32.const 65536) (i32.const 0))
                (i32.const -1))
 (module
-   (memory 1  )
-   (data passive "\42\42\42\42\42\42\42\42\42\42\42\42\42\42\42\42")
+  (memory 1  )
+  (data passive "\42\42\42\42\42\42\42\42\42\42\42\42\42\42\42\42")
    
   (func (export "checkRange") (param $from i32) (param $to i32) (param $expected i32) (result i32)
-   (loop $cont
-     (if (i32.eq (local.get $from) (local.get $to))
-         (then
-           (return (i32.const -1))))
-     (if (i32.eq (i32.load8_u (local.get $from)) (local.get $expected))
-         (then
-           (local.set $from (i32.add (local.get $from) (i32.const 1)))
-           (br $cont))))
-   (return (local.get $from)))
-
-   (func (export "run") (param $offs i32) (param $len i32)
-     (memory.init 0 (local.get $offs) (i32.const 0) (local.get $len))))
+    (loop $cont
+      (if (i32.eq (local.get $from) (local.get $to))
+        (then
+          (return (i32.const -1))))
+      (if (i32.eq (i32.load8_u (local.get $from)) (local.get $expected))
+        (then
+          (local.set $from (i32.add (local.get $from) (i32.const 1)))
+          (br $cont))))
+    (return (local.get $from)))
+
+  (func (export "run") (param $offs i32) (param $len i32)
+    (memory.init 0 (local.get $offs) (i32.const 0) (local.get $len))))
 
 (assert_trap (invoke "run" (i32.const 0) (i32.const 4294967292))
               "out of bounds")
diff --git a/test/core/table_copy.wast b/test/core/table_copy.wast
index d705694027..51c4ae148b 100644
--- a/test/core/table_copy.wast
+++ b/test/core/table_copy.wast
@@ -11,7 +11,6 @@
 )
 (register "a")
 
-
 (module
   (type (func (result i32)))  ;; type #0
   (import "a" "ef0" (func (result i32)))    ;; index 0
@@ -30,7 +29,7 @@
   (func (result i32) (i32.const 8))
   (func (result i32) (i32.const 9))  ;; index 9
   (func (export "test")
-    nop)
+    (nop))
   (func (export "check") (param i32) (result i32)
     (call_indirect (type 0) (local.get 0)))
 )
@@ -605,33 +604,35 @@
     ))
 
 (invoke "test")
+
 (module
-           (type (func (result i32)))
-           (table 32 64 funcref)
-           (elem (i32.const 0)
-                  $f0 $f1 $f2 $f3 $f4 $f5 $f6 $f7)
-           (func $f0 (export "f0") (result i32) (i32.const 0))
-           (func $f1 (export "f1") (result i32) (i32.const 1))
-           (func $f2 (export "f2") (result i32) (i32.const 2))
-           (func $f3 (export "f3") (result i32) (i32.const 3))
-           (func $f4 (export "f4") (result i32) (i32.const 4))
-           (func $f5 (export "f5") (result i32) (i32.const 5))
-           (func $f6 (export "f6") (result i32) (i32.const 6))
-           (func $f7 (export "f7") (result i32) (i32.const 7))
-           (func $f8 (export "f8") (result i32) (i32.const 8))
-           (func $f9 (export "f9") (result i32) (i32.const 9))
-           (func $f10 (export "f10") (result i32) (i32.const 10))
-           (func $f11 (export "f11") (result i32) (i32.const 11))
-           (func $f12 (export "f12") (result i32) (i32.const 12))
-           (func $f13 (export "f13") (result i32) (i32.const 13))
-           (func $f14 (export "f14") (result i32) (i32.const 14))
-           (func $f15 (export "f15") (result i32) (i32.const 15))
-           (func (export "test") (param $n i32) (result i32)
-             (call_indirect (type 0) (local.get $n)))
-           (func (export "run") (param $targetOffs i32) (param $srcOffs i32) (param $len i32)
-             (table.copy (local.get $targetOffs) (local.get $srcOffs) (local.get $len))))
+  (type (func (result i32)))
+  (table 32 64 funcref)
+  (elem (i32.const 0)
+         $f0 $f1 $f2 $f3 $f4 $f5 $f6 $f7)
+  (func $f0 (export "f0") (result i32) (i32.const 0))
+  (func $f1 (export "f1") (result i32) (i32.const 1))
+  (func $f2 (export "f2") (result i32) (i32.const 2))
+  (func $f3 (export "f3") (result i32) (i32.const 3))
+  (func $f4 (export "f4") (result i32) (i32.const 4))
+  (func $f5 (export "f5") (result i32) (i32.const 5))
+  (func $f6 (export "f6") (result i32) (i32.const 6))
+  (func $f7 (export "f7") (result i32) (i32.const 7))
+  (func $f8 (export "f8") (result i32) (i32.const 8))
+  (func $f9 (export "f9") (result i32) (i32.const 9))
+  (func $f10 (export "f10") (result i32) (i32.const 10))
+  (func $f11 (export "f11") (result i32) (i32.const 11))
+  (func $f12 (export "f12") (result i32) (i32.const 12))
+  (func $f13 (export "f13") (result i32) (i32.const 13))
+  (func $f14 (export "f14") (result i32) (i32.const 14))
+  (func $f15 (export "f15") (result i32) (i32.const 15))
+  (func (export "test") (param $n i32) (result i32)
+    (call_indirect (type 0) (local.get $n)))
+  (func (export "run") (param $targetOffs i32) (param $srcOffs i32) (param $len i32)
+    (table.copy (local.get $targetOffs) (local.get $srcOffs) (local.get $len))))
+
 (assert_trap (invoke "run" (i32.const 24) (i32.const 0) (i32.const 16))
-                        "out of bounds")
+             "out of bounds")
 (assert_return (invoke "test" (i32.const 0)) (i32.const 0))
 (assert_return (invoke "test" (i32.const 1)) (i32.const 1))
 (assert_return (invoke "test" (i32.const 2)) (i32.const 2))
@@ -664,33 +665,35 @@
 (assert_return (invoke "test" (i32.const 29)) (i32.const 5))
 (assert_return (invoke "test" (i32.const 30)) (i32.const 6))
 (assert_return (invoke "test" (i32.const 31)) (i32.const 7))
+
 (module
-           (type (func (result i32)))
-           (table 32 64 funcref)
-           (elem (i32.const 0)
-                  $f0 $f1 $f2 $f3 $f4 $f5 $f6 $f7 $f8)
-           (func $f0 (export "f0") (result i32) (i32.const 0))
-           (func $f1 (export "f1") (result i32) (i32.const 1))
-           (func $f2 (export "f2") (result i32) (i32.const 2))
-           (func $f3 (export "f3") (result i32) (i32.const 3))
-           (func $f4 (export "f4") (result i32) (i32.const 4))
-           (func $f5 (export "f5") (result i32) (i32.const 5))
-           (func $f6 (export "f6") (result i32) (i32.const 6))
-           (func $f7 (export "f7") (result i32) (i32.const 7))
-           (func $f8 (export "f8") (result i32) (i32.const 8))
-           (func $f9 (export "f9") (result i32) (i32.const 9))
-           (func $f10 (export "f10") (result i32) (i32.const 10))
-           (func $f11 (export "f11") (result i32) (i32.const 11))
-           (func $f12 (export "f12") (result i32) (i32.const 12))
-           (func $f13 (export "f13") (result i32) (i32.const 13))
-           (func $f14 (export "f14") (result i32) (i32.const 14))
-           (func $f15 (export "f15") (result i32) (i32.const 15))
-           (func (export "test") (param $n i32) (result i32)
-             (call_indirect (type 0) (local.get $n)))
-           (func (export "run") (param $targetOffs i32) (param $srcOffs i32) (param $len i32)
-             (table.copy (local.get $targetOffs) (local.get $srcOffs) (local.get $len))))
+  (type (func (result i32)))
+  (table 32 64 funcref)
+  (elem (i32.const 0)
+         $f0 $f1 $f2 $f3 $f4 $f5 $f6 $f7 $f8)
+  (func $f0 (export "f0") (result i32) (i32.const 0))
+  (func $f1 (export "f1") (result i32) (i32.const 1))
+  (func $f2 (export "f2") (result i32) (i32.const 2))
+  (func $f3 (export "f3") (result i32) (i32.const 3))
+  (func $f4 (export "f4") (result i32) (i32.const 4))
+  (func $f5 (export "f5") (result i32) (i32.const 5))
+  (func $f6 (export "f6") (result i32) (i32.const 6))
+  (func $f7 (export "f7") (result i32) (i32.const 7))
+  (func $f8 (export "f8") (result i32) (i32.const 8))
+  (func $f9 (export "f9") (result i32) (i32.const 9))
+  (func $f10 (export "f10") (result i32) (i32.const 10))
+  (func $f11 (export "f11") (result i32) (i32.const 11))
+  (func $f12 (export "f12") (result i32) (i32.const 12))
+  (func $f13 (export "f13") (result i32) (i32.const 13))
+  (func $f14 (export "f14") (result i32) (i32.const 14))
+  (func $f15 (export "f15") (result i32) (i32.const 15))
+  (func (export "test") (param $n i32) (result i32)
+    (call_indirect (type 0) (local.get $n)))
+  (func (export "run") (param $targetOffs i32) (param $srcOffs i32) (param $len i32)
+    (table.copy (local.get $targetOffs) (local.get $srcOffs) (local.get $len))))
+
 (assert_trap (invoke "run" (i32.const 23) (i32.const 0) (i32.const 15))
-                        "out of bounds")
+             "out of bounds")
 (assert_return (invoke "test" (i32.const 0)) (i32.const 0))
 (assert_return (invoke "test" (i32.const 1)) (i32.const 1))
 (assert_return (invoke "test" (i32.const 2)) (i32.const 2))
@@ -723,33 +726,35 @@
 (assert_return (invoke "test" (i32.const 29)) (i32.const 6))
 (assert_return (invoke "test" (i32.const 30)) (i32.const 7))
 (assert_return (invoke "test" (i32.const 31)) (i32.const 8))
+
 (module
-           (type (func (result i32)))
-           (table 32 64 funcref)
-           (elem (i32.const 24)
-                  $f0 $f1 $f2 $f3 $f4 $f5 $f6 $f7)
-           (func $f0 (export "f0") (result i32) (i32.const 0))
-           (func $f1 (export "f1") (result i32) (i32.const 1))
-           (func $f2 (export "f2") (result i32) (i32.const 2))
-           (func $f3 (export "f3") (result i32) (i32.const 3))
-           (func $f4 (export "f4") (result i32) (i32.const 4))
-           (func $f5 (export "f5") (result i32) (i32.const 5))
-           (func $f6 (export "f6") (result i32) (i32.const 6))
-           (func $f7 (export "f7") (result i32) (i32.const 7))
-           (func $f8 (export "f8") (result i32) (i32.const 8))
-           (func $f9 (export "f9") (result i32) (i32.const 9))
-           (func $f10 (export "f10") (result i32) (i32.const 10))
-           (func $f11 (export "f11") (result i32) (i32.const 11))
-           (func $f12 (export "f12") (result i32) (i32.const 12))
-           (func $f13 (export "f13") (result i32) (i32.const 13))
-           (func $f14 (export "f14") (result i32) (i32.const 14))
-           (func $f15 (export "f15") (result i32) (i32.const 15))
-           (func (export "test") (param $n i32) (result i32)
-             (call_indirect (type 0) (local.get $n)))
-           (func (export "run") (param $targetOffs i32) (param $srcOffs i32) (param $len i32)
-             (table.copy (local.get $targetOffs) (local.get $srcOffs) (local.get $len))))
+  (type (func (result i32)))
+  (table 32 64 funcref)
+  (elem (i32.const 24)
+         $f0 $f1 $f2 $f3 $f4 $f5 $f6 $f7)
+  (func $f0 (export "f0") (result i32) (i32.const 0))
+  (func $f1 (export "f1") (result i32) (i32.const 1))
+  (func $f2 (export "f2") (result i32) (i32.const 2))
+  (func $f3 (export "f3") (result i32) (i32.const 3))
+  (func $f4 (export "f4") (result i32) (i32.const 4))
+  (func $f5 (export "f5") (result i32) (i32.const 5))
+  (func $f6 (export "f6") (result i32) (i32.const 6))
+  (func $f7 (export "f7") (result i32) (i32.const 7))
+  (func $f8 (export "f8") (result i32) (i32.const 8))
+  (func $f9 (export "f9") (result i32) (i32.const 9))
+  (func $f10 (export "f10") (result i32) (i32.const 10))
+  (func $f11 (export "f11") (result i32) (i32.const 11))
+  (func $f12 (export "f12") (result i32) (i32.const 12))
+  (func $f13 (export "f13") (result i32) (i32.const 13))
+  (func $f14 (export "f14") (result i32) (i32.const 14))
+  (func $f15 (export "f15") (result i32) (i32.const 15))
+  (func (export "test") (param $n i32) (result i32)
+    (call_indirect (type 0) (local.get $n)))
+  (func (export "run") (param $targetOffs i32) (param $srcOffs i32) (param $len i32)
+    (table.copy (local.get $targetOffs) (local.get $srcOffs) (local.get $len))))
+
 (assert_trap (invoke "run" (i32.const 0) (i32.const 24) (i32.const 16))
-                        "out of bounds")
+             "out of bounds")
 (assert_return (invoke "test" (i32.const 0)) (i32.const 0))
 (assert_return (invoke "test" (i32.const 1)) (i32.const 1))
 (assert_return (invoke "test" (i32.const 2)) (i32.const 2))
@@ -782,33 +787,35 @@
 (assert_return (invoke "test" (i32.const 29)) (i32.const 5))
 (assert_return (invoke "test" (i32.const 30)) (i32.const 6))
 (assert_return (invoke "test" (i32.const 31)) (i32.const 7))
+
 (module
-           (type (func (result i32)))
-           (table 32 64 funcref)
-           (elem (i32.const 23)
-                  $f0 $f1 $f2 $f3 $f4 $f5 $f6 $f7 $f8)
-           (func $f0 (export "f0") (result i32) (i32.const 0))
-           (func $f1 (export "f1") (result i32) (i32.const 1))
-           (func $f2 (export "f2") (result i32) (i32.const 2))
-           (func $f3 (export "f3") (result i32) (i32.const 3))
-           (func $f4 (export "f4") (result i32) (i32.const 4))
-           (func $f5 (export "f5") (result i32) (i32.const 5))
-           (func $f6 (export "f6") (result i32) (i32.const 6))
-           (func $f7 (export "f7") (result i32) (i32.const 7))
-           (func $f8 (export "f8") (result i32) (i32.const 8))
-           (func $f9 (export "f9") (result i32) (i32.const 9))
-           (func $f10 (export "f10") (result i32) (i32.const 10))
-           (func $f11 (export "f11") (result i32) (i32.const 11))
-           (func $f12 (export "f12") (result i32) (i32.const 12))
-           (func $f13 (export "f13") (result i32) (i32.const 13))
-           (func $f14 (export "f14") (result i32) (i32.const 14))
-           (func $f15 (export "f15") (result i32) (i32.const 15))
-           (func (export "test") (param $n i32) (result i32)
-             (call_indirect (type 0) (local.get $n)))
-           (func (export "run") (param $targetOffs i32) (param $srcOffs i32) (param $len i32)
-             (table.copy (local.get $targetOffs) (local.get $srcOffs) (local.get $len))))
+  (type (func (result i32)))
+  (table 32 64 funcref)
+  (elem (i32.const 23)
+         $f0 $f1 $f2 $f3 $f4 $f5 $f6 $f7 $f8)
+  (func $f0 (export "f0") (result i32) (i32.const 0))
+  (func $f1 (export "f1") (result i32) (i32.const 1))
+  (func $f2 (export "f2") (result i32) (i32.const 2))
+  (func $f3 (export "f3") (result i32) (i32.const 3))
+  (func $f4 (export "f4") (result i32) (i32.const 4))
+  (func $f5 (export "f5") (result i32) (i32.const 5))
+  (func $f6 (export "f6") (result i32) (i32.const 6))
+  (func $f7 (export "f7") (result i32) (i32.const 7))
+  (func $f8 (export "f8") (result i32) (i32.const 8))
+  (func $f9 (export "f9") (result i32) (i32.const 9))
+  (func $f10 (export "f10") (result i32) (i32.const 10))
+  (func $f11 (export "f11") (result i32) (i32.const 11))
+  (func $f12 (export "f12") (result i32) (i32.const 12))
+  (func $f13 (export "f13") (result i32) (i32.const 13))
+  (func $f14 (export "f14") (result i32) (i32.const 14))
+  (func $f15 (export "f15") (result i32) (i32.const 15))
+  (func (export "test") (param $n i32) (result i32)
+    (call_indirect (type 0) (local.get $n)))
+  (func (export "run") (param $targetOffs i32) (param $srcOffs i32) (param $len i32)
+    (table.copy (local.get $targetOffs) (local.get $srcOffs) (local.get $len))))
+
 (assert_trap (invoke "run" (i32.const 0) (i32.const 23) (i32.const 15))
-                        "out of bounds")
+             "out of bounds")
 (assert_return (invoke "test" (i32.const 0)) (i32.const 0))
 (assert_return (invoke "test" (i32.const 1)) (i32.const 1))
 (assert_return (invoke "test" (i32.const 2)) (i32.const 2))
@@ -841,33 +848,35 @@
 (assert_return (invoke "test" (i32.const 29)) (i32.const 6))
 (assert_return (invoke "test" (i32.const 30)) (i32.const 7))
 (assert_return (invoke "test" (i32.const 31)) (i32.const 8))
+
 (module
-           (type (func (result i32)))
-           (table 32 64 funcref)
-           (elem (i32.const 11)
-                  $f0 $f1 $f2 $f3 $f4 $f5 $f6 $f7)
-           (func $f0 (export "f0") (result i32) (i32.const 0))
-           (func $f1 (export "f1") (result i32) (i32.const 1))
-           (func $f2 (export "f2") (result i32) (i32.const 2))
-           (func $f3 (export "f3") (result i32) (i32.const 3))
-           (func $f4 (export "f4") (result i32) (i32.const 4))
-           (func $f5 (export "f5") (result i32) (i32.const 5))
-           (func $f6 (export "f6") (result i32) (i32.const 6))
-           (func $f7 (export "f7") (result i32) (i32.const 7))
-           (func $f8 (export "f8") (result i32) (i32.const 8))
-           (func $f9 (export "f9") (result i32) (i32.const 9))
-           (func $f10 (export "f10") (result i32) (i32.const 10))
-           (func $f11 (export "f11") (result i32) (i32.const 11))
-           (func $f12 (export "f12") (result i32) (i32.const 12))
-           (func $f13 (export "f13") (result i32) (i32.const 13))
-           (func $f14 (export "f14") (result i32) (i32.const 14))
-           (func $f15 (export "f15") (result i32) (i32.const 15))
-           (func (export "test") (param $n i32) (result i32)
-             (call_indirect (type 0) (local.get $n)))
-           (func (export "run") (param $targetOffs i32) (param $srcOffs i32) (param $len i32)
-             (table.copy (local.get $targetOffs) (local.get $srcOffs) (local.get $len))))
+  (type (func (result i32)))
+  (table 32 64 funcref)
+  (elem (i32.const 11)
+         $f0 $f1 $f2 $f3 $f4 $f5 $f6 $f7)
+  (func $f0 (export "f0") (result i32) (i32.const 0))
+  (func $f1 (export "f1") (result i32) (i32.const 1))
+  (func $f2 (export "f2") (result i32) (i32.const 2))
+  (func $f3 (export "f3") (result i32) (i32.const 3))
+  (func $f4 (export "f4") (result i32) (i32.const 4))
+  (func $f5 (export "f5") (result i32) (i32.const 5))
+  (func $f6 (export "f6") (result i32) (i32.const 6))
+  (func $f7 (export "f7") (result i32) (i32.const 7))
+  (func $f8 (export "f8") (result i32) (i32.const 8))
+  (func $f9 (export "f9") (result i32) (i32.const 9))
+  (func $f10 (export "f10") (result i32) (i32.const 10))
+  (func $f11 (export "f11") (result i32) (i32.const 11))
+  (func $f12 (export "f12") (result i32) (i32.const 12))
+  (func $f13 (export "f13") (result i32) (i32.const 13))
+  (func $f14 (export "f14") (result i32) (i32.const 14))
+  (func $f15 (export "f15") (result i32) (i32.const 15))
+  (func (export "test") (param $n i32) (result i32)
+    (call_indirect (type 0) (local.get $n)))
+  (func (export "run") (param $targetOffs i32) (param $srcOffs i32) (param $len i32)
+    (table.copy (local.get $targetOffs) (local.get $srcOffs) (local.get $len))))
+
 (assert_trap (invoke "run" (i32.const 24) (i32.const 11) (i32.const 16))
-                        "out of bounds")
+             "out of bounds")
 (assert_trap (invoke "test" (i32.const 0)) "uninitialized element")
 (assert_trap (invoke "test" (i32.const 1)) "uninitialized element")
 (assert_trap (invoke "test" (i32.const 2)) "uninitialized element")
@@ -900,33 +909,35 @@
 (assert_trap (invoke "test" (i32.const 29)) "uninitialized element")
 (assert_trap (invoke "test" (i32.const 30)) "uninitialized element")
 (assert_trap (invoke "test" (i32.const 31)) "uninitialized element")
+
 (module
-           (type (func (result i32)))
-           (table 32 64 funcref)
-           (elem (i32.const 24)
-                  $f0 $f1 $f2 $f3 $f4 $f5 $f6 $f7)
-           (func $f0 (export "f0") (result i32) (i32.const 0))
-           (func $f1 (export "f1") (result i32) (i32.const 1))
-           (func $f2 (export "f2") (result i32) (i32.const 2))
-           (func $f3 (export "f3") (result i32) (i32.const 3))
-           (func $f4 (export "f4") (result i32) (i32.const 4))
-           (func $f5 (export "f5") (result i32) (i32.const 5))
-           (func $f6 (export "f6") (result i32) (i32.const 6))
-           (func $f7 (export "f7") (result i32) (i32.const 7))
-           (func $f8 (export "f8") (result i32) (i32.const 8))
-           (func $f9 (export "f9") (result i32) (i32.const 9))
-           (func $f10 (export "f10") (result i32) (i32.const 10))
-           (func $f11 (export "f11") (result i32) (i32.const 11))
-           (func $f12 (export "f12") (result i32) (i32.const 12))
-           (func $f13 (export "f13") (result i32) (i32.const 13))
-           (func $f14 (export "f14") (result i32) (i32.const 14))
-           (func $f15 (export "f15") (result i32) (i32.const 15))
-           (func (export "test") (param $n i32) (result i32)
-             (call_indirect (type 0) (local.get $n)))
-           (func (export "run") (param $targetOffs i32) (param $srcOffs i32) (param $len i32)
-             (table.copy (local.get $targetOffs) (local.get $srcOffs) (local.get $len))))
+  (type (func (result i32)))
+  (table 32 64 funcref)
+  (elem (i32.const 24)
+         $f0 $f1 $f2 $f3 $f4 $f5 $f6 $f7)
+  (func $f0 (export "f0") (result i32) (i32.const 0))
+  (func $f1 (export "f1") (result i32) (i32.const 1))
+  (func $f2 (export "f2") (result i32) (i32.const 2))
+  (func $f3 (export "f3") (result i32) (i32.const 3))
+  (func $f4 (export "f4") (result i32) (i32.const 4))
+  (func $f5 (export "f5") (result i32) (i32.const 5))
+  (func $f6 (export "f6") (result i32) (i32.const 6))
+  (func $f7 (export "f7") (result i32) (i32.const 7))
+  (func $f8 (export "f8") (result i32) (i32.const 8))
+  (func $f9 (export "f9") (result i32) (i32.const 9))
+  (func $f10 (export "f10") (result i32) (i32.const 10))
+  (func $f11 (export "f11") (result i32) (i32.const 11))
+  (func $f12 (export "f12") (result i32) (i32.const 12))
+  (func $f13 (export "f13") (result i32) (i32.const 13))
+  (func $f14 (export "f14") (result i32) (i32.const 14))
+  (func $f15 (export "f15") (result i32) (i32.const 15))
+  (func (export "test") (param $n i32) (result i32)
+    (call_indirect (type 0) (local.get $n)))
+  (func (export "run") (param $targetOffs i32) (param $srcOffs i32) (param $len i32)
+    (table.copy (local.get $targetOffs) (local.get $srcOffs) (local.get $len))))
+
 (assert_trap (invoke "run" (i32.const 11) (i32.const 24) (i32.const 16))
-                        "out of bounds")
+             "out of bounds")
 (assert_trap (invoke "test" (i32.const 0)) "uninitialized element")
 (assert_trap (invoke "test" (i32.const 1)) "uninitialized element")
 (assert_trap (invoke "test" (i32.const 2)) "uninitialized element")
@@ -959,33 +970,35 @@
 (assert_return (invoke "test" (i32.const 29)) (i32.const 5))
 (assert_return (invoke "test" (i32.const 30)) (i32.const 6))
 (assert_return (invoke "test" (i32.const 31)) (i32.const 7))
+
 (module
-           (type (func (result i32)))
-           (table 32 64 funcref)
-           (elem (i32.const 21)
-                  $f0 $f1 $f2 $f3 $f4 $f5 $f6 $f7)
-           (func $f0 (export "f0") (result i32) (i32.const 0))
-           (func $f1 (export "f1") (result i32) (i32.const 1))
-           (func $f2 (export "f2") (result i32) (i32.const 2))
-           (func $f3 (export "f3") (result i32) (i32.const 3))
-           (func $f4 (export "f4") (result i32) (i32.const 4))
-           (func $f5 (export "f5") (result i32) (i32.const 5))
-           (func $f6 (export "f6") (result i32) (i32.const 6))
-           (func $f7 (export "f7") (result i32) (i32.const 7))
-           (func $f8 (export "f8") (result i32) (i32.const 8))
-           (func $f9 (export "f9") (result i32) (i32.const 9))
-           (func $f10 (export "f10") (result i32) (i32.const 10))
-           (func $f11 (export "f11") (result i32) (i32.const 11))
-           (func $f12 (export "f12") (result i32) (i32.const 12))
-           (func $f13 (export "f13") (result i32) (i32.const 13))
-           (func $f14 (export "f14") (result i32) (i32.const 14))
-           (func $f15 (export "f15") (result i32) (i32.const 15))
-           (func (export "test") (param $n i32) (result i32)
-             (call_indirect (type 0) (local.get $n)))
-           (func (export "run") (param $targetOffs i32) (param $srcOffs i32) (param $len i32)
-             (table.copy (local.get $targetOffs) (local.get $srcOffs) (local.get $len))))
+  (type (func (result i32)))
+  (table 32 64 funcref)
+  (elem (i32.const 21)
+         $f0 $f1 $f2 $f3 $f4 $f5 $f6 $f7)
+  (func $f0 (export "f0") (result i32) (i32.const 0))
+  (func $f1 (export "f1") (result i32) (i32.const 1))
+  (func $f2 (export "f2") (result i32) (i32.const 2))
+  (func $f3 (export "f3") (result i32) (i32.const 3))
+  (func $f4 (export "f4") (result i32) (i32.const 4))
+  (func $f5 (export "f5") (result i32) (i32.const 5))
+  (func $f6 (export "f6") (result i32) (i32.const 6))
+  (func $f7 (export "f7") (result i32) (i32.const 7))
+  (func $f8 (export "f8") (result i32) (i32.const 8))
+  (func $f9 (export "f9") (result i32) (i32.const 9))
+  (func $f10 (export "f10") (result i32) (i32.const 10))
+  (func $f11 (export "f11") (result i32) (i32.const 11))
+  (func $f12 (export "f12") (result i32) (i32.const 12))
+  (func $f13 (export "f13") (result i32) (i32.const 13))
+  (func $f14 (export "f14") (result i32) (i32.const 14))
+  (func $f15 (export "f15") (result i32) (i32.const 15))
+  (func (export "test") (param $n i32) (result i32)
+    (call_indirect (type 0) (local.get $n)))
+  (func (export "run") (param $targetOffs i32) (param $srcOffs i32) (param $len i32)
+    (table.copy (local.get $targetOffs) (local.get $srcOffs) (local.get $len))))
+
 (assert_trap (invoke "run" (i32.const 24) (i32.const 21) (i32.const 16))
-                        "out of bounds")
+             "out of bounds")
 (assert_trap (invoke "test" (i32.const 0)) "uninitialized element")
 (assert_trap (invoke "test" (i32.const 1)) "uninitialized element")
 (assert_trap (invoke "test" (i32.const 2)) "uninitialized element")
@@ -1018,33 +1031,35 @@
 (assert_trap (invoke "test" (i32.const 29)) "uninitialized element")
 (assert_trap (invoke "test" (i32.const 30)) "uninitialized element")
 (assert_trap (invoke "test" (i32.const 31)) "uninitialized element")
+
 (module
-           (type (func (result i32)))
-           (table 32 64 funcref)
-           (elem (i32.const 24)
-                  $f0 $f1 $f2 $f3 $f4 $f5 $f6 $f7)
-           (func $f0 (export "f0") (result i32) (i32.const 0))
-           (func $f1 (export "f1") (result i32) (i32.const 1))
-           (func $f2 (export "f2") (result i32) (i32.const 2))
-           (func $f3 (export "f3") (result i32) (i32.const 3))
-           (func $f4 (export "f4") (result i32) (i32.const 4))
-           (func $f5 (export "f5") (result i32) (i32.const 5))
-           (func $f6 (export "f6") (result i32) (i32.const 6))
-           (func $f7 (export "f7") (result i32) (i32.const 7))
-           (func $f8 (export "f8") (result i32) (i32.const 8))
-           (func $f9 (export "f9") (result i32) (i32.const 9))
-           (func $f10 (export "f10") (result i32) (i32.const 10))
-           (func $f11 (export "f11") (result i32) (i32.const 11))
-           (func $f12 (export "f12") (result i32) (i32.const 12))
-           (func $f13 (export "f13") (result i32) (i32.const 13))
-           (func $f14 (export "f14") (result i32) (i32.const 14))
-           (func $f15 (export "f15") (result i32) (i32.const 15))
-           (func (export "test") (param $n i32) (result i32)
-             (call_indirect (type 0) (local.get $n)))
-           (func (export "run") (param $targetOffs i32) (param $srcOffs i32) (param $len i32)
-             (table.copy (local.get $targetOffs) (local.get $srcOffs) (local.get $len))))
+  (type (func (result i32)))
+  (table 32 64 funcref)
+  (elem (i32.const 24)
+         $f0 $f1 $f2 $f3 $f4 $f5 $f6 $f7)
+  (func $f0 (export "f0") (result i32) (i32.const 0))
+  (func $f1 (export "f1") (result i32) (i32.const 1))
+  (func $f2 (export "f2") (result i32) (i32.const 2))
+  (func $f3 (export "f3") (result i32) (i32.const 3))
+  (func $f4 (export "f4") (result i32) (i32.const 4))
+  (func $f5 (export "f5") (result i32) (i32.const 5))
+  (func $f6 (export "f6") (result i32) (i32.const 6))
+  (func $f7 (export "f7") (result i32) (i32.const 7))
+  (func $f8 (export "f8") (result i32) (i32.const 8))
+  (func $f9 (export "f9") (result i32) (i32.const 9))
+  (func $f10 (export "f10") (result i32) (i32.const 10))
+  (func $f11 (export "f11") (result i32) (i32.const 11))
+  (func $f12 (export "f12") (result i32) (i32.const 12))
+  (func $f13 (export "f13") (result i32) (i32.const 13))
+  (func $f14 (export "f14") (result i32) (i32.const 14))
+  (func $f15 (export "f15") (result i32) (i32.const 15))
+  (func (export "test") (param $n i32) (result i32)
+    (call_indirect (type 0) (local.get $n)))
+  (func (export "run") (param $targetOffs i32) (param $srcOffs i32) (param $len i32)
+    (table.copy (local.get $targetOffs) (local.get $srcOffs) (local.get $len))))
+
 (assert_trap (invoke "run" (i32.const 21) (i32.const 24) (i32.const 16))
-                        "out of bounds")
+             "out of bounds")
 (assert_trap (invoke "test" (i32.const 0)) "uninitialized element")
 (assert_trap (invoke "test" (i32.const 1)) "uninitialized element")
 (assert_trap (invoke "test" (i32.const 2)) "uninitialized element")
@@ -1077,33 +1092,35 @@
 (assert_return (invoke "test" (i32.const 29)) (i32.const 5))
 (assert_return (invoke "test" (i32.const 30)) (i32.const 6))
 (assert_return (invoke "test" (i32.const 31)) (i32.const 7))
+
 (module
-           (type (func (result i32)))
-           (table 32 64 funcref)
-           (elem (i32.const 21)
-                  $f0 $f1 $f2 $f3 $f4 $f5 $f6 $f7 $f8 $f9 $f10)
-           (func $f0 (export "f0") (result i32) (i32.const 0))
-           (func $f1 (export "f1") (result i32) (i32.const 1))
-           (func $f2 (export "f2") (result i32) (i32.const 2))
-           (func $f3 (export "f3") (result i32) (i32.const 3))
-           (func $f4 (export "f4") (result i32) (i32.const 4))
-           (func $f5 (export "f5") (result i32) (i32.const 5))
-           (func $f6 (export "f6") (result i32) (i32.const 6))
-           (func $f7 (export "f7") (result i32) (i32.const 7))
-           (func $f8 (export "f8") (result i32) (i32.const 8))
-           (func $f9 (export "f9") (result i32) (i32.const 9))
-           (func $f10 (export "f10") (result i32) (i32.const 10))
-           (func $f11 (export "f11") (result i32) (i32.const 11))
-           (func $f12 (export "f12") (result i32) (i32.const 12))
-           (func $f13 (export "f13") (result i32) (i32.const 13))
-           (func $f14 (export "f14") (result i32) (i32.const 14))
-           (func $f15 (export "f15") (result i32) (i32.const 15))
-           (func (export "test") (param $n i32) (result i32)
-             (call_indirect (type 0) (local.get $n)))
-           (func (export "run") (param $targetOffs i32) (param $srcOffs i32) (param $len i32)
-             (table.copy (local.get $targetOffs) (local.get $srcOffs) (local.get $len))))
+  (type (func (result i32)))
+  (table 32 64 funcref)
+  (elem (i32.const 21)
+         $f0 $f1 $f2 $f3 $f4 $f5 $f6 $f7 $f8 $f9 $f10)
+  (func $f0 (export "f0") (result i32) (i32.const 0))
+  (func $f1 (export "f1") (result i32) (i32.const 1))
+  (func $f2 (export "f2") (result i32) (i32.const 2))
+  (func $f3 (export "f3") (result i32) (i32.const 3))
+  (func $f4 (export "f4") (result i32) (i32.const 4))
+  (func $f5 (export "f5") (result i32) (i32.const 5))
+  (func $f6 (export "f6") (result i32) (i32.const 6))
+  (func $f7 (export "f7") (result i32) (i32.const 7))
+  (func $f8 (export "f8") (result i32) (i32.const 8))
+  (func $f9 (export "f9") (result i32) (i32.const 9))
+  (func $f10 (export "f10") (result i32) (i32.const 10))
+  (func $f11 (export "f11") (result i32) (i32.const 11))
+  (func $f12 (export "f12") (result i32) (i32.const 12))
+  (func $f13 (export "f13") (result i32) (i32.const 13))
+  (func $f14 (export "f14") (result i32) (i32.const 14))
+  (func $f15 (export "f15") (result i32) (i32.const 15))
+  (func (export "test") (param $n i32) (result i32)
+    (call_indirect (type 0) (local.get $n)))
+  (func (export "run") (param $targetOffs i32) (param $srcOffs i32) (param $len i32)
+    (table.copy (local.get $targetOffs) (local.get $srcOffs) (local.get $len))))
+
 (assert_trap (invoke "run" (i32.const 21) (i32.const 21) (i32.const 16))
-                        "out of bounds")
+             "out of bounds")
 (assert_trap (invoke "test" (i32.const 0)) "uninitialized element")
 (assert_trap (invoke "test" (i32.const 1)) "uninitialized element")
 (assert_trap (invoke "test" (i32.const 2)) "uninitialized element")
@@ -1136,33 +1153,35 @@
 (assert_return (invoke "test" (i32.const 29)) (i32.const 8))
 (assert_return (invoke "test" (i32.const 30)) (i32.const 9))
 (assert_return (invoke "test" (i32.const 31)) (i32.const 10))
+
 (module
-           (type (func (result i32)))
-           (table 128 128 funcref)
-           (elem (i32.const 112)
-                  $f0 $f1 $f2 $f3 $f4 $f5 $f6 $f7 $f8 $f9 $f10 $f11 $f12 $f13 $f14 $f15)
-           (func $f0 (export "f0") (result i32) (i32.const 0))
-           (func $f1 (export "f1") (result i32) (i32.const 1))
-           (func $f2 (export "f2") (result i32) (i32.const 2))
-           (func $f3 (export "f3") (result i32) (i32.const 3))
-           (func $f4 (export "f4") (result i32) (i32.const 4))
-           (func $f5 (export "f5") (result i32) (i32.const 5))
-           (func $f6 (export "f6") (result i32) (i32.const 6))
-           (func $f7 (export "f7") (result i32) (i32.const 7))
-           (func $f8 (export "f8") (result i32) (i32.const 8))
-           (func $f9 (export "f9") (result i32) (i32.const 9))
-           (func $f10 (export "f10") (result i32) (i32.const 10))
-           (func $f11 (export "f11") (result i32) (i32.const 11))
-           (func $f12 (export "f12") (result i32) (i32.const 12))
-           (func $f13 (export "f13") (result i32) (i32.const 13))
-           (func $f14 (export "f14") (result i32) (i32.const 14))
-           (func $f15 (export "f15") (result i32) (i32.const 15))
-           (func (export "test") (param $n i32) (result i32)
-             (call_indirect (type 0) (local.get $n)))
-           (func (export "run") (param $targetOffs i32) (param $srcOffs i32) (param $len i32)
-             (table.copy (local.get $targetOffs) (local.get $srcOffs) (local.get $len))))
+  (type (func (result i32)))
+  (table 128 128 funcref)
+  (elem (i32.const 112)
+         $f0 $f1 $f2 $f3 $f4 $f5 $f6 $f7 $f8 $f9 $f10 $f11 $f12 $f13 $f14 $f15)
+  (func $f0 (export "f0") (result i32) (i32.const 0))
+  (func $f1 (export "f1") (result i32) (i32.const 1))
+  (func $f2 (export "f2") (result i32) (i32.const 2))
+  (func $f3 (export "f3") (result i32) (i32.const 3))
+  (func $f4 (export "f4") (result i32) (i32.const 4))
+  (func $f5 (export "f5") (result i32) (i32.const 5))
+  (func $f6 (export "f6") (result i32) (i32.const 6))
+  (func $f7 (export "f7") (result i32) (i32.const 7))
+  (func $f8 (export "f8") (result i32) (i32.const 8))
+  (func $f9 (export "f9") (result i32) (i32.const 9))
+  (func $f10 (export "f10") (result i32) (i32.const 10))
+  (func $f11 (export "f11") (result i32) (i32.const 11))
+  (func $f12 (export "f12") (result i32) (i32.const 12))
+  (func $f13 (export "f13") (result i32) (i32.const 13))
+  (func $f14 (export "f14") (result i32) (i32.const 14))
+  (func $f15 (export "f15") (result i32) (i32.const 15))
+  (func (export "test") (param $n i32) (result i32)
+    (call_indirect (type 0) (local.get $n)))
+  (func (export "run") (param $targetOffs i32) (param $srcOffs i32) (param $len i32)
+    (table.copy (local.get $targetOffs) (local.get $srcOffs) (local.get $len))))
+
 (assert_trap (invoke "run" (i32.const 0) (i32.const 112) (i32.const 4294967264))
-                        "out of bounds")
+             "out of bounds")
 (assert_return (invoke "test" (i32.const 0)) (i32.const 0))
 (assert_return (invoke "test" (i32.const 1)) (i32.const 1))
 (assert_return (invoke "test" (i32.const 2)) (i32.const 2))
@@ -1291,33 +1310,35 @@
 (assert_return (invoke "test" (i32.const 125)) (i32.const 13))
 (assert_return (invoke "test" (i32.const 126)) (i32.const 14))
 (assert_return (invoke "test" (i32.const 127)) (i32.const 15))
+
 (module
-           (type (func (result i32)))
-           (table 128 128 funcref)
-           (elem (i32.const 0)
-                  $f0 $f1 $f2 $f3 $f4 $f5 $f6 $f7 $f8 $f9 $f10 $f11 $f12 $f13 $f14 $f15)
-           (func $f0 (export "f0") (result i32) (i32.const 0))
-           (func $f1 (export "f1") (result i32) (i32.const 1))
-           (func $f2 (export "f2") (result i32) (i32.const 2))
-           (func $f3 (export "f3") (result i32) (i32.const 3))
-           (func $f4 (export "f4") (result i32) (i32.const 4))
-           (func $f5 (export "f5") (result i32) (i32.const 5))
-           (func $f6 (export "f6") (result i32) (i32.const 6))
-           (func $f7 (export "f7") (result i32) (i32.const 7))
-           (func $f8 (export "f8") (result i32) (i32.const 8))
-           (func $f9 (export "f9") (result i32) (i32.const 9))
-           (func $f10 (export "f10") (result i32) (i32.const 10))
-           (func $f11 (export "f11") (result i32) (i32.const 11))
-           (func $f12 (export "f12") (result i32) (i32.const 12))
-           (func $f13 (export "f13") (result i32) (i32.const 13))
-           (func $f14 (export "f14") (result i32) (i32.const 14))
-           (func $f15 (export "f15") (result i32) (i32.const 15))
-           (func (export "test") (param $n i32) (result i32)
-             (call_indirect (type 0) (local.get $n)))
-           (func (export "run") (param $targetOffs i32) (param $srcOffs i32) (param $len i32)
-             (table.copy (local.get $targetOffs) (local.get $srcOffs) (local.get $len))))
+  (type (func (result i32)))
+  (table 128 128 funcref)
+  (elem (i32.const 0)
+         $f0 $f1 $f2 $f3 $f4 $f5 $f6 $f7 $f8 $f9 $f10 $f11 $f12 $f13 $f14 $f15)
+  (func $f0 (export "f0") (result i32) (i32.const 0))
+  (func $f1 (export "f1") (result i32) (i32.const 1))
+  (func $f2 (export "f2") (result i32) (i32.const 2))
+  (func $f3 (export "f3") (result i32) (i32.const 3))
+  (func $f4 (export "f4") (result i32) (i32.const 4))
+  (func $f5 (export "f5") (result i32) (i32.const 5))
+  (func $f6 (export "f6") (result i32) (i32.const 6))
+  (func $f7 (export "f7") (result i32) (i32.const 7))
+  (func $f8 (export "f8") (result i32) (i32.const 8))
+  (func $f9 (export "f9") (result i32) (i32.const 9))
+  (func $f10 (export "f10") (result i32) (i32.const 10))
+  (func $f11 (export "f11") (result i32) (i32.const 11))
+  (func $f12 (export "f12") (result i32) (i32.const 12))
+  (func $f13 (export "f13") (result i32) (i32.const 13))
+  (func $f14 (export "f14") (result i32) (i32.const 14))
+  (func $f15 (export "f15") (result i32) (i32.const 15))
+  (func (export "test") (param $n i32) (result i32)
+    (call_indirect (type 0) (local.get $n)))
+  (func (export "run") (param $targetOffs i32) (param $srcOffs i32) (param $len i32)
+    (table.copy (local.get $targetOffs) (local.get $srcOffs) (local.get $len))))
+
 (assert_trap (invoke "run" (i32.const 112) (i32.const 0) (i32.const 4294967264))
-                        "out of bounds")
+             "out of bounds")
 (assert_return (invoke "test" (i32.const 0)) (i32.const 0))
 (assert_return (invoke "test" (i32.const 1)) (i32.const 1))
 (assert_return (invoke "test" (i32.const 2)) (i32.const 2))
diff --git a/test/core/table_init.wast b/test/core/table_init.wast
index d967a194f0..6f98b25473 100644
--- a/test/core/table_init.wast
+++ b/test/core/table_init.wast
@@ -11,7 +11,6 @@
 )
 (register "a")
 
-
 (module
   (type (func (result i32)))  ;; type #0
   (import "a" "ef0" (func (result i32)))    ;; index 0
@@ -140,15 +139,15 @@
   (func (result i32) (i32.const 8))
   (func (result i32) (i32.const 9))  ;; index 9
   (func (export "test")
-    (table.init 1 (i32.const 7) (i32.const 0) (i32.const 4)) 
-elem.drop 1 
-(table.init 3 (i32.const 15) (i32.const 1) (i32.const 3)) 
-elem.drop 3 
-(table.copy (i32.const 20) (i32.const 15) (i32.const 5)) 
-(table.copy (i32.const 21) (i32.const 29) (i32.const 1)) 
-(table.copy (i32.const 24) (i32.const 10) (i32.const 1)) 
-(table.copy (i32.const 13) (i32.const 11) (i32.const 4)) 
-(table.copy (i32.const 19) (i32.const 20) (i32.const 5)))
+    (table.init 1 (i32.const 7) (i32.const 0) (i32.const 4))
+    (elem.drop 1)
+    (table.init 3 (i32.const 15) (i32.const 1) (i32.const 3))
+    (elem.drop 3)
+    (table.copy (i32.const 20) (i32.const 15) (i32.const 5))
+    (table.copy (i32.const 21) (i32.const 29) (i32.const 1))
+    (table.copy (i32.const 24) (i32.const 10) (i32.const 1))
+    (table.copy (i32.const 13) (i32.const 11) (i32.const 4))
+    (table.copy (i32.const 19) (i32.const 20) (i32.const 5)))
   (func (export "check") (param i32) (result i32)
     (call_indirect (type 0) (local.get 0)))
 )
@@ -230,9 +229,8 @@ elem.drop 3
   (func (result i32) (i32.const 8))
   (func (result i32) (i32.const 9))
   (func (export "test")
-    elem.drop 2
+    (elem.drop 2)
     ))
-
 (assert_trap (invoke "test") "elements segment dropped")
 
 (module
@@ -254,7 +252,6 @@ elem.drop 3
   (func (export "test")
     (table.init 2 (i32.const 12) (i32.const 1) (i32.const 1))
     ))
-
 (assert_trap (invoke "test") "elements segment dropped")
 
 (module
@@ -276,7 +273,6 @@ elem.drop 3
   (func (export "test")
     (table.init 1 (i32.const 12) (i32.const 1) (i32.const 1))
     (table.init 1 (i32.const 21) (i32.const 1) (i32.const 1))))
-
 (invoke "test")
 
 (module
@@ -296,9 +292,8 @@ elem.drop 3
   (func (result i32) (i32.const 8))
   (func (result i32) (i32.const 9))
   (func (export "test")
-    elem.drop 1
-    elem.drop 1))
-
+    (elem.drop 1)
+    (elem.drop 1)))
 (assert_trap (invoke "test") "elements segment dropped")
 
 (module
@@ -318,9 +313,8 @@ elem.drop 3
   (func (result i32) (i32.const 8))
   (func (result i32) (i32.const 9))
   (func (export "test")
-    elem.drop 1
+    (elem.drop 1)
     (table.init 1 (i32.const 12) (i32.const 1) (i32.const 1))))
-
 (assert_trap (invoke "test") "elements segment dropped")
 
 (module
@@ -340,9 +334,8 @@ elem.drop 3
   (func (result i32) (i32.const 8))
   (func (result i32) (i32.const 9))
   (func (export "test")
-    
-    (table.init 1 (i32.const 12) (i32.const 0) (i32.const 5))))
-
+    (table.init 1 (i32.const 12) (i32.const 0) (i32.const 5))
+    ))
 (assert_trap (invoke "test") "out of bounds")
 
 (module
@@ -362,9 +355,8 @@ elem.drop 3
   (func (result i32) (i32.const 8))
   (func (result i32) (i32.const 9))
   (func (export "test")
-    
-    (table.init 1 (i32.const 12) (i32.const 2) (i32.const 3))))
-
+    (table.init 1 (i32.const 12) (i32.const 2) (i32.const 3))
+    ))
 (assert_trap (invoke "test") "out of bounds")
 
 (module
@@ -384,9 +376,8 @@ elem.drop 3
   (func (result i32) (i32.const 8))
   (func (result i32) (i32.const 9))
   (func (export "test")
-    
-    (table.init 1 (i32.const 28) (i32.const 1) (i32.const 3))))
-
+    (table.init 1 (i32.const 28) (i32.const 1) (i32.const 3))
+    ))
 (assert_trap (invoke "test") "out of bounds")
 
 (module
@@ -406,9 +397,8 @@ elem.drop 3
   (func (result i32) (i32.const 8))
   (func (result i32) (i32.const 9))
   (func (export "test")
-    
-    (table.init 1 (i32.const 12) (i32.const 4) (i32.const 0))))
-
+    (table.init 1 (i32.const 12) (i32.const 4) (i32.const 0))
+    ))
 (invoke "test")
 
 (module
@@ -428,601 +418,601 @@ elem.drop 3
   (func (result i32) (i32.const 8))
   (func (result i32) (i32.const 9))
   (func (export "test")
-    
-    (table.init 1 (i32.const 30) (i32.const 2) (i32.const 0))))
-
+    (table.init 1 (i32.const 30) (i32.const 2) (i32.const 0))
+    ))
 (invoke "test")
+
+(assert_invalid
+  (module
+    (table 10 funcref)
+    (elem passive funcref $f0 $f0 $f0)
+    (func $f0)
+    (func (export "test")
+      (table.init 0 (i32.const 1) (i32.const 1) (f32.const 1))))
+  "type mismatch")
+
+(assert_invalid
+  (module
+    (table 10 funcref)
+    (elem passive funcref $f0 $f0 $f0)
+    (func $f0)
+    (func (export "test")
+      (table.init 0 (i32.const 1) (i32.const 1) (i64.const 1))))
+  "type mismatch")
+
+(assert_invalid
+  (module
+    (table 10 funcref)
+    (elem passive funcref $f0 $f0 $f0)
+    (func $f0)
+    (func (export "test")
+      (table.init 0 (i32.const 1) (i32.const 1) (f64.const 1))))
+  "type mismatch")
+
+(assert_invalid
+  (module
+    (table 10 funcref)
+    (elem passive funcref $f0 $f0 $f0)
+    (func $f0)
+    (func (export "test")
+      (table.init 0 (i32.const 1) (f32.const 1) (i32.const 1))))
+  "type mismatch")
+
+(assert_invalid
+  (module
+    (table 10 funcref)
+    (elem passive funcref $f0 $f0 $f0)
+    (func $f0)
+    (func (export "test")
+      (table.init 0 (i32.const 1) (f32.const 1) (f32.const 1))))
+  "type mismatch")
+
+(assert_invalid
+  (module
+    (table 10 funcref)
+    (elem passive funcref $f0 $f0 $f0)
+    (func $f0)
+    (func (export "test")
+      (table.init 0 (i32.const 1) (f32.const 1) (i64.const 1))))
+  "type mismatch")
+
+(assert_invalid
+  (module
+    (table 10 funcref)
+    (elem passive funcref $f0 $f0 $f0)
+    (func $f0)
+    (func (export "test")
+      (table.init 0 (i32.const 1) (f32.const 1) (f64.const 1))))
+  "type mismatch")
+
+(assert_invalid
+  (module
+    (table 10 funcref)
+    (elem passive funcref $f0 $f0 $f0)
+    (func $f0)
+    (func (export "test")
+      (table.init 0 (i32.const 1) (i64.const 1) (i32.const 1))))
+  "type mismatch")
+
+(assert_invalid
+  (module
+    (table 10 funcref)
+    (elem passive funcref $f0 $f0 $f0)
+    (func $f0)
+    (func (export "test")
+      (table.init 0 (i32.const 1) (i64.const 1) (f32.const 1))))
+  "type mismatch")
+
+(assert_invalid
+  (module
+    (table 10 funcref)
+    (elem passive funcref $f0 $f0 $f0)
+    (func $f0)
+    (func (export "test")
+      (table.init 0 (i32.const 1) (i64.const 1) (i64.const 1))))
+  "type mismatch")
+
+(assert_invalid
+  (module
+    (table 10 funcref)
+    (elem passive funcref $f0 $f0 $f0)
+    (func $f0)
+    (func (export "test")
+      (table.init 0 (i32.const 1) (i64.const 1) (f64.const 1))))
+  "type mismatch")
+
+(assert_invalid
+  (module
+    (table 10 funcref)
+    (elem passive funcref $f0 $f0 $f0)
+    (func $f0)
+    (func (export "test")
+      (table.init 0 (i32.const 1) (f64.const 1) (i32.const 1))))
+  "type mismatch")
+
+(assert_invalid
+  (module
+    (table 10 funcref)
+    (elem passive funcref $f0 $f0 $f0)
+    (func $f0)
+    (func (export "test")
+      (table.init 0 (i32.const 1) (f64.const 1) (f32.const 1))))
+  "type mismatch")
+
+(assert_invalid
+  (module
+    (table 10 funcref)
+    (elem passive funcref $f0 $f0 $f0)
+    (func $f0)
+    (func (export "test")
+      (table.init 0 (i32.const 1) (f64.const 1) (i64.const 1))))
+  "type mismatch")
+
+(assert_invalid
+  (module
+    (table 10 funcref)
+    (elem passive funcref $f0 $f0 $f0)
+    (func $f0)
+    (func (export "test")
+      (table.init 0 (i32.const 1) (f64.const 1) (f64.const 1))))
+  "type mismatch")
+
+(assert_invalid
+  (module
+    (table 10 funcref)
+    (elem passive funcref $f0 $f0 $f0)
+    (func $f0)
+    (func (export "test")
+      (table.init 0 (f32.const 1) (i32.const 1) (i32.const 1))))
+  "type mismatch")
+
+(assert_invalid
+  (module
+    (table 10 funcref)
+    (elem passive funcref $f0 $f0 $f0)
+    (func $f0)
+    (func (export "test")
+      (table.init 0 (f32.const 1) (i32.const 1) (f32.const 1))))
+  "type mismatch")
+
+(assert_invalid
+  (module
+    (table 10 funcref)
+    (elem passive funcref $f0 $f0 $f0)
+    (func $f0)
+    (func (export "test")
+      (table.init 0 (f32.const 1) (i32.const 1) (i64.const 1))))
+  "type mismatch")
+
+(assert_invalid
+  (module
+    (table 10 funcref)
+    (elem passive funcref $f0 $f0 $f0)
+    (func $f0)
+    (func (export "test")
+      (table.init 0 (f32.const 1) (i32.const 1) (f64.const 1))))
+  "type mismatch")
+
+(assert_invalid
+  (module
+    (table 10 funcref)
+    (elem passive funcref $f0 $f0 $f0)
+    (func $f0)
+    (func (export "test")
+      (table.init 0 (f32.const 1) (f32.const 1) (i32.const 1))))
+  "type mismatch")
+
+(assert_invalid
+  (module
+    (table 10 funcref)
+    (elem passive funcref $f0 $f0 $f0)
+    (func $f0)
+    (func (export "test")
+      (table.init 0 (f32.const 1) (f32.const 1) (f32.const 1))))
+  "type mismatch")
+
+(assert_invalid
+  (module
+    (table 10 funcref)
+    (elem passive funcref $f0 $f0 $f0)
+    (func $f0)
+    (func (export "test")
+      (table.init 0 (f32.const 1) (f32.const 1) (i64.const 1))))
+  "type mismatch")
+
+(assert_invalid
+  (module
+    (table 10 funcref)
+    (elem passive funcref $f0 $f0 $f0)
+    (func $f0)
+    (func (export "test")
+      (table.init 0 (f32.const 1) (f32.const 1) (f64.const 1))))
+  "type mismatch")
+
+(assert_invalid
+  (module
+    (table 10 funcref)
+    (elem passive funcref $f0 $f0 $f0)
+    (func $f0)
+    (func (export "test")
+      (table.init 0 (f32.const 1) (i64.const 1) (i32.const 1))))
+  "type mismatch")
+
+(assert_invalid
+  (module
+    (table 10 funcref)
+    (elem passive funcref $f0 $f0 $f0)
+    (func $f0)
+    (func (export "test")
+      (table.init 0 (f32.const 1) (i64.const 1) (f32.const 1))))
+  "type mismatch")
+
+(assert_invalid
+  (module
+    (table 10 funcref)
+    (elem passive funcref $f0 $f0 $f0)
+    (func $f0)
+    (func (export "test")
+      (table.init 0 (f32.const 1) (i64.const 1) (i64.const 1))))
+  "type mismatch")
+
+(assert_invalid
+  (module
+    (table 10 funcref)
+    (elem passive funcref $f0 $f0 $f0)
+    (func $f0)
+    (func (export "test")
+      (table.init 0 (f32.const 1) (i64.const 1) (f64.const 1))))
+  "type mismatch")
+
+(assert_invalid
+  (module
+    (table 10 funcref)
+    (elem passive funcref $f0 $f0 $f0)
+    (func $f0)
+    (func (export "test")
+      (table.init 0 (f32.const 1) (f64.const 1) (i32.const 1))))
+  "type mismatch")
+
+(assert_invalid
+  (module
+    (table 10 funcref)
+    (elem passive funcref $f0 $f0 $f0)
+    (func $f0)
+    (func (export "test")
+      (table.init 0 (f32.const 1) (f64.const 1) (f32.const 1))))
+  "type mismatch")
+
+(assert_invalid
+  (module
+    (table 10 funcref)
+    (elem passive funcref $f0 $f0 $f0)
+    (func $f0)
+    (func (export "test")
+      (table.init 0 (f32.const 1) (f64.const 1) (i64.const 1))))
+  "type mismatch")
+
+(assert_invalid
+  (module
+    (table 10 funcref)
+    (elem passive funcref $f0 $f0 $f0)
+    (func $f0)
+    (func (export "test")
+      (table.init 0 (f32.const 1) (f64.const 1) (f64.const 1))))
+  "type mismatch")
+
+(assert_invalid
+  (module
+    (table 10 funcref)
+    (elem passive funcref $f0 $f0 $f0)
+    (func $f0)
+    (func (export "test")
+      (table.init 0 (i64.const 1) (i32.const 1) (i32.const 1))))
+  "type mismatch")
+
+(assert_invalid
+  (module
+    (table 10 funcref)
+    (elem passive funcref $f0 $f0 $f0)
+    (func $f0)
+    (func (export "test")
+      (table.init 0 (i64.const 1) (i32.const 1) (f32.const 1))))
+  "type mismatch")
+
+(assert_invalid
+  (module
+    (table 10 funcref)
+    (elem passive funcref $f0 $f0 $f0)
+    (func $f0)
+    (func (export "test")
+      (table.init 0 (i64.const 1) (i32.const 1) (i64.const 1))))
+  "type mismatch")
+
+(assert_invalid
+  (module
+    (table 10 funcref)
+    (elem passive funcref $f0 $f0 $f0)
+    (func $f0)
+    (func (export "test")
+      (table.init 0 (i64.const 1) (i32.const 1) (f64.const 1))))
+  "type mismatch")
+
+(assert_invalid
+  (module
+    (table 10 funcref)
+    (elem passive funcref $f0 $f0 $f0)
+    (func $f0)
+    (func (export "test")
+      (table.init 0 (i64.const 1) (f32.const 1) (i32.const 1))))
+  "type mismatch")
+
+(assert_invalid
+  (module
+    (table 10 funcref)
+    (elem passive funcref $f0 $f0 $f0)
+    (func $f0)
+    (func (export "test")
+      (table.init 0 (i64.const 1) (f32.const 1) (f32.const 1))))
+  "type mismatch")
+
+(assert_invalid
+  (module
+    (table 10 funcref)
+    (elem passive funcref $f0 $f0 $f0)
+    (func $f0)
+    (func (export "test")
+      (table.init 0 (i64.const 1) (f32.const 1) (i64.const 1))))
+  "type mismatch")
+
+(assert_invalid
+  (module
+    (table 10 funcref)
+    (elem passive funcref $f0 $f0 $f0)
+    (func $f0)
+    (func (export "test")
+      (table.init 0 (i64.const 1) (f32.const 1) (f64.const 1))))
+  "type mismatch")
+
+(assert_invalid
+  (module
+    (table 10 funcref)
+    (elem passive funcref $f0 $f0 $f0)
+    (func $f0)
+    (func (export "test")
+      (table.init 0 (i64.const 1) (i64.const 1) (i32.const 1))))
+  "type mismatch")
+
+(assert_invalid
+  (module
+    (table 10 funcref)
+    (elem passive funcref $f0 $f0 $f0)
+    (func $f0)
+    (func (export "test")
+      (table.init 0 (i64.const 1) (i64.const 1) (f32.const 1))))
+  "type mismatch")
+
+(assert_invalid
+  (module
+    (table 10 funcref)
+    (elem passive funcref $f0 $f0 $f0)
+    (func $f0)
+    (func (export "test")
+      (table.init 0 (i64.const 1) (i64.const 1) (i64.const 1))))
+  "type mismatch")
+
+(assert_invalid
+  (module
+    (table 10 funcref)
+    (elem passive funcref $f0 $f0 $f0)
+    (func $f0)
+    (func (export "test")
+      (table.init 0 (i64.const 1) (i64.const 1) (f64.const 1))))
+  "type mismatch")
+
+(assert_invalid
+  (module
+    (table 10 funcref)
+    (elem passive funcref $f0 $f0 $f0)
+    (func $f0)
+    (func (export "test")
+      (table.init 0 (i64.const 1) (f64.const 1) (i32.const 1))))
+  "type mismatch")
+
+(assert_invalid
+  (module
+    (table 10 funcref)
+    (elem passive funcref $f0 $f0 $f0)
+    (func $f0)
+    (func (export "test")
+      (table.init 0 (i64.const 1) (f64.const 1) (f32.const 1))))
+  "type mismatch")
+
+(assert_invalid
+  (module
+    (table 10 funcref)
+    (elem passive funcref $f0 $f0 $f0)
+    (func $f0)
+    (func (export "test")
+      (table.init 0 (i64.const 1) (f64.const 1) (i64.const 1))))
+  "type mismatch")
+
+(assert_invalid
+  (module
+    (table 10 funcref)
+    (elem passive funcref $f0 $f0 $f0)
+    (func $f0)
+    (func (export "test")
+      (table.init 0 (i64.const 1) (f64.const 1) (f64.const 1))))
+  "type mismatch")
+
+(assert_invalid
+  (module
+    (table 10 funcref)
+    (elem passive funcref $f0 $f0 $f0)
+    (func $f0)
+    (func (export "test")
+      (table.init 0 (f64.const 1) (i32.const 1) (i32.const 1))))
+  "type mismatch")
+
+(assert_invalid
+  (module
+    (table 10 funcref)
+    (elem passive funcref $f0 $f0 $f0)
+    (func $f0)
+    (func (export "test")
+      (table.init 0 (f64.const 1) (i32.const 1) (f32.const 1))))
+  "type mismatch")
+
+(assert_invalid
+  (module
+    (table 10 funcref)
+    (elem passive funcref $f0 $f0 $f0)
+    (func $f0)
+    (func (export "test")
+      (table.init 0 (f64.const 1) (i32.const 1) (i64.const 1))))
+  "type mismatch")
+
+(assert_invalid
+  (module
+    (table 10 funcref)
+    (elem passive funcref $f0 $f0 $f0)
+    (func $f0)
+    (func (export "test")
+      (table.init 0 (f64.const 1) (i32.const 1) (f64.const 1))))
+  "type mismatch")
+
+(assert_invalid
+  (module
+    (table 10 funcref)
+    (elem passive funcref $f0 $f0 $f0)
+    (func $f0)
+    (func (export "test")
+      (table.init 0 (f64.const 1) (f32.const 1) (i32.const 1))))
+  "type mismatch")
+
+(assert_invalid
+  (module
+    (table 10 funcref)
+    (elem passive funcref $f0 $f0 $f0)
+    (func $f0)
+    (func (export "test")
+      (table.init 0 (f64.const 1) (f32.const 1) (f32.const 1))))
+  "type mismatch")
+
+(assert_invalid
+  (module
+    (table 10 funcref)
+    (elem passive funcref $f0 $f0 $f0)
+    (func $f0)
+    (func (export "test")
+      (table.init 0 (f64.const 1) (f32.const 1) (i64.const 1))))
+  "type mismatch")
+
+(assert_invalid
+  (module
+    (table 10 funcref)
+    (elem passive funcref $f0 $f0 $f0)
+    (func $f0)
+    (func (export "test")
+      (table.init 0 (f64.const 1) (f32.const 1) (f64.const 1))))
+  "type mismatch")
+
+(assert_invalid
+  (module
+    (table 10 funcref)
+    (elem passive funcref $f0 $f0 $f0)
+    (func $f0)
+    (func (export "test")
+      (table.init 0 (f64.const 1) (i64.const 1) (i32.const 1))))
+  "type mismatch")
+
+(assert_invalid
+  (module
+    (table 10 funcref)
+    (elem passive funcref $f0 $f0 $f0)
+    (func $f0)
+    (func (export "test")
+      (table.init 0 (f64.const 1) (i64.const 1) (f32.const 1))))
+  "type mismatch")
+
+(assert_invalid
+  (module
+    (table 10 funcref)
+    (elem passive funcref $f0 $f0 $f0)
+    (func $f0)
+    (func (export "test")
+      (table.init 0 (f64.const 1) (i64.const 1) (i64.const 1))))
+  "type mismatch")
+
+(assert_invalid
+  (module
+    (table 10 funcref)
+    (elem passive funcref $f0 $f0 $f0)
+    (func $f0)
+    (func (export "test")
+      (table.init 0 (f64.const 1) (i64.const 1) (f64.const 1))))
+  "type mismatch")
+
+(assert_invalid
+  (module
+    (table 10 funcref)
+    (elem passive funcref $f0 $f0 $f0)
+    (func $f0)
+    (func (export "test")
+      (table.init 0 (f64.const 1) (f64.const 1) (i32.const 1))))
+  "type mismatch")
+
 (assert_invalid
-   (module
-     (table 10 funcref)
-     (elem passive funcref $f0 $f0 $f0)
-     (func $f0)
-     (func (export "test")
-       (table.init 0 (i32.const 1) (i32.const 1) (f32.const 1))))
-   "type mismatch")
-
-(assert_invalid
-   (module
-     (table 10 funcref)
-     (elem passive funcref $f0 $f0 $f0)
-     (func $f0)
-     (func (export "test")
-       (table.init 0 (i32.const 1) (i32.const 1) (i64.const 1))))
-   "type mismatch")
-
-(assert_invalid
-   (module
-     (table 10 funcref)
-     (elem passive funcref $f0 $f0 $f0)
-     (func $f0)
-     (func (export "test")
-       (table.init 0 (i32.const 1) (i32.const 1) (f64.const 1))))
-   "type mismatch")
-
-(assert_invalid
-   (module
-     (table 10 funcref)
-     (elem passive funcref $f0 $f0 $f0)
-     (func $f0)
-     (func (export "test")
-       (table.init 0 (i32.const 1) (f32.const 1) (i32.const 1))))
-   "type mismatch")
-
-(assert_invalid
-   (module
-     (table 10 funcref)
-     (elem passive funcref $f0 $f0 $f0)
-     (func $f0)
-     (func (export "test")
-       (table.init 0 (i32.const 1) (f32.const 1) (f32.const 1))))
-   "type mismatch")
-
-(assert_invalid
-   (module
-     (table 10 funcref)
-     (elem passive funcref $f0 $f0 $f0)
-     (func $f0)
-     (func (export "test")
-       (table.init 0 (i32.const 1) (f32.const 1) (i64.const 1))))
-   "type mismatch")
-
-(assert_invalid
-   (module
-     (table 10 funcref)
-     (elem passive funcref $f0 $f0 $f0)
-     (func $f0)
-     (func (export "test")
-       (table.init 0 (i32.const 1) (f32.const 1) (f64.const 1))))
-   "type mismatch")
-
-(assert_invalid
-   (module
-     (table 10 funcref)
-     (elem passive funcref $f0 $f0 $f0)
-     (func $f0)
-     (func (export "test")
-       (table.init 0 (i32.const 1) (i64.const 1) (i32.const 1))))
-   "type mismatch")
-
-(assert_invalid
-   (module
-     (table 10 funcref)
-     (elem passive funcref $f0 $f0 $f0)
-     (func $f0)
-     (func (export "test")
-       (table.init 0 (i32.const 1) (i64.const 1) (f32.const 1))))
-   "type mismatch")
-
-(assert_invalid
-   (module
-     (table 10 funcref)
-     (elem passive funcref $f0 $f0 $f0)
-     (func $f0)
-     (func (export "test")
-       (table.init 0 (i32.const 1) (i64.const 1) (i64.const 1))))
-   "type mismatch")
-
-(assert_invalid
-   (module
-     (table 10 funcref)
-     (elem passive funcref $f0 $f0 $f0)
-     (func $f0)
-     (func (export "test")
-       (table.init 0 (i32.const 1) (i64.const 1) (f64.const 1))))
-   "type mismatch")
-
-(assert_invalid
-   (module
-     (table 10 funcref)
-     (elem passive funcref $f0 $f0 $f0)
-     (func $f0)
-     (func (export "test")
-       (table.init 0 (i32.const 1) (f64.const 1) (i32.const 1))))
-   "type mismatch")
-
-(assert_invalid
-   (module
-     (table 10 funcref)
-     (elem passive funcref $f0 $f0 $f0)
-     (func $f0)
-     (func (export "test")
-       (table.init 0 (i32.const 1) (f64.const 1) (f32.const 1))))
-   "type mismatch")
-
-(assert_invalid
-   (module
-     (table 10 funcref)
-     (elem passive funcref $f0 $f0 $f0)
-     (func $f0)
-     (func (export "test")
-       (table.init 0 (i32.const 1) (f64.const 1) (i64.const 1))))
-   "type mismatch")
-
-(assert_invalid
-   (module
-     (table 10 funcref)
-     (elem passive funcref $f0 $f0 $f0)
-     (func $f0)
-     (func (export "test")
-       (table.init 0 (i32.const 1) (f64.const 1) (f64.const 1))))
-   "type mismatch")
-
-(assert_invalid
-   (module
-     (table 10 funcref)
-     (elem passive funcref $f0 $f0 $f0)
-     (func $f0)
-     (func (export "test")
-       (table.init 0 (f32.const 1) (i32.const 1) (i32.const 1))))
-   "type mismatch")
-
-(assert_invalid
-   (module
-     (table 10 funcref)
-     (elem passive funcref $f0 $f0 $f0)
-     (func $f0)
-     (func (export "test")
-       (table.init 0 (f32.const 1) (i32.const 1) (f32.const 1))))
-   "type mismatch")
-
-(assert_invalid
-   (module
-     (table 10 funcref)
-     (elem passive funcref $f0 $f0 $f0)
-     (func $f0)
-     (func (export "test")
-       (table.init 0 (f32.const 1) (i32.const 1) (i64.const 1))))
-   "type mismatch")
-
-(assert_invalid
-   (module
-     (table 10 funcref)
-     (elem passive funcref $f0 $f0 $f0)
-     (func $f0)
-     (func (export "test")
-       (table.init 0 (f32.const 1) (i32.const 1) (f64.const 1))))
-   "type mismatch")
-
-(assert_invalid
-   (module
-     (table 10 funcref)
-     (elem passive funcref $f0 $f0 $f0)
-     (func $f0)
-     (func (export "test")
-       (table.init 0 (f32.const 1) (f32.const 1) (i32.const 1))))
-   "type mismatch")
-
-(assert_invalid
-   (module
-     (table 10 funcref)
-     (elem passive funcref $f0 $f0 $f0)
-     (func $f0)
-     (func (export "test")
-       (table.init 0 (f32.const 1) (f32.const 1) (f32.const 1))))
-   "type mismatch")
-
-(assert_invalid
-   (module
-     (table 10 funcref)
-     (elem passive funcref $f0 $f0 $f0)
-     (func $f0)
-     (func (export "test")
-       (table.init 0 (f32.const 1) (f32.const 1) (i64.const 1))))
-   "type mismatch")
-
-(assert_invalid
-   (module
-     (table 10 funcref)
-     (elem passive funcref $f0 $f0 $f0)
-     (func $f0)
-     (func (export "test")
-       (table.init 0 (f32.const 1) (f32.const 1) (f64.const 1))))
-   "type mismatch")
-
-(assert_invalid
-   (module
-     (table 10 funcref)
-     (elem passive funcref $f0 $f0 $f0)
-     (func $f0)
-     (func (export "test")
-       (table.init 0 (f32.const 1) (i64.const 1) (i32.const 1))))
-   "type mismatch")
-
-(assert_invalid
-   (module
-     (table 10 funcref)
-     (elem passive funcref $f0 $f0 $f0)
-     (func $f0)
-     (func (export "test")
-       (table.init 0 (f32.const 1) (i64.const 1) (f32.const 1))))
-   "type mismatch")
-
-(assert_invalid
-   (module
-     (table 10 funcref)
-     (elem passive funcref $f0 $f0 $f0)
-     (func $f0)
-     (func (export "test")
-       (table.init 0 (f32.const 1) (i64.const 1) (i64.const 1))))
-   "type mismatch")
-
-(assert_invalid
-   (module
-     (table 10 funcref)
-     (elem passive funcref $f0 $f0 $f0)
-     (func $f0)
-     (func (export "test")
-       (table.init 0 (f32.const 1) (i64.const 1) (f64.const 1))))
-   "type mismatch")
-
-(assert_invalid
-   (module
-     (table 10 funcref)
-     (elem passive funcref $f0 $f0 $f0)
-     (func $f0)
-     (func (export "test")
-       (table.init 0 (f32.const 1) (f64.const 1) (i32.const 1))))
-   "type mismatch")
-
-(assert_invalid
-   (module
-     (table 10 funcref)
-     (elem passive funcref $f0 $f0 $f0)
-     (func $f0)
-     (func (export "test")
-       (table.init 0 (f32.const 1) (f64.const 1) (f32.const 1))))
-   "type mismatch")
-
-(assert_invalid
-   (module
-     (table 10 funcref)
-     (elem passive funcref $f0 $f0 $f0)
-     (func $f0)
-     (func (export "test")
-       (table.init 0 (f32.const 1) (f64.const 1) (i64.const 1))))
-   "type mismatch")
-
-(assert_invalid
-   (module
-     (table 10 funcref)
-     (elem passive funcref $f0 $f0 $f0)
-     (func $f0)
-     (func (export "test")
-       (table.init 0 (f32.const 1) (f64.const 1) (f64.const 1))))
-   "type mismatch")
-
-(assert_invalid
-   (module
-     (table 10 funcref)
-     (elem passive funcref $f0 $f0 $f0)
-     (func $f0)
-     (func (export "test")
-       (table.init 0 (i64.const 1) (i32.const 1) (i32.const 1))))
-   "type mismatch")
-
-(assert_invalid
-   (module
-     (table 10 funcref)
-     (elem passive funcref $f0 $f0 $f0)
-     (func $f0)
-     (func (export "test")
-       (table.init 0 (i64.const 1) (i32.const 1) (f32.const 1))))
-   "type mismatch")
-
-(assert_invalid
-   (module
-     (table 10 funcref)
-     (elem passive funcref $f0 $f0 $f0)
-     (func $f0)
-     (func (export "test")
-       (table.init 0 (i64.const 1) (i32.const 1) (i64.const 1))))
-   "type mismatch")
-
-(assert_invalid
-   (module
-     (table 10 funcref)
-     (elem passive funcref $f0 $f0 $f0)
-     (func $f0)
-     (func (export "test")
-       (table.init 0 (i64.const 1) (i32.const 1) (f64.const 1))))
-   "type mismatch")
-
-(assert_invalid
-   (module
-     (table 10 funcref)
-     (elem passive funcref $f0 $f0 $f0)
-     (func $f0)
-     (func (export "test")
-       (table.init 0 (i64.const 1) (f32.const 1) (i32.const 1))))
-   "type mismatch")
-
-(assert_invalid
-   (module
-     (table 10 funcref)
-     (elem passive funcref $f0 $f0 $f0)
-     (func $f0)
-     (func (export "test")
-       (table.init 0 (i64.const 1) (f32.const 1) (f32.const 1))))
-   "type mismatch")
-
-(assert_invalid
-   (module
-     (table 10 funcref)
-     (elem passive funcref $f0 $f0 $f0)
-     (func $f0)
-     (func (export "test")
-       (table.init 0 (i64.const 1) (f32.const 1) (i64.const 1))))
-   "type mismatch")
-
-(assert_invalid
-   (module
-     (table 10 funcref)
-     (elem passive funcref $f0 $f0 $f0)
-     (func $f0)
-     (func (export "test")
-       (table.init 0 (i64.const 1) (f32.const 1) (f64.const 1))))
-   "type mismatch")
-
-(assert_invalid
-   (module
-     (table 10 funcref)
-     (elem passive funcref $f0 $f0 $f0)
-     (func $f0)
-     (func (export "test")
-       (table.init 0 (i64.const 1) (i64.const 1) (i32.const 1))))
-   "type mismatch")
-
-(assert_invalid
-   (module
-     (table 10 funcref)
-     (elem passive funcref $f0 $f0 $f0)
-     (func $f0)
-     (func (export "test")
-       (table.init 0 (i64.const 1) (i64.const 1) (f32.const 1))))
-   "type mismatch")
-
-(assert_invalid
-   (module
-     (table 10 funcref)
-     (elem passive funcref $f0 $f0 $f0)
-     (func $f0)
-     (func (export "test")
-       (table.init 0 (i64.const 1) (i64.const 1) (i64.const 1))))
-   "type mismatch")
-
-(assert_invalid
-   (module
-     (table 10 funcref)
-     (elem passive funcref $f0 $f0 $f0)
-     (func $f0)
-     (func (export "test")
-       (table.init 0 (i64.const 1) (i64.const 1) (f64.const 1))))
-   "type mismatch")
-
-(assert_invalid
-   (module
-     (table 10 funcref)
-     (elem passive funcref $f0 $f0 $f0)
-     (func $f0)
-     (func (export "test")
-       (table.init 0 (i64.const 1) (f64.const 1) (i32.const 1))))
-   "type mismatch")
-
-(assert_invalid
-   (module
-     (table 10 funcref)
-     (elem passive funcref $f0 $f0 $f0)
-     (func $f0)
-     (func (export "test")
-       (table.init 0 (i64.const 1) (f64.const 1) (f32.const 1))))
-   "type mismatch")
-
-(assert_invalid
-   (module
-     (table 10 funcref)
-     (elem passive funcref $f0 $f0 $f0)
-     (func $f0)
-     (func (export "test")
-       (table.init 0 (i64.const 1) (f64.const 1) (i64.const 1))))
-   "type mismatch")
-
-(assert_invalid
-   (module
-     (table 10 funcref)
-     (elem passive funcref $f0 $f0 $f0)
-     (func $f0)
-     (func (export "test")
-       (table.init 0 (i64.const 1) (f64.const 1) (f64.const 1))))
-   "type mismatch")
-
-(assert_invalid
-   (module
-     (table 10 funcref)
-     (elem passive funcref $f0 $f0 $f0)
-     (func $f0)
-     (func (export "test")
-       (table.init 0 (f64.const 1) (i32.const 1) (i32.const 1))))
-   "type mismatch")
-
-(assert_invalid
-   (module
-     (table 10 funcref)
-     (elem passive funcref $f0 $f0 $f0)
-     (func $f0)
-     (func (export "test")
-       (table.init 0 (f64.const 1) (i32.const 1) (f32.const 1))))
-   "type mismatch")
-
-(assert_invalid
-   (module
-     (table 10 funcref)
-     (elem passive funcref $f0 $f0 $f0)
-     (func $f0)
-     (func (export "test")
-       (table.init 0 (f64.const 1) (i32.const 1) (i64.const 1))))
-   "type mismatch")
-
-(assert_invalid
-   (module
-     (table 10 funcref)
-     (elem passive funcref $f0 $f0 $f0)
-     (func $f0)
-     (func (export "test")
-       (table.init 0 (f64.const 1) (i32.const 1) (f64.const 1))))
-   "type mismatch")
-
-(assert_invalid
-   (module
-     (table 10 funcref)
-     (elem passive funcref $f0 $f0 $f0)
-     (func $f0)
-     (func (export "test")
-       (table.init 0 (f64.const 1) (f32.const 1) (i32.const 1))))
-   "type mismatch")
-
-(assert_invalid
-   (module
-     (table 10 funcref)
-     (elem passive funcref $f0 $f0 $f0)
-     (func $f0)
-     (func (export "test")
-       (table.init 0 (f64.const 1) (f32.const 1) (f32.const 1))))
-   "type mismatch")
-
-(assert_invalid
-   (module
-     (table 10 funcref)
-     (elem passive funcref $f0 $f0 $f0)
-     (func $f0)
-     (func (export "test")
-       (table.init 0 (f64.const 1) (f32.const 1) (i64.const 1))))
-   "type mismatch")
-
-(assert_invalid
-   (module
-     (table 10 funcref)
-     (elem passive funcref $f0 $f0 $f0)
-     (func $f0)
-     (func (export "test")
-       (table.init 0 (f64.const 1) (f32.const 1) (f64.const 1))))
-   "type mismatch")
-
-(assert_invalid
-   (module
-     (table 10 funcref)
-     (elem passive funcref $f0 $f0 $f0)
-     (func $f0)
-     (func (export "test")
-       (table.init 0 (f64.const 1) (i64.const 1) (i32.const 1))))
-   "type mismatch")
-
-(assert_invalid
-   (module
-     (table 10 funcref)
-     (elem passive funcref $f0 $f0 $f0)
-     (func $f0)
-     (func (export "test")
-       (table.init 0 (f64.const 1) (i64.const 1) (f32.const 1))))
-   "type mismatch")
-
-(assert_invalid
-   (module
-     (table 10 funcref)
-     (elem passive funcref $f0 $f0 $f0)
-     (func $f0)
-     (func (export "test")
-       (table.init 0 (f64.const 1) (i64.const 1) (i64.const 1))))
-   "type mismatch")
-
-(assert_invalid
-   (module
-     (table 10 funcref)
-     (elem passive funcref $f0 $f0 $f0)
-     (func $f0)
-     (func (export "test")
-       (table.init 0 (f64.const 1) (i64.const 1) (f64.const 1))))
-   "type mismatch")
-
-(assert_invalid
-   (module
-     (table 10 funcref)
-     (elem passive funcref $f0 $f0 $f0)
-     (func $f0)
-     (func (export "test")
-       (table.init 0 (f64.const 1) (f64.const 1) (i32.const 1))))
-   "type mismatch")
-
-(assert_invalid
-   (module
-     (table 10 funcref)
-     (elem passive funcref $f0 $f0 $f0)
-     (func $f0)
-     (func (export "test")
-       (table.init 0 (f64.const 1) (f64.const 1) (f32.const 1))))
-   "type mismatch")
-
-(assert_invalid
-   (module
-     (table 10 funcref)
-     (elem passive funcref $f0 $f0 $f0)
-     (func $f0)
-     (func (export "test")
-       (table.init 0 (f64.const 1) (f64.const 1) (i64.const 1))))
-   "type mismatch")
-
-(assert_invalid
-   (module
-     (table 10 funcref)
-     (elem passive funcref $f0 $f0 $f0)
-     (func $f0)
-     (func (export "test")
-       (table.init 0 (f64.const 1) (f64.const 1) (f64.const 1))))
-   "type mismatch")
+  (module
+    (table 10 funcref)
+    (elem passive funcref $f0 $f0 $f0)
+    (func $f0)
+    (func (export "test")
+      (table.init 0 (f64.const 1) (f64.const 1) (f32.const 1))))
+  "type mismatch")
+
+(assert_invalid
+  (module
+    (table 10 funcref)
+    (elem passive funcref $f0 $f0 $f0)
+    (func $f0)
+    (func (export "test")
+      (table.init 0 (f64.const 1) (f64.const 1) (i64.const 1))))
+  "type mismatch")
+
+(assert_invalid
+  (module
+    (table 10 funcref)
+    (elem passive funcref $f0 $f0 $f0)
+    (func $f0)
+    (func (export "test")
+      (table.init 0 (f64.const 1) (f64.const 1) (f64.const 1))))
+  "type mismatch")
 
 (module
-           (type (func (result i32)))
-           (table 32 64 funcref)
-           (elem passive funcref $f0 $f1 $f2 $f3 $f4 $f5 $f6 $f7 $f8 $f9 $f10 $f11 $f12 $f13 $f14 $f15)
-           (func $f0 (export "f0") (result i32) (i32.const 0))
-           (func $f1 (export "f1") (result i32) (i32.const 1))
-           (func $f2 (export "f2") (result i32) (i32.const 2))
-           (func $f3 (export "f3") (result i32) (i32.const 3))
-           (func $f4 (export "f4") (result i32) (i32.const 4))
-           (func $f5 (export "f5") (result i32) (i32.const 5))
-           (func $f6 (export "f6") (result i32) (i32.const 6))
-           (func $f7 (export "f7") (result i32) (i32.const 7))
-           (func $f8 (export "f8") (result i32) (i32.const 8))
-           (func $f9 (export "f9") (result i32) (i32.const 9))
-           (func $f10 (export "f10") (result i32) (i32.const 10))
-           (func $f11 (export "f11") (result i32) (i32.const 11))
-           (func $f12 (export "f12") (result i32) (i32.const 12))
-           (func $f13 (export "f13") (result i32) (i32.const 13))
-           (func $f14 (export "f14") (result i32) (i32.const 14))
-           (func $f15 (export "f15") (result i32) (i32.const 15))
-           (func (export "test") (param $n i32) (result i32)
-             (call_indirect (type 0) (local.get $n)))
-           (func (export "run") (param $offs i32) (param $len i32)
-             (table.init 0 (local.get $offs) (i32.const 0) (local.get $len))))
+  (type (func (result i32)))
+  (table 32 64 funcref)
+  (elem passive funcref $f0 $f1 $f2 $f3 $f4 $f5 $f6 $f7 $f8 $f9 $f10 $f11 $f12 $f13 $f14 $f15)
+  (func $f0 (export "f0") (result i32) (i32.const 0))
+  (func $f1 (export "f1") (result i32) (i32.const 1))
+  (func $f2 (export "f2") (result i32) (i32.const 2))
+  (func $f3 (export "f3") (result i32) (i32.const 3))
+  (func $f4 (export "f4") (result i32) (i32.const 4))
+  (func $f5 (export "f5") (result i32) (i32.const 5))
+  (func $f6 (export "f6") (result i32) (i32.const 6))
+  (func $f7 (export "f7") (result i32) (i32.const 7))
+  (func $f8 (export "f8") (result i32) (i32.const 8))
+  (func $f9 (export "f9") (result i32) (i32.const 9))
+  (func $f10 (export "f10") (result i32) (i32.const 10))
+  (func $f11 (export "f11") (result i32) (i32.const 11))
+  (func $f12 (export "f12") (result i32) (i32.const 12))
+  (func $f13 (export "f13") (result i32) (i32.const 13))
+  (func $f14 (export "f14") (result i32) (i32.const 14))
+  (func $f15 (export "f15") (result i32) (i32.const 15))
+  (func (export "test") (param $n i32) (result i32)
+    (call_indirect (type 0) (local.get $n)))
+  (func (export "run") (param $offs i32) (param $len i32)
+    (table.init 0 (local.get $offs) (i32.const 0) (local.get $len))))
 (assert_trap (invoke "run" (i32.const 24) (i32.const 16)) "out of bounds")
 (assert_return (invoke "test" (i32.const 24)) (i32.const 0))
 (assert_return (invoke "test" (i32.const 25)) (i32.const 1))
@@ -1056,30 +1046,31 @@ elem.drop 3
 (assert_trap (invoke "test" (i32.const 21)) "uninitialized element")
 (assert_trap (invoke "test" (i32.const 22)) "uninitialized element")
 (assert_trap (invoke "test" (i32.const 23)) "uninitialized element")
+
 (module
-           (type (func (result i32)))
-           (table 32 64 funcref)
-           (elem passive funcref $f0 $f1 $f2 $f3 $f4 $f5 $f6 $f7 $f8 $f9 $f10 $f11 $f12 $f13 $f14 $f15)
-           (func $f0 (export "f0") (result i32) (i32.const 0))
-           (func $f1 (export "f1") (result i32) (i32.const 1))
-           (func $f2 (export "f2") (result i32) (i32.const 2))
-           (func $f3 (export "f3") (result i32) (i32.const 3))
-           (func $f4 (export "f4") (result i32) (i32.const 4))
-           (func $f5 (export "f5") (result i32) (i32.const 5))
-           (func $f6 (export "f6") (result i32) (i32.const 6))
-           (func $f7 (export "f7") (result i32) (i32.const 7))
-           (func $f8 (export "f8") (result i32) (i32.const 8))
-           (func $f9 (export "f9") (result i32) (i32.const 9))
-           (func $f10 (export "f10") (result i32) (i32.const 10))
-           (func $f11 (export "f11") (result i32) (i32.const 11))
-           (func $f12 (export "f12") (result i32) (i32.const 12))
-           (func $f13 (export "f13") (result i32) (i32.const 13))
-           (func $f14 (export "f14") (result i32) (i32.const 14))
-           (func $f15 (export "f15") (result i32) (i32.const 15))
-           (func (export "test") (param $n i32) (result i32)
-             (call_indirect (type 0) (local.get $n)))
-           (func (export "run") (param $offs i32) (param $len i32)
-             (table.init 0 (local.get $offs) (i32.const 0) (local.get $len))))
+  (type (func (result i32)))
+  (table 32 64 funcref)
+  (elem passive funcref $f0 $f1 $f2 $f3 $f4 $f5 $f6 $f7 $f8 $f9 $f10 $f11 $f12 $f13 $f14 $f15)
+  (func $f0 (export "f0") (result i32) (i32.const 0))
+  (func $f1 (export "f1") (result i32) (i32.const 1))
+  (func $f2 (export "f2") (result i32) (i32.const 2))
+  (func $f3 (export "f3") (result i32) (i32.const 3))
+  (func $f4 (export "f4") (result i32) (i32.const 4))
+  (func $f5 (export "f5") (result i32) (i32.const 5))
+  (func $f6 (export "f6") (result i32) (i32.const 6))
+  (func $f7 (export "f7") (result i32) (i32.const 7))
+  (func $f8 (export "f8") (result i32) (i32.const 8))
+  (func $f9 (export "f9") (result i32) (i32.const 9))
+  (func $f10 (export "f10") (result i32) (i32.const 10))
+  (func $f11 (export "f11") (result i32) (i32.const 11))
+  (func $f12 (export "f12") (result i32) (i32.const 12))
+  (func $f13 (export "f13") (result i32) (i32.const 13))
+  (func $f14 (export "f14") (result i32) (i32.const 14))
+  (func $f15 (export "f15") (result i32) (i32.const 15))
+  (func (export "test") (param $n i32) (result i32)
+    (call_indirect (type 0) (local.get $n)))
+  (func (export "run") (param $offs i32) (param $len i32)
+    (table.init 0 (local.get $offs) (i32.const 0) (local.get $len))))
 (assert_trap (invoke "run" (i32.const 25) (i32.const 16)) "out of bounds")
 (assert_return (invoke "test" (i32.const 25)) (i32.const 0))
 (assert_return (invoke "test" (i32.const 26)) (i32.const 1))
@@ -1113,30 +1104,31 @@ elem.drop 3
 (assert_trap (invoke "test" (i32.const 22)) "uninitialized element")
 (assert_trap (invoke "test" (i32.const 23)) "uninitialized element")
 (assert_trap (invoke "test" (i32.const 24)) "uninitialized element")
+
 (module
-           (type (func (result i32)))
-           (table 160 320 funcref)
-           (elem passive funcref $f0 $f1 $f2 $f3 $f4 $f5 $f6 $f7 $f8 $f9 $f10 $f11 $f12 $f13 $f14 $f15)
-           (func $f0 (export "f0") (result i32) (i32.const 0))
-           (func $f1 (export "f1") (result i32) (i32.const 1))
-           (func $f2 (export "f2") (result i32) (i32.const 2))
-           (func $f3 (export "f3") (result i32) (i32.const 3))
-           (func $f4 (export "f4") (result i32) (i32.const 4))
-           (func $f5 (export "f5") (result i32) (i32.const 5))
-           (func $f6 (export "f6") (result i32) (i32.const 6))
-           (func $f7 (export "f7") (result i32) (i32.const 7))
-           (func $f8 (export "f8") (result i32) (i32.const 8))
-           (func $f9 (export "f9") (result i32) (i32.const 9))
-           (func $f10 (export "f10") (result i32) (i32.const 10))
-           (func $f11 (export "f11") (result i32) (i32.const 11))
-           (func $f12 (export "f12") (result i32) (i32.const 12))
-           (func $f13 (export "f13") (result i32) (i32.const 13))
-           (func $f14 (export "f14") (result i32) (i32.const 14))
-           (func $f15 (export "f15") (result i32) (i32.const 15))
-           (func (export "test") (param $n i32) (result i32)
-             (call_indirect (type 0) (local.get $n)))
-           (func (export "run") (param $offs i32) (param $len i32)
-             (table.init 0 (local.get $offs) (i32.const 0) (local.get $len))))
+  (type (func (result i32)))
+  (table 160 320 funcref)
+  (elem passive funcref $f0 $f1 $f2 $f3 $f4 $f5 $f6 $f7 $f8 $f9 $f10 $f11 $f12 $f13 $f14 $f15)
+  (func $f0 (export "f0") (result i32) (i32.const 0))
+  (func $f1 (export "f1") (result i32) (i32.const 1))
+  (func $f2 (export "f2") (result i32) (i32.const 2))
+  (func $f3 (export "f3") (result i32) (i32.const 3))
+  (func $f4 (export "f4") (result i32) (i32.const 4))
+  (func $f5 (export "f5") (result i32) (i32.const 5))
+  (func $f6 (export "f6") (result i32) (i32.const 6))
+  (func $f7 (export "f7") (result i32) (i32.const 7))
+  (func $f8 (export "f8") (result i32) (i32.const 8))
+  (func $f9 (export "f9") (result i32) (i32.const 9))
+  (func $f10 (export "f10") (result i32) (i32.const 10))
+  (func $f11 (export "f11") (result i32) (i32.const 11))
+  (func $f12 (export "f12") (result i32) (i32.const 12))
+  (func $f13 (export "f13") (result i32) (i32.const 13))
+  (func $f14 (export "f14") (result i32) (i32.const 14))
+  (func $f15 (export "f15") (result i32) (i32.const 15))
+  (func (export "test") (param $n i32) (result i32)
+    (call_indirect (type 0) (local.get $n)))
+  (func (export "run") (param $offs i32) (param $len i32)
+    (table.init 0 (local.get $offs) (i32.const 0) (local.get $len))))
 (assert_trap (invoke "run" (i32.const 96) (i32.const 32)) "out of bounds")
 (assert_return (invoke "test" (i32.const 96)) (i32.const 0))
 (assert_return (invoke "test" (i32.const 97)) (i32.const 1))
@@ -1298,30 +1290,31 @@ elem.drop 3
 (assert_trap (invoke "test" (i32.const 93)) "uninitialized element")
 (assert_trap (invoke "test" (i32.const 94)) "uninitialized element")
 (assert_trap (invoke "test" (i32.const 95)) "uninitialized element")
+
 (module
-           (type (func (result i32)))
-           (table 160 320 funcref)
-           (elem passive funcref $f0 $f1 $f2 $f3 $f4 $f5 $f6 $f7 $f8 $f9 $f10 $f11 $f12 $f13 $f14 $f15)
-           (func $f0 (export "f0") (result i32) (i32.const 0))
-           (func $f1 (export "f1") (result i32) (i32.const 1))
-           (func $f2 (export "f2") (result i32) (i32.const 2))
-           (func $f3 (export "f3") (result i32) (i32.const 3))
-           (func $f4 (export "f4") (result i32) (i32.const 4))
-           (func $f5 (export "f5") (result i32) (i32.const 5))
-           (func $f6 (export "f6") (result i32) (i32.const 6))
-           (func $f7 (export "f7") (result i32) (i32.const 7))
-           (func $f8 (export "f8") (result i32) (i32.const 8))
-           (func $f9 (export "f9") (result i32) (i32.const 9))
-           (func $f10 (export "f10") (result i32) (i32.const 10))
-           (func $f11 (export "f11") (result i32) (i32.const 11))
-           (func $f12 (export "f12") (result i32) (i32.const 12))
-           (func $f13 (export "f13") (result i32) (i32.const 13))
-           (func $f14 (export "f14") (result i32) (i32.const 14))
-           (func $f15 (export "f15") (result i32) (i32.const 15))
-           (func (export "test") (param $n i32) (result i32)
-             (call_indirect (type 0) (local.get $n)))
-           (func (export "run") (param $offs i32) (param $len i32)
-             (table.init 0 (local.get $offs) (i32.const 0) (local.get $len))))
+  (type (func (result i32)))
+  (table 160 320 funcref)
+  (elem passive funcref $f0 $f1 $f2 $f3 $f4 $f5 $f6 $f7 $f8 $f9 $f10 $f11 $f12 $f13 $f14 $f15)
+  (func $f0 (export "f0") (result i32) (i32.const 0))
+  (func $f1 (export "f1") (result i32) (i32.const 1))
+  (func $f2 (export "f2") (result i32) (i32.const 2))
+  (func $f3 (export "f3") (result i32) (i32.const 3))
+  (func $f4 (export "f4") (result i32) (i32.const 4))
+  (func $f5 (export "f5") (result i32) (i32.const 5))
+  (func $f6 (export "f6") (result i32) (i32.const 6))
+  (func $f7 (export "f7") (result i32) (i32.const 7))
+  (func $f8 (export "f8") (result i32) (i32.const 8))
+  (func $f9 (export "f9") (result i32) (i32.const 9))
+  (func $f10 (export "f10") (result i32) (i32.const 10))
+  (func $f11 (export "f11") (result i32) (i32.const 11))
+  (func $f12 (export "f12") (result i32) (i32.const 12))
+  (func $f13 (export "f13") (result i32) (i32.const 13))
+  (func $f14 (export "f14") (result i32) (i32.const 14))
+  (func $f15 (export "f15") (result i32) (i32.const 15))
+  (func (export "test") (param $n i32) (result i32)
+    (call_indirect (type 0) (local.get $n)))
+  (func (export "run") (param $offs i32) (param $len i32)
+    (table.init 0 (local.get $offs) (i32.const 0) (local.get $len))))
 (assert_trap (invoke "run" (i32.const 97) (i32.const 31)) "out of bounds")
 (assert_return (invoke "test" (i32.const 97)) (i32.const 0))
 (assert_return (invoke "test" (i32.const 98)) (i32.const 1))
@@ -1483,30 +1476,31 @@ elem.drop 3
 (assert_trap (invoke "test" (i32.const 94)) "uninitialized element")
 (assert_trap (invoke "test" (i32.const 95)) "uninitialized element")
 (assert_trap (invoke "test" (i32.const 96)) "uninitialized element")
+
 (module
-           (type (func (result i32)))
-           (table 64 64 funcref)
-           (elem passive funcref $f0 $f1 $f2 $f3 $f4 $f5 $f6 $f7 $f8 $f9 $f10 $f11 $f12 $f13 $f14 $f15)
-           (func $f0 (export "f0") (result i32) (i32.const 0))
-           (func $f1 (export "f1") (result i32) (i32.const 1))
-           (func $f2 (export "f2") (result i32) (i32.const 2))
-           (func $f3 (export "f3") (result i32) (i32.const 3))
-           (func $f4 (export "f4") (result i32) (i32.const 4))
-           (func $f5 (export "f5") (result i32) (i32.const 5))
-           (func $f6 (export "f6") (result i32) (i32.const 6))
-           (func $f7 (export "f7") (result i32) (i32.const 7))
-           (func $f8 (export "f8") (result i32) (i32.const 8))
-           (func $f9 (export "f9") (result i32) (i32.const 9))
-           (func $f10 (export "f10") (result i32) (i32.const 10))
-           (func $f11 (export "f11") (result i32) (i32.const 11))
-           (func $f12 (export "f12") (result i32) (i32.const 12))
-           (func $f13 (export "f13") (result i32) (i32.const 13))
-           (func $f14 (export "f14") (result i32) (i32.const 14))
-           (func $f15 (export "f15") (result i32) (i32.const 15))
-           (func (export "test") (param $n i32) (result i32)
-             (call_indirect (type 0) (local.get $n)))
-           (func (export "run") (param $offs i32) (param $len i32)
-             (table.init 0 (local.get $offs) (i32.const 0) (local.get $len))))
+  (type (func (result i32)))
+  (table 64 64 funcref)
+  (elem passive funcref $f0 $f1 $f2 $f3 $f4 $f5 $f6 $f7 $f8 $f9 $f10 $f11 $f12 $f13 $f14 $f15)
+  (func $f0 (export "f0") (result i32) (i32.const 0))
+  (func $f1 (export "f1") (result i32) (i32.const 1))
+  (func $f2 (export "f2") (result i32) (i32.const 2))
+  (func $f3 (export "f3") (result i32) (i32.const 3))
+  (func $f4 (export "f4") (result i32) (i32.const 4))
+  (func $f5 (export "f5") (result i32) (i32.const 5))
+  (func $f6 (export "f6") (result i32) (i32.const 6))
+  (func $f7 (export "f7") (result i32) (i32.const 7))
+  (func $f8 (export "f8") (result i32) (i32.const 8))
+  (func $f9 (export "f9") (result i32) (i32.const 9))
+  (func $f10 (export "f10") (result i32) (i32.const 10))
+  (func $f11 (export "f11") (result i32) (i32.const 11))
+  (func $f12 (export "f12") (result i32) (i32.const 12))
+  (func $f13 (export "f13") (result i32) (i32.const 13))
+  (func $f14 (export "f14") (result i32) (i32.const 14))
+  (func $f15 (export "f15") (result i32) (i32.const 15))
+  (func (export "test") (param $n i32) (result i32)
+    (call_indirect (type 0) (local.get $n)))
+  (func (export "run") (param $offs i32) (param $len i32)
+    (table.init 0 (local.get $offs) (i32.const 0) (local.get $len))))
 (assert_trap (invoke "run" (i32.const 48) (i32.const 4294967280)) "out of bounds")
 (assert_return (invoke "test" (i32.const 48)) (i32.const 0))
 (assert_return (invoke "test" (i32.const 49)) (i32.const 1))
@@ -1572,30 +1566,31 @@ elem.drop 3
 (assert_trap (invoke "test" (i32.const 45)) "uninitialized element")
 (assert_trap (invoke "test" (i32.const 46)) "uninitialized element")
 (assert_trap (invoke "test" (i32.const 47)) "uninitialized element")
+
 (module
-           (type (func (result i32)))
-           (table 16 16 funcref)
-           (elem passive funcref $f0 $f1 $f2 $f3 $f4 $f5 $f6 $f7 $f8 $f9 $f10 $f11 $f12 $f13 $f14 $f15)
-           (func $f0 (export "f0") (result i32) (i32.const 0))
-           (func $f1 (export "f1") (result i32) (i32.const 1))
-           (func $f2 (export "f2") (result i32) (i32.const 2))
-           (func $f3 (export "f3") (result i32) (i32.const 3))
-           (func $f4 (export "f4") (result i32) (i32.const 4))
-           (func $f5 (export "f5") (result i32) (i32.const 5))
-           (func $f6 (export "f6") (result i32) (i32.const 6))
-           (func $f7 (export "f7") (result i32) (i32.const 7))
-           (func $f8 (export "f8") (result i32) (i32.const 8))
-           (func $f9 (export "f9") (result i32) (i32.const 9))
-           (func $f10 (export "f10") (result i32) (i32.const 10))
-           (func $f11 (export "f11") (result i32) (i32.const 11))
-           (func $f12 (export "f12") (result i32) (i32.const 12))
-           (func $f13 (export "f13") (result i32) (i32.const 13))
-           (func $f14 (export "f14") (result i32) (i32.const 14))
-           (func $f15 (export "f15") (result i32) (i32.const 15))
-           (func (export "test") (param $n i32) (result i32)
-             (call_indirect (type 0) (local.get $n)))
-           (func (export "run") (param $offs i32) (param $len i32)
-             (table.init 0 (local.get $offs) (i32.const 8) (local.get $len))))
+  (type (func (result i32)))
+  (table 16 16 funcref)
+  (elem passive funcref $f0 $f1 $f2 $f3 $f4 $f5 $f6 $f7 $f8 $f9 $f10 $f11 $f12 $f13 $f14 $f15)
+  (func $f0 (export "f0") (result i32) (i32.const 0))
+  (func $f1 (export "f1") (result i32) (i32.const 1))
+  (func $f2 (export "f2") (result i32) (i32.const 2))
+  (func $f3 (export "f3") (result i32) (i32.const 3))
+  (func $f4 (export "f4") (result i32) (i32.const 4))
+  (func $f5 (export "f5") (result i32) (i32.const 5))
+  (func $f6 (export "f6") (result i32) (i32.const 6))
+  (func $f7 (export "f7") (result i32) (i32.const 7))
+  (func $f8 (export "f8") (result i32) (i32.const 8))
+  (func $f9 (export "f9") (result i32) (i32.const 9))
+  (func $f10 (export "f10") (result i32) (i32.const 10))
+  (func $f11 (export "f11") (result i32) (i32.const 11))
+  (func $f12 (export "f12") (result i32) (i32.const 12))
+  (func $f13 (export "f13") (result i32) (i32.const 13))
+  (func $f14 (export "f14") (result i32) (i32.const 14))
+  (func $f15 (export "f15") (result i32) (i32.const 15))
+  (func (export "test") (param $n i32) (result i32)
+    (call_indirect (type 0) (local.get $n)))
+  (func (export "run") (param $offs i32) (param $len i32)
+    (table.init 0 (local.get $offs) (i32.const 8) (local.get $len))))
 (assert_trap (invoke "run" (i32.const 0) (i32.const 4294967292)) "out of bounds")
 (assert_return (invoke "test" (i32.const 0)) (i32.const 8))
 (assert_return (invoke "test" (i32.const 1)) (i32.const 9))
diff --git a/test/meta/common.js b/test/meta/common.js
index 151eb4adfe..dd117b4760 100644
--- a/test/meta/common.js
+++ b/test/meta/common.js
@@ -17,15 +17,15 @@ function print_origin(origin) {
 function checkRangeCode() {
     return `
   (func (export "checkRange") (param $from i32) (param $to i32) (param $expected i32) (result i32)
-   (loop $cont
-     (if (i32.eq (local.get $from) (local.get $to))
-         (then
-           (return (i32.const -1))))
-     (if (i32.eq (i32.load8_u (local.get $from)) (local.get $expected))
-         (then
-           (local.set $from (i32.add (local.get $from) (i32.const 1)))
-           (br $cont))))
-   (return (local.get $from)))
+    (loop $cont
+      (if (i32.eq (local.get $from) (local.get $to))
+        (then
+          (return (i32.const -1))))
+      (if (i32.eq (i32.load8_u (local.get $from)) (local.get $expected))
+        (then
+          (local.set $from (i32.add (local.get $from) (i32.const 1)))
+          (br $cont))))
+    (return (local.get $from)))
 `;
 }
 
diff --git a/test/meta/generate_memory_copy.js b/test/meta/generate_memory_copy.js
index f64f0d77b6..1ccbc6545b 100644
--- a/test/meta/generate_memory_copy.js
+++ b/test/meta/generate_memory_copy.js
@@ -28,7 +28,7 @@ const e = 0;
 
 // This just gives the initial state of the memory, with its active
 // initialisers applied.
-mem_test("nop",
+mem_test("(nop)",
          [e,e,3,1,4, 1,e,e,e,e, e,e,7,5,2, 3,6,e,e,e, e,e,e,e,e, e,e,e,e,e]);
 
 // Copy non-zero over non-zero
@@ -202,8 +202,7 @@ print(
         if (ty1 == 'i32' && ty2 == 'i32' && ty3 == 'i32')
             continue;  // this is the only valid case
         print(
-`
-(assert_invalid
+`(assert_invalid
   (module
     (memory 1 1)
     (func (export "testfn")
@@ -257,8 +256,7 @@ print(
 
 // Destination wraparound the end of 32-bit offset space
 print(
-`
-(module
+`(module
   (memory 1 1)
   (func (export "test")
     (memory.copy (i32.const 0xFFFFFF00) (i32.const 0x4000) (i32.const 257))))
@@ -267,8 +265,7 @@ print(
 
 // Source range invalid
 print(
-`
-(module
+`(module
   (memory 1 1)
   (func (export "test")
     (memory.copy (i32.const 0x8000) (i32.const 0xFF00) (i32.const 257))))
@@ -277,8 +274,7 @@ print(
 
 // Source wraparound the end of 32-bit offset space
 print(
-`
-(module
+`(module
  (memory 1 1)
  (func (export "test")
    (memory.copy (i32.const 0x4000) (i32.const 0xFFFFFF00) (i32.const 257))))
@@ -287,8 +283,7 @@ print(
 
 // Zero len with both offsets in-bounds is a no-op
 print(
-`
-(module
+`(module
   (memory 1 1)
   (func (export "test")
     (memory.fill (i32.const 0x0000) (i32.const 0x55) (i32.const 0x8000))
@@ -302,8 +297,7 @@ checkRange(0x08000, 0x10000, 0xAA);
 
 // Zero len with dest offset out-of-bounds at the end of memory is allowed
 print(
-`
-(module
+`(module
   (memory 1 1)
   (func (export "test")
     (memory.copy (i32.const 0x10000) (i32.const 0x7000) (i32.const 0))))
@@ -312,8 +306,7 @@ print(
 
 // Zero len with src offset out-of-bounds at the end of memory is allowed
 print(
-`
-(module
+`(module
   (memory 1 1)
   (func (export "test")
     (memory.copy (i32.const 0x9000) (i32.const 0x10000) (i32.const 0))))
@@ -323,211 +316,210 @@ print(
 // 100 random fills followed by 100 random copies, in a single-page buffer,
 // followed by verification of the (now heavily mashed-around) buffer.
 print(
-`
-(module
-       (memory 1 1)
-       (func (export "test")
-         (memory.fill (i32.const 17767) (i32.const 1) (i32.const 1344))
-         (memory.fill (i32.const 39017) (i32.const 2) (i32.const 1055))
-         (memory.fill (i32.const 56401) (i32.const 3) (i32.const 988))
-         (memory.fill (i32.const 37962) (i32.const 4) (i32.const 322))
-         (memory.fill (i32.const 7977) (i32.const 5) (i32.const 1994))
-         (memory.fill (i32.const 22714) (i32.const 6) (i32.const 3036))
-         (memory.fill (i32.const 16882) (i32.const 7) (i32.const 2372))
-         (memory.fill (i32.const 43491) (i32.const 8) (i32.const 835))
-         (memory.fill (i32.const 124) (i32.const 9) (i32.const 1393))
-         (memory.fill (i32.const 2132) (i32.const 10) (i32.const 2758))
-         (memory.fill (i32.const 8987) (i32.const 11) (i32.const 3098))
-         (memory.fill (i32.const 52711) (i32.const 12) (i32.const 741))
-         (memory.fill (i32.const 3958) (i32.const 13) (i32.const 2823))
-         (memory.fill (i32.const 49715) (i32.const 14) (i32.const 1280))
-         (memory.fill (i32.const 50377) (i32.const 15) (i32.const 1466))
-         (memory.fill (i32.const 20493) (i32.const 16) (i32.const 3158))
-         (memory.fill (i32.const 47665) (i32.const 17) (i32.const 544))
-         (memory.fill (i32.const 12451) (i32.const 18) (i32.const 2669))
-         (memory.fill (i32.const 24869) (i32.const 19) (i32.const 2651))
-         (memory.fill (i32.const 45317) (i32.const 20) (i32.const 1570))
-         (memory.fill (i32.const 43096) (i32.const 21) (i32.const 1691))
-         (memory.fill (i32.const 33886) (i32.const 22) (i32.const 646))
-         (memory.fill (i32.const 48555) (i32.const 23) (i32.const 1858))
-         (memory.fill (i32.const 53453) (i32.const 24) (i32.const 2657))
-         (memory.fill (i32.const 30363) (i32.const 25) (i32.const 981))
-         (memory.fill (i32.const 9300) (i32.const 26) (i32.const 1807))
-         (memory.fill (i32.const 50190) (i32.const 27) (i32.const 487))
-         (memory.fill (i32.const 62753) (i32.const 28) (i32.const 530))
-         (memory.fill (i32.const 36316) (i32.const 29) (i32.const 943))
-         (memory.fill (i32.const 6768) (i32.const 30) (i32.const 381))
-         (memory.fill (i32.const 51262) (i32.const 31) (i32.const 3089))
-         (memory.fill (i32.const 49729) (i32.const 32) (i32.const 658))
-         (memory.fill (i32.const 44540) (i32.const 33) (i32.const 1702))
-         (memory.fill (i32.const 33342) (i32.const 34) (i32.const 1092))
-         (memory.fill (i32.const 50814) (i32.const 35) (i32.const 1410))
-         (memory.fill (i32.const 47594) (i32.const 36) (i32.const 2204))
-         (memory.fill (i32.const 54123) (i32.const 37) (i32.const 2394))
-         (memory.fill (i32.const 55183) (i32.const 38) (i32.const 250))
-         (memory.fill (i32.const 22620) (i32.const 39) (i32.const 2097))
-         (memory.fill (i32.const 17132) (i32.const 40) (i32.const 3264))
-         (memory.fill (i32.const 54331) (i32.const 41) (i32.const 3299))
-         (memory.fill (i32.const 39474) (i32.const 42) (i32.const 2796))
-         (memory.fill (i32.const 36156) (i32.const 43) (i32.const 2070))
-         (memory.fill (i32.const 35308) (i32.const 44) (i32.const 2763))
-         (memory.fill (i32.const 32731) (i32.const 45) (i32.const 312))
-         (memory.fill (i32.const 63746) (i32.const 46) (i32.const 192))
-         (memory.fill (i32.const 30974) (i32.const 47) (i32.const 596))
-         (memory.fill (i32.const 16635) (i32.const 48) (i32.const 501))
-         (memory.fill (i32.const 57002) (i32.const 49) (i32.const 686))
-         (memory.fill (i32.const 34299) (i32.const 50) (i32.const 385))
-         (memory.fill (i32.const 60881) (i32.const 51) (i32.const 903))
-         (memory.fill (i32.const 61445) (i32.const 52) (i32.const 2390))
-         (memory.fill (i32.const 46972) (i32.const 53) (i32.const 1441))
-         (memory.fill (i32.const 25973) (i32.const 54) (i32.const 3162))
-         (memory.fill (i32.const 5566) (i32.const 55) (i32.const 2135))
-         (memory.fill (i32.const 35977) (i32.const 56) (i32.const 519))
-         (memory.fill (i32.const 44892) (i32.const 57) (i32.const 3280))
-         (memory.fill (i32.const 46760) (i32.const 58) (i32.const 1678))
-         (memory.fill (i32.const 46607) (i32.const 59) (i32.const 3168))
-         (memory.fill (i32.const 22449) (i32.const 60) (i32.const 1441))
-         (memory.fill (i32.const 58609) (i32.const 61) (i32.const 663))
-         (memory.fill (i32.const 32261) (i32.const 62) (i32.const 1671))
-         (memory.fill (i32.const 3063) (i32.const 63) (i32.const 721))
-         (memory.fill (i32.const 34025) (i32.const 64) (i32.const 84))
-         (memory.fill (i32.const 33338) (i32.const 65) (i32.const 2029))
-         (memory.fill (i32.const 36810) (i32.const 66) (i32.const 29))
-         (memory.fill (i32.const 19147) (i32.const 67) (i32.const 3034))
-         (memory.fill (i32.const 12616) (i32.const 68) (i32.const 1043))
-         (memory.fill (i32.const 18276) (i32.const 69) (i32.const 3324))
-         (memory.fill (i32.const 4639) (i32.const 70) (i32.const 1091))
-         (memory.fill (i32.const 16158) (i32.const 71) (i32.const 1997))
-         (memory.fill (i32.const 18204) (i32.const 72) (i32.const 2259))
-         (memory.fill (i32.const 50532) (i32.const 73) (i32.const 3189))
-         (memory.fill (i32.const 11028) (i32.const 74) (i32.const 1968))
-         (memory.fill (i32.const 15962) (i32.const 75) (i32.const 1455))
-         (memory.fill (i32.const 45406) (i32.const 76) (i32.const 1177))
-         (memory.fill (i32.const 54137) (i32.const 77) (i32.const 1568))
-         (memory.fill (i32.const 33083) (i32.const 78) (i32.const 1642))
-         (memory.fill (i32.const 61028) (i32.const 79) (i32.const 3284))
-         (memory.fill (i32.const 51729) (i32.const 80) (i32.const 223))
-         (memory.fill (i32.const 4361) (i32.const 81) (i32.const 2171))
-         (memory.fill (i32.const 57514) (i32.const 82) (i32.const 1322))
-         (memory.fill (i32.const 55724) (i32.const 83) (i32.const 2648))
-         (memory.fill (i32.const 24091) (i32.const 84) (i32.const 1045))
-         (memory.fill (i32.const 43183) (i32.const 85) (i32.const 3097))
-         (memory.fill (i32.const 32307) (i32.const 86) (i32.const 2796))
-         (memory.fill (i32.const 3811) (i32.const 87) (i32.const 2010))
-         (memory.fill (i32.const 54856) (i32.const 88) (i32.const 0))
-         (memory.fill (i32.const 49941) (i32.const 89) (i32.const 2069))
-         (memory.fill (i32.const 20411) (i32.const 90) (i32.const 2896))
-         (memory.fill (i32.const 33826) (i32.const 91) (i32.const 192))
-         (memory.fill (i32.const 9402) (i32.const 92) (i32.const 2195))
-         (memory.fill (i32.const 12413) (i32.const 93) (i32.const 24))
-         (memory.fill (i32.const 14091) (i32.const 94) (i32.const 577))
-         (memory.fill (i32.const 44058) (i32.const 95) (i32.const 2089))
-         (memory.fill (i32.const 36735) (i32.const 96) (i32.const 3436))
-         (memory.fill (i32.const 23288) (i32.const 97) (i32.const 2765))
-         (memory.fill (i32.const 6392) (i32.const 98) (i32.const 830))
-         (memory.fill (i32.const 33307) (i32.const 99) (i32.const 1938))
-         (memory.fill (i32.const 21941) (i32.const 100) (i32.const 2750))
-         (memory.copy (i32.const 59214) (i32.const 54248) (i32.const 2098))
-         (memory.copy (i32.const 63026) (i32.const 39224) (i32.const 230))
-         (memory.copy (i32.const 51833) (i32.const 23629) (i32.const 2300))
-         (memory.copy (i32.const 6708) (i32.const 23996) (i32.const 639))
-         (memory.copy (i32.const 6990) (i32.const 33399) (i32.const 1097))
-         (memory.copy (i32.const 19403) (i32.const 10348) (i32.const 3197))
-         (memory.copy (i32.const 27308) (i32.const 54406) (i32.const 100))
-         (memory.copy (i32.const 27221) (i32.const 43682) (i32.const 1717))
-         (memory.copy (i32.const 60528) (i32.const 8629) (i32.const 119))
-         (memory.copy (i32.const 5947) (i32.const 2308) (i32.const 658))
-         (memory.copy (i32.const 4787) (i32.const 51631) (i32.const 2269))
-         (memory.copy (i32.const 12617) (i32.const 19197) (i32.const 833))
-         (memory.copy (i32.const 11854) (i32.const 46505) (i32.const 3300))
-         (memory.copy (i32.const 11376) (i32.const 45012) (i32.const 2281))
-         (memory.copy (i32.const 34186) (i32.const 6697) (i32.const 2572))
-         (memory.copy (i32.const 4936) (i32.const 1690) (i32.const 1328))
-         (memory.copy (i32.const 63164) (i32.const 7637) (i32.const 1670))
-         (memory.copy (i32.const 44568) (i32.const 18344) (i32.const 33))
-         (memory.copy (i32.const 43918) (i32.const 22348) (i32.const 1427))
-         (memory.copy (i32.const 46637) (i32.const 49819) (i32.const 1434))
-         (memory.copy (i32.const 63684) (i32.const 8755) (i32.const 834))
-         (memory.copy (i32.const 33485) (i32.const 20131) (i32.const 3317))
-         (memory.copy (i32.const 40575) (i32.const 54317) (i32.const 3201))
-         (memory.copy (i32.const 25812) (i32.const 59254) (i32.const 2452))
-         (memory.copy (i32.const 19678) (i32.const 56882) (i32.const 346))
-         (memory.copy (i32.const 15852) (i32.const 35914) (i32.const 2430))
-         (memory.copy (i32.const 11824) (i32.const 35574) (i32.const 300))
-         (memory.copy (i32.const 59427) (i32.const 13957) (i32.const 3153))
-         (memory.copy (i32.const 34299) (i32.const 60594) (i32.const 1281))
-         (memory.copy (i32.const 8964) (i32.const 12276) (i32.const 943))
-         (memory.copy (i32.const 2827) (i32.const 10425) (i32.const 1887))
-         (memory.copy (i32.const 43194) (i32.const 43910) (i32.const 738))
-         (memory.copy (i32.const 63038) (i32.const 18949) (i32.const 122))
-         (memory.copy (i32.const 24044) (i32.const 44761) (i32.const 1755))
-         (memory.copy (i32.const 22608) (i32.const 14755) (i32.const 702))
-         (memory.copy (i32.const 11284) (i32.const 26579) (i32.const 1830))
-         (memory.copy (i32.const 23092) (i32.const 20471) (i32.const 1064))
-         (memory.copy (i32.const 57248) (i32.const 54770) (i32.const 2631))
-         (memory.copy (i32.const 25492) (i32.const 1025) (i32.const 3113))
-         (memory.copy (i32.const 49588) (i32.const 44220) (i32.const 975))
-         (memory.copy (i32.const 28280) (i32.const 41722) (i32.const 2336))
-         (memory.copy (i32.const 61289) (i32.const 230) (i32.const 2872))
-         (memory.copy (i32.const 22480) (i32.const 52506) (i32.const 2197))
-         (memory.copy (i32.const 40553) (i32.const 9578) (i32.const 1958))
-         (memory.copy (i32.const 29004) (i32.const 20862) (i32.const 2186))
-         (memory.copy (i32.const 53029) (i32.const 43955) (i32.const 1037))
-         (memory.copy (i32.const 25476) (i32.const 35667) (i32.const 1650))
-         (memory.copy (i32.const 58516) (i32.const 45819) (i32.const 1986))
-         (memory.copy (i32.const 38297) (i32.const 5776) (i32.const 1955))
-         (memory.copy (i32.const 28503) (i32.const 55364) (i32.const 2368))
-         (memory.copy (i32.const 62619) (i32.const 18108) (i32.const 1356))
-         (memory.copy (i32.const 50149) (i32.const 13861) (i32.const 382))
-         (memory.copy (i32.const 16904) (i32.const 36341) (i32.const 1900))
-         (memory.copy (i32.const 48098) (i32.const 11358) (i32.const 2807))
-         (memory.copy (i32.const 28512) (i32.const 40362) (i32.const 323))
-         (memory.copy (i32.const 35506) (i32.const 27856) (i32.const 1670))
-         (memory.copy (i32.const 62970) (i32.const 53332) (i32.const 1341))
-         (memory.copy (i32.const 14133) (i32.const 46312) (i32.const 644))
-         (memory.copy (i32.const 29030) (i32.const 19074) (i32.const 496))
-         (memory.copy (i32.const 44952) (i32.const 47577) (i32.const 2784))
-         (memory.copy (i32.const 39559) (i32.const 44661) (i32.const 1350))
-         (memory.copy (i32.const 10352) (i32.const 29274) (i32.const 1475))
-         (memory.copy (i32.const 46911) (i32.const 46178) (i32.const 1467))
-         (memory.copy (i32.const 4905) (i32.const 28740) (i32.const 1895))
-         (memory.copy (i32.const 38012) (i32.const 57253) (i32.const 1751))
-         (memory.copy (i32.const 26446) (i32.const 27223) (i32.const 1127))
-         (memory.copy (i32.const 58835) (i32.const 24657) (i32.const 1063))
-         (memory.copy (i32.const 61356) (i32.const 38790) (i32.const 766))
-         (memory.copy (i32.const 44160) (i32.const 2284) (i32.const 1520))
-         (memory.copy (i32.const 32740) (i32.const 47237) (i32.const 3014))
-         (memory.copy (i32.const 11148) (i32.const 21260) (i32.const 1011))
-         (memory.copy (i32.const 7665) (i32.const 31612) (i32.const 3034))
-         (memory.copy (i32.const 18044) (i32.const 12987) (i32.const 3320))
-         (memory.copy (i32.const 57306) (i32.const 55905) (i32.const 308))
-         (memory.copy (i32.const 24675) (i32.const 16815) (i32.const 1155))
-         (memory.copy (i32.const 19900) (i32.const 10115) (i32.const 722))
-         (memory.copy (i32.const 2921) (i32.const 5935) (i32.const 2370))
-         (memory.copy (i32.const 32255) (i32.const 50095) (i32.const 2926))
-         (memory.copy (i32.const 15126) (i32.const 17299) (i32.const 2607))
-         (memory.copy (i32.const 45575) (i32.const 28447) (i32.const 2045))
-         (memory.copy (i32.const 55149) (i32.const 36113) (i32.const 2596))
-         (memory.copy (i32.const 28461) (i32.const 54157) (i32.const 1168))
-         (memory.copy (i32.const 47951) (i32.const 53385) (i32.const 3137))
-         (memory.copy (i32.const 30646) (i32.const 45155) (i32.const 2649))
-         (memory.copy (i32.const 5057) (i32.const 4295) (i32.const 52))
-         (memory.copy (i32.const 6692) (i32.const 24195) (i32.const 441))
-         (memory.copy (i32.const 32984) (i32.const 27117) (i32.const 3445))
-         (memory.copy (i32.const 32530) (i32.const 59372) (i32.const 2785))
-         (memory.copy (i32.const 34361) (i32.const 8962) (i32.const 2406))
-         (memory.copy (i32.const 17893) (i32.const 54538) (i32.const 3381))
-         (memory.copy (i32.const 22685) (i32.const 44151) (i32.const 136))
-         (memory.copy (i32.const 59089) (i32.const 7077) (i32.const 1045))
-         (memory.copy (i32.const 42945) (i32.const 55028) (i32.const 2389))
-         (memory.copy (i32.const 44693) (i32.const 20138) (i32.const 877))
-         (memory.copy (i32.const 36810) (i32.const 25196) (i32.const 3447))
-         (memory.copy (i32.const 45742) (i32.const 31888) (i32.const 854))
-         (memory.copy (i32.const 24236) (i32.const 31866) (i32.const 1377))
-         (memory.copy (i32.const 33778) (i32.const 692) (i32.const 1594))
-         (memory.copy (i32.const 60618) (i32.const 18585) (i32.const 2987))
-         (memory.copy (i32.const 50370) (i32.const 41271) (i32.const 1406))
-       )
+`(module
+  (memory 1 1)
+  (func (export "test")
+    (memory.fill (i32.const 17767) (i32.const 1) (i32.const 1344))
+    (memory.fill (i32.const 39017) (i32.const 2) (i32.const 1055))
+    (memory.fill (i32.const 56401) (i32.const 3) (i32.const 988))
+    (memory.fill (i32.const 37962) (i32.const 4) (i32.const 322))
+    (memory.fill (i32.const 7977) (i32.const 5) (i32.const 1994))
+    (memory.fill (i32.const 22714) (i32.const 6) (i32.const 3036))
+    (memory.fill (i32.const 16882) (i32.const 7) (i32.const 2372))
+    (memory.fill (i32.const 43491) (i32.const 8) (i32.const 835))
+    (memory.fill (i32.const 124) (i32.const 9) (i32.const 1393))
+    (memory.fill (i32.const 2132) (i32.const 10) (i32.const 2758))
+    (memory.fill (i32.const 8987) (i32.const 11) (i32.const 3098))
+    (memory.fill (i32.const 52711) (i32.const 12) (i32.const 741))
+    (memory.fill (i32.const 3958) (i32.const 13) (i32.const 2823))
+    (memory.fill (i32.const 49715) (i32.const 14) (i32.const 1280))
+    (memory.fill (i32.const 50377) (i32.const 15) (i32.const 1466))
+    (memory.fill (i32.const 20493) (i32.const 16) (i32.const 3158))
+    (memory.fill (i32.const 47665) (i32.const 17) (i32.const 544))
+    (memory.fill (i32.const 12451) (i32.const 18) (i32.const 2669))
+    (memory.fill (i32.const 24869) (i32.const 19) (i32.const 2651))
+    (memory.fill (i32.const 45317) (i32.const 20) (i32.const 1570))
+    (memory.fill (i32.const 43096) (i32.const 21) (i32.const 1691))
+    (memory.fill (i32.const 33886) (i32.const 22) (i32.const 646))
+    (memory.fill (i32.const 48555) (i32.const 23) (i32.const 1858))
+    (memory.fill (i32.const 53453) (i32.const 24) (i32.const 2657))
+    (memory.fill (i32.const 30363) (i32.const 25) (i32.const 981))
+    (memory.fill (i32.const 9300) (i32.const 26) (i32.const 1807))
+    (memory.fill (i32.const 50190) (i32.const 27) (i32.const 487))
+    (memory.fill (i32.const 62753) (i32.const 28) (i32.const 530))
+    (memory.fill (i32.const 36316) (i32.const 29) (i32.const 943))
+    (memory.fill (i32.const 6768) (i32.const 30) (i32.const 381))
+    (memory.fill (i32.const 51262) (i32.const 31) (i32.const 3089))
+    (memory.fill (i32.const 49729) (i32.const 32) (i32.const 658))
+    (memory.fill (i32.const 44540) (i32.const 33) (i32.const 1702))
+    (memory.fill (i32.const 33342) (i32.const 34) (i32.const 1092))
+    (memory.fill (i32.const 50814) (i32.const 35) (i32.const 1410))
+    (memory.fill (i32.const 47594) (i32.const 36) (i32.const 2204))
+    (memory.fill (i32.const 54123) (i32.const 37) (i32.const 2394))
+    (memory.fill (i32.const 55183) (i32.const 38) (i32.const 250))
+    (memory.fill (i32.const 22620) (i32.const 39) (i32.const 2097))
+    (memory.fill (i32.const 17132) (i32.const 40) (i32.const 3264))
+    (memory.fill (i32.const 54331) (i32.const 41) (i32.const 3299))
+    (memory.fill (i32.const 39474) (i32.const 42) (i32.const 2796))
+    (memory.fill (i32.const 36156) (i32.const 43) (i32.const 2070))
+    (memory.fill (i32.const 35308) (i32.const 44) (i32.const 2763))
+    (memory.fill (i32.const 32731) (i32.const 45) (i32.const 312))
+    (memory.fill (i32.const 63746) (i32.const 46) (i32.const 192))
+    (memory.fill (i32.const 30974) (i32.const 47) (i32.const 596))
+    (memory.fill (i32.const 16635) (i32.const 48) (i32.const 501))
+    (memory.fill (i32.const 57002) (i32.const 49) (i32.const 686))
+    (memory.fill (i32.const 34299) (i32.const 50) (i32.const 385))
+    (memory.fill (i32.const 60881) (i32.const 51) (i32.const 903))
+    (memory.fill (i32.const 61445) (i32.const 52) (i32.const 2390))
+    (memory.fill (i32.const 46972) (i32.const 53) (i32.const 1441))
+    (memory.fill (i32.const 25973) (i32.const 54) (i32.const 3162))
+    (memory.fill (i32.const 5566) (i32.const 55) (i32.const 2135))
+    (memory.fill (i32.const 35977) (i32.const 56) (i32.const 519))
+    (memory.fill (i32.const 44892) (i32.const 57) (i32.const 3280))
+    (memory.fill (i32.const 46760) (i32.const 58) (i32.const 1678))
+    (memory.fill (i32.const 46607) (i32.const 59) (i32.const 3168))
+    (memory.fill (i32.const 22449) (i32.const 60) (i32.const 1441))
+    (memory.fill (i32.const 58609) (i32.const 61) (i32.const 663))
+    (memory.fill (i32.const 32261) (i32.const 62) (i32.const 1671))
+    (memory.fill (i32.const 3063) (i32.const 63) (i32.const 721))
+    (memory.fill (i32.const 34025) (i32.const 64) (i32.const 84))
+    (memory.fill (i32.const 33338) (i32.const 65) (i32.const 2029))
+    (memory.fill (i32.const 36810) (i32.const 66) (i32.const 29))
+    (memory.fill (i32.const 19147) (i32.const 67) (i32.const 3034))
+    (memory.fill (i32.const 12616) (i32.const 68) (i32.const 1043))
+    (memory.fill (i32.const 18276) (i32.const 69) (i32.const 3324))
+    (memory.fill (i32.const 4639) (i32.const 70) (i32.const 1091))
+    (memory.fill (i32.const 16158) (i32.const 71) (i32.const 1997))
+    (memory.fill (i32.const 18204) (i32.const 72) (i32.const 2259))
+    (memory.fill (i32.const 50532) (i32.const 73) (i32.const 3189))
+    (memory.fill (i32.const 11028) (i32.const 74) (i32.const 1968))
+    (memory.fill (i32.const 15962) (i32.const 75) (i32.const 1455))
+    (memory.fill (i32.const 45406) (i32.const 76) (i32.const 1177))
+    (memory.fill (i32.const 54137) (i32.const 77) (i32.const 1568))
+    (memory.fill (i32.const 33083) (i32.const 78) (i32.const 1642))
+    (memory.fill (i32.const 61028) (i32.const 79) (i32.const 3284))
+    (memory.fill (i32.const 51729) (i32.const 80) (i32.const 223))
+    (memory.fill (i32.const 4361) (i32.const 81) (i32.const 2171))
+    (memory.fill (i32.const 57514) (i32.const 82) (i32.const 1322))
+    (memory.fill (i32.const 55724) (i32.const 83) (i32.const 2648))
+    (memory.fill (i32.const 24091) (i32.const 84) (i32.const 1045))
+    (memory.fill (i32.const 43183) (i32.const 85) (i32.const 3097))
+    (memory.fill (i32.const 32307) (i32.const 86) (i32.const 2796))
+    (memory.fill (i32.const 3811) (i32.const 87) (i32.const 2010))
+    (memory.fill (i32.const 54856) (i32.const 88) (i32.const 0))
+    (memory.fill (i32.const 49941) (i32.const 89) (i32.const 2069))
+    (memory.fill (i32.const 20411) (i32.const 90) (i32.const 2896))
+    (memory.fill (i32.const 33826) (i32.const 91) (i32.const 192))
+    (memory.fill (i32.const 9402) (i32.const 92) (i32.const 2195))
+    (memory.fill (i32.const 12413) (i32.const 93) (i32.const 24))
+    (memory.fill (i32.const 14091) (i32.const 94) (i32.const 577))
+    (memory.fill (i32.const 44058) (i32.const 95) (i32.const 2089))
+    (memory.fill (i32.const 36735) (i32.const 96) (i32.const 3436))
+    (memory.fill (i32.const 23288) (i32.const 97) (i32.const 2765))
+    (memory.fill (i32.const 6392) (i32.const 98) (i32.const 830))
+    (memory.fill (i32.const 33307) (i32.const 99) (i32.const 1938))
+    (memory.fill (i32.const 21941) (i32.const 100) (i32.const 2750))
+    (memory.copy (i32.const 59214) (i32.const 54248) (i32.const 2098))
+    (memory.copy (i32.const 63026) (i32.const 39224) (i32.const 230))
+    (memory.copy (i32.const 51833) (i32.const 23629) (i32.const 2300))
+    (memory.copy (i32.const 6708) (i32.const 23996) (i32.const 639))
+    (memory.copy (i32.const 6990) (i32.const 33399) (i32.const 1097))
+    (memory.copy (i32.const 19403) (i32.const 10348) (i32.const 3197))
+    (memory.copy (i32.const 27308) (i32.const 54406) (i32.const 100))
+    (memory.copy (i32.const 27221) (i32.const 43682) (i32.const 1717))
+    (memory.copy (i32.const 60528) (i32.const 8629) (i32.const 119))
+    (memory.copy (i32.const 5947) (i32.const 2308) (i32.const 658))
+    (memory.copy (i32.const 4787) (i32.const 51631) (i32.const 2269))
+    (memory.copy (i32.const 12617) (i32.const 19197) (i32.const 833))
+    (memory.copy (i32.const 11854) (i32.const 46505) (i32.const 3300))
+    (memory.copy (i32.const 11376) (i32.const 45012) (i32.const 2281))
+    (memory.copy (i32.const 34186) (i32.const 6697) (i32.const 2572))
+    (memory.copy (i32.const 4936) (i32.const 1690) (i32.const 1328))
+    (memory.copy (i32.const 63164) (i32.const 7637) (i32.const 1670))
+    (memory.copy (i32.const 44568) (i32.const 18344) (i32.const 33))
+    (memory.copy (i32.const 43918) (i32.const 22348) (i32.const 1427))
+    (memory.copy (i32.const 46637) (i32.const 49819) (i32.const 1434))
+    (memory.copy (i32.const 63684) (i32.const 8755) (i32.const 834))
+    (memory.copy (i32.const 33485) (i32.const 20131) (i32.const 3317))
+    (memory.copy (i32.const 40575) (i32.const 54317) (i32.const 3201))
+    (memory.copy (i32.const 25812) (i32.const 59254) (i32.const 2452))
+    (memory.copy (i32.const 19678) (i32.const 56882) (i32.const 346))
+    (memory.copy (i32.const 15852) (i32.const 35914) (i32.const 2430))
+    (memory.copy (i32.const 11824) (i32.const 35574) (i32.const 300))
+    (memory.copy (i32.const 59427) (i32.const 13957) (i32.const 3153))
+    (memory.copy (i32.const 34299) (i32.const 60594) (i32.const 1281))
+    (memory.copy (i32.const 8964) (i32.const 12276) (i32.const 943))
+    (memory.copy (i32.const 2827) (i32.const 10425) (i32.const 1887))
+    (memory.copy (i32.const 43194) (i32.const 43910) (i32.const 738))
+    (memory.copy (i32.const 63038) (i32.const 18949) (i32.const 122))
+    (memory.copy (i32.const 24044) (i32.const 44761) (i32.const 1755))
+    (memory.copy (i32.const 22608) (i32.const 14755) (i32.const 702))
+    (memory.copy (i32.const 11284) (i32.const 26579) (i32.const 1830))
+    (memory.copy (i32.const 23092) (i32.const 20471) (i32.const 1064))
+    (memory.copy (i32.const 57248) (i32.const 54770) (i32.const 2631))
+    (memory.copy (i32.const 25492) (i32.const 1025) (i32.const 3113))
+    (memory.copy (i32.const 49588) (i32.const 44220) (i32.const 975))
+    (memory.copy (i32.const 28280) (i32.const 41722) (i32.const 2336))
+    (memory.copy (i32.const 61289) (i32.const 230) (i32.const 2872))
+    (memory.copy (i32.const 22480) (i32.const 52506) (i32.const 2197))
+    (memory.copy (i32.const 40553) (i32.const 9578) (i32.const 1958))
+    (memory.copy (i32.const 29004) (i32.const 20862) (i32.const 2186))
+    (memory.copy (i32.const 53029) (i32.const 43955) (i32.const 1037))
+    (memory.copy (i32.const 25476) (i32.const 35667) (i32.const 1650))
+    (memory.copy (i32.const 58516) (i32.const 45819) (i32.const 1986))
+    (memory.copy (i32.const 38297) (i32.const 5776) (i32.const 1955))
+    (memory.copy (i32.const 28503) (i32.const 55364) (i32.const 2368))
+    (memory.copy (i32.const 62619) (i32.const 18108) (i32.const 1356))
+    (memory.copy (i32.const 50149) (i32.const 13861) (i32.const 382))
+    (memory.copy (i32.const 16904) (i32.const 36341) (i32.const 1900))
+    (memory.copy (i32.const 48098) (i32.const 11358) (i32.const 2807))
+    (memory.copy (i32.const 28512) (i32.const 40362) (i32.const 323))
+    (memory.copy (i32.const 35506) (i32.const 27856) (i32.const 1670))
+    (memory.copy (i32.const 62970) (i32.const 53332) (i32.const 1341))
+    (memory.copy (i32.const 14133) (i32.const 46312) (i32.const 644))
+    (memory.copy (i32.const 29030) (i32.const 19074) (i32.const 496))
+    (memory.copy (i32.const 44952) (i32.const 47577) (i32.const 2784))
+    (memory.copy (i32.const 39559) (i32.const 44661) (i32.const 1350))
+    (memory.copy (i32.const 10352) (i32.const 29274) (i32.const 1475))
+    (memory.copy (i32.const 46911) (i32.const 46178) (i32.const 1467))
+    (memory.copy (i32.const 4905) (i32.const 28740) (i32.const 1895))
+    (memory.copy (i32.const 38012) (i32.const 57253) (i32.const 1751))
+    (memory.copy (i32.const 26446) (i32.const 27223) (i32.const 1127))
+    (memory.copy (i32.const 58835) (i32.const 24657) (i32.const 1063))
+    (memory.copy (i32.const 61356) (i32.const 38790) (i32.const 766))
+    (memory.copy (i32.const 44160) (i32.const 2284) (i32.const 1520))
+    (memory.copy (i32.const 32740) (i32.const 47237) (i32.const 3014))
+    (memory.copy (i32.const 11148) (i32.const 21260) (i32.const 1011))
+    (memory.copy (i32.const 7665) (i32.const 31612) (i32.const 3034))
+    (memory.copy (i32.const 18044) (i32.const 12987) (i32.const 3320))
+    (memory.copy (i32.const 57306) (i32.const 55905) (i32.const 308))
+    (memory.copy (i32.const 24675) (i32.const 16815) (i32.const 1155))
+    (memory.copy (i32.const 19900) (i32.const 10115) (i32.const 722))
+    (memory.copy (i32.const 2921) (i32.const 5935) (i32.const 2370))
+    (memory.copy (i32.const 32255) (i32.const 50095) (i32.const 2926))
+    (memory.copy (i32.const 15126) (i32.const 17299) (i32.const 2607))
+    (memory.copy (i32.const 45575) (i32.const 28447) (i32.const 2045))
+    (memory.copy (i32.const 55149) (i32.const 36113) (i32.const 2596))
+    (memory.copy (i32.const 28461) (i32.const 54157) (i32.const 1168))
+    (memory.copy (i32.const 47951) (i32.const 53385) (i32.const 3137))
+    (memory.copy (i32.const 30646) (i32.const 45155) (i32.const 2649))
+    (memory.copy (i32.const 5057) (i32.const 4295) (i32.const 52))
+    (memory.copy (i32.const 6692) (i32.const 24195) (i32.const 441))
+    (memory.copy (i32.const 32984) (i32.const 27117) (i32.const 3445))
+    (memory.copy (i32.const 32530) (i32.const 59372) (i32.const 2785))
+    (memory.copy (i32.const 34361) (i32.const 8962) (i32.const 2406))
+    (memory.copy (i32.const 17893) (i32.const 54538) (i32.const 3381))
+    (memory.copy (i32.const 22685) (i32.const 44151) (i32.const 136))
+    (memory.copy (i32.const 59089) (i32.const 7077) (i32.const 1045))
+    (memory.copy (i32.const 42945) (i32.const 55028) (i32.const 2389))
+    (memory.copy (i32.const 44693) (i32.const 20138) (i32.const 877))
+    (memory.copy (i32.const 36810) (i32.const 25196) (i32.const 3447))
+    (memory.copy (i32.const 45742) (i32.const 31888) (i32.const 854))
+    (memory.copy (i32.const 24236) (i32.const 31866) (i32.const 1377))
+    (memory.copy (i32.const 33778) (i32.const 692) (i32.const 1594))
+    (memory.copy (i32.const 60618) (i32.const 18585) (i32.const 2987))
+    (memory.copy (i32.const 50370) (i32.const 41271) (i32.const 1406))
+  )
   ${checkRangeCode()})
 (invoke "test")
 `);
diff --git a/test/meta/generate_memory_fill.js b/test/meta/generate_memory_fill.js
index 255b2d28cc..9ba90b2869 100644
--- a/test/meta/generate_memory_fill.js
+++ b/test/meta/generate_memory_fill.js
@@ -3,8 +3,8 @@
 
 print_origin("generate_memory_fill.js");
 
-let PREAMBLE = `
-  (memory 1 1)
+let PREAMBLE =
+  `(memory 1 1)
   ${checkRangeCode()}`;
 
 // Range valid
@@ -21,8 +21,7 @@ checkRange(0x0FF00, 0x10000, 0x55)
 
 // Range invalid
 print(
-`
-(module
+`(module
   ${PREAMBLE}
   (func (export "test")
     (memory.fill (i32.const 0xFF00) (i32.const 0x55) (i32.const 257))))
@@ -31,8 +30,7 @@ print(
 
 // Wraparound the end of 32-bit offset space
 print(
-`
-(module
+`(module
   ${PREAMBLE}
   (func (export "test")
     (memory.fill (i32.const 0xFFFFFF00) (i32.const 0x55) (i32.const 257))))
@@ -41,8 +39,7 @@ print(
 
 // Zero len with offset in-bounds is a no-op
 print(
-`
-(module
+`(module
   ${PREAMBLE}
   (func (export "test")
     (memory.fill (i32.const 0x12) (i32.const 0x55) (i32.const 0))))
@@ -52,8 +49,7 @@ checkRange(0x00000, 0x10000, 0x00);
 
 // Zero len with offset out-of-bounds at the end of memory is allowed
 print(
-`
-(module
+`(module
   ${PREAMBLE}
   (func (export "test")
     (memory.fill (i32.const 0x10000) (i32.const 0x55) (i32.const 0))))
@@ -62,8 +58,7 @@ print(
 
 // Very large range
 print(
-`
-(module
+`(module
   ${PREAMBLE}
   (func (export "test")
     (memory.fill (i32.const 0x1) (i32.const 0xAA) (i32.const 0xFFFE))))
@@ -93,8 +88,7 @@ checkRange(0x12+10, 0x10000, 0x00);
 
 // Module doesn't have a memory.
 print(
-`
-(assert_invalid
+`(assert_invalid
   (module
     (func (export "testfn")
       (memory.fill (i32.const 10) (i32.const 20) (i32.const 30))))
@@ -110,8 +104,7 @@ print(
         if (ty1 == 'i32' && ty2 == 'i32' && ty3 == 'i32')
             continue;  // this is the only valid case
         print(
-`
-(assert_invalid
+`(assert_invalid
   (module
     (memory 1 1)
     (func (export "testfn")
diff --git a/test/meta/generate_memory_init.js b/test/meta/generate_memory_init.js
index 095e53f415..a2e47315ee 100644
--- a/test/meta/generate_memory_init.js
+++ b/test/meta/generate_memory_init.js
@@ -30,7 +30,7 @@ const e = 0;
 
 // This just gives the initial state of the memory, with its active
 // initialisers applied.
-mem_test("nop",
+mem_test("(nop)",
          [e,e,3,1,4, 1,e,e,e,e, e,e,7,5,2, 3,6,e,e,e, e,e,e,e,e, e,e,e,e,e]);
 
 // Passive init that overwrites all-zero entries
@@ -42,22 +42,22 @@ mem_test("(memory.init 3 (i32.const 15) (i32.const 1) (i32.const 3))",
          [e,e,3,1,4, 1,e,e,e,e, e,e,7,5,2, 9,2,7,e,e, e,e,e,e,e, e,e,e,e,e]);
 
 // Perform active and passive initialisation and then multiple copies
-mem_test("(memory.init 1 (i32.const 7) (i32.const 0) (i32.const 4)) \n" +
-         "data.drop 1 \n" +
-         "(memory.init 3 (i32.const 15) (i32.const 1) (i32.const 3)) \n" +
-         "data.drop 3 \n" +
-         "(memory.copy (i32.const 20) (i32.const 15) (i32.const 5)) \n" +
-         "(memory.copy (i32.const 21) (i32.const 29) (i32.const 1)) \n" +
-         "(memory.copy (i32.const 24) (i32.const 10) (i32.const 1)) \n" +
-         "(memory.copy (i32.const 13) (i32.const 11) (i32.const 4)) \n" +
-         "(memory.copy (i32.const 19) (i32.const 20) (i32.const 5))",
+mem_test(`(memory.init 1 (i32.const 7) (i32.const 0) (i32.const 4))
+    (data.drop 1)
+    (memory.init 3 (i32.const 15) (i32.const 1) (i32.const 3))
+    (data.drop 3)
+    (memory.copy (i32.const 20) (i32.const 15) (i32.const 5))
+    (memory.copy (i32.const 21) (i32.const 29) (i32.const 1))
+    (memory.copy (i32.const 24) (i32.const 10) (i32.const 1))
+    (memory.copy (i32.const 13) (i32.const 11) (i32.const 4))
+    (memory.copy (i32.const 19) (i32.const 20) (i32.const 5))`,
          [e,e,3,1,4, 1,e,2,7,1, 8,e,7,e,7, 5,2,7,e,9, e,7,e,8,8, e,e,e,e,e]);
 
 // Miscellaneous
 
 let PREAMBLE =
     `(memory 1)
-     (data passive "\\37")`;
+    (data passive "\\37")`;
 
 // drop with no memory
 print(
@@ -193,11 +193,11 @@ print(
             continue;  // this is the only valid case
         print(
 `(assert_invalid
-   (module
-     ${PREAMBLE}
-     (func (export "test")
-       (memory.init 0 (${ty1}.const 1) (${ty2}.const 1) (${ty3}.const 1))))
-   "type mismatch")
+  (module
+    ${PREAMBLE}
+    (func (export "test")
+      (memory.init 0 (${ty1}.const 1) (${ty2}.const 1) (${ty3}.const 1))))
+  "type mismatch")
 `);
     }}}
 }
@@ -214,11 +214,11 @@ const mem_init_len = 16;
 function mem_init(min, max, shared, backup, write) {
     print(
 `(module
-   (memory ${min} ${max} ${shared})
-   (data passive "\\42\\42\\42\\42\\42\\42\\42\\42\\42\\42\\42\\42\\42\\42\\42\\42")
+  (memory ${min} ${max} ${shared})
+  (data passive "\\42\\42\\42\\42\\42\\42\\42\\42\\42\\42\\42\\42\\42\\42\\42\\42")
    ${checkRangeCode()}
-   (func (export "run") (param $offs i32) (param $len i32)
-     (memory.init 0 (local.get $offs) (i32.const 0) (local.get $len))))
+  (func (export "run") (param $offs i32) (param $len i32)
+    (memory.init 0 (local.get $offs) (i32.const 0) (local.get $len))))
 `);
     // A fill writing past the end of the memory should throw *and* have filled
     // all the way up to the end.
diff --git a/test/meta/generate_table_copy.js b/test/meta/generate_table_copy.js
index 743bed8e61..b8d1af8068 100644
--- a/test/meta/generate_table_copy.js
+++ b/test/meta/generate_table_copy.js
@@ -15,8 +15,7 @@ function emit_a() {
   (func (export "ef3") (result i32) (i32.const 3))
   (func (export "ef4") (result i32) (i32.const 4))
 )
-(register "a")
-`);
+(register "a")`);
 }
 
 // ... and this one imports those 5 functions.  It adds 5 of its own, creates a
@@ -81,7 +80,7 @@ let e = undefined;
 
 // This just gives the initial state of the table, with its active
 // initialisers applied
-tab_test("nop",
+tab_test("(nop)",
          [e,e,3,1,4, 1,e,e,e,e, e,e,7,5,2, 3,6,e,e,e, e,e,e,e,e, e,e,e,e,e]);
 
 // Copy non-null over non-null
@@ -221,41 +220,43 @@ function tbl_copy(min, max, srcOffs, targetOffs, len, copyDown=false) {
     let srcLim = srcOffs + Math.min(len, targetAvail, srcAvail);
 
     print(
-        `(module
-           (type (func (result i32)))
-           (table ${min} ${max} funcref)
-           (elem (i32.const ${srcOffs})
-                 ${(function () {
-                        var s = "";
-                        for (let i=srcOffs, j=0; i < srcLim; i++, j++)
-                            s += " $f" + j;
-                        return s;
-                     })()})
-           (func $f0 (export "f0") (result i32) (i32.const 0))
-           (func $f1 (export "f1") (result i32) (i32.const 1))
-           (func $f2 (export "f2") (result i32) (i32.const 2))
-           (func $f3 (export "f3") (result i32) (i32.const 3))
-           (func $f4 (export "f4") (result i32) (i32.const 4))
-           (func $f5 (export "f5") (result i32) (i32.const 5))
-           (func $f6 (export "f6") (result i32) (i32.const 6))
-           (func $f7 (export "f7") (result i32) (i32.const 7))
-           (func $f8 (export "f8") (result i32) (i32.const 8))
-           (func $f9 (export "f9") (result i32) (i32.const 9))
-           (func $f10 (export "f10") (result i32) (i32.const 10))
-           (func $f11 (export "f11") (result i32) (i32.const 11))
-           (func $f12 (export "f12") (result i32) (i32.const 12))
-           (func $f13 (export "f13") (result i32) (i32.const 13))
-           (func $f14 (export "f14") (result i32) (i32.const 14))
-           (func $f15 (export "f15") (result i32) (i32.const 15))
-           (func (export "test") (param $n i32) (result i32)
-             (call_indirect (type 0) (local.get $n)))
-           (func (export "run") (param $targetOffs i32) (param $srcOffs i32) (param $len i32)
-             (table.copy (local.get $targetOffs) (local.get $srcOffs) (local.get $len))))`);
+        `
+(module
+  (type (func (result i32)))
+  (table ${min} ${max} funcref)
+  (elem (i32.const ${srcOffs})
+        ${(function () {
+             var s = "";
+             for (let i=srcOffs, j=0; i < srcLim; i++, j++)
+               s += " $f" + j;
+             return s;
+         })()})
+  (func $f0 (export "f0") (result i32) (i32.const 0))
+  (func $f1 (export "f1") (result i32) (i32.const 1))
+  (func $f2 (export "f2") (result i32) (i32.const 2))
+  (func $f3 (export "f3") (result i32) (i32.const 3))
+  (func $f4 (export "f4") (result i32) (i32.const 4))
+  (func $f5 (export "f5") (result i32) (i32.const 5))
+  (func $f6 (export "f6") (result i32) (i32.const 6))
+  (func $f7 (export "f7") (result i32) (i32.const 7))
+  (func $f8 (export "f8") (result i32) (i32.const 8))
+  (func $f9 (export "f9") (result i32) (i32.const 9))
+  (func $f10 (export "f10") (result i32) (i32.const 10))
+  (func $f11 (export "f11") (result i32) (i32.const 11))
+  (func $f12 (export "f12") (result i32) (i32.const 12))
+  (func $f13 (export "f13") (result i32) (i32.const 13))
+  (func $f14 (export "f14") (result i32) (i32.const 14))
+  (func $f15 (export "f15") (result i32) (i32.const 15))
+  (func (export "test") (param $n i32) (result i32)
+    (call_indirect (type 0) (local.get $n)))
+  (func (export "run") (param $targetOffs i32) (param $srcOffs i32) (param $len i32)
+    (table.copy (local.get $targetOffs) (local.get $srcOffs) (local.get $len))))
+`);
 
     let immediateOOB = copyDown && (srcOffs + len > tblLength || targetOffs + len > tblLength);
 
     print(`(assert_trap (invoke "run" (i32.const ${targetOffs}) (i32.const ${srcOffs}) (i32.const ${len}))
-                        "out of bounds")`);
+             "out of bounds")`);
 
     var t = 0;
     var s = 0;
diff --git a/test/meta/generate_table_init.js b/test/meta/generate_table_init.js
index 52cce96367..bfac8ae5d2 100644
--- a/test/meta/generate_table_init.js
+++ b/test/meta/generate_table_init.js
@@ -15,8 +15,7 @@ function emit_a() {
   (func (export "ef3") (result i32) (i32.const 3))
   (func (export "ef4") (result i32) (i32.const 4))
 )
-(register "a")
-`);
+(register "a")`);
 }
 
 // ... and this one imports those 5 functions.  It adds 5 of its own, creates a
@@ -88,15 +87,15 @@ tab_test("(table.init 3 (i32.const 15) (i32.const 1) (i32.const 3))",
          [e,e,3,1,4, 1,e,e,e,e, e,e,7,5,2, 9,2,7,e,e, e,e,e,e,e, e,e,e,e,e]);
 
 // Perform active and passive initialisation and then multiple copies
-tab_test("(table.init 1 (i32.const 7) (i32.const 0) (i32.const 4)) \n" +
-         "elem.drop 1 \n" +
-         "(table.init 3 (i32.const 15) (i32.const 1) (i32.const 3)) \n" +
-         "elem.drop 3 \n" +
-         "(table.copy (i32.const 20) (i32.const 15) (i32.const 5)) \n" +
-         "(table.copy (i32.const 21) (i32.const 29) (i32.const 1)) \n" +
-         "(table.copy (i32.const 24) (i32.const 10) (i32.const 1)) \n" +
-         "(table.copy (i32.const 13) (i32.const 11) (i32.const 4)) \n" +
-         "(table.copy (i32.const 19) (i32.const 20) (i32.const 5))",
+tab_test(`(table.init 1 (i32.const 7) (i32.const 0) (i32.const 4))
+    (elem.drop 1)
+    (table.init 3 (i32.const 15) (i32.const 1) (i32.const 3))
+    (elem.drop 3)
+    (table.copy (i32.const 20) (i32.const 15) (i32.const 5))
+    (table.copy (i32.const 21) (i32.const 29) (i32.const 1))
+    (table.copy (i32.const 24) (i32.const 10) (i32.const 1))
+    (table.copy (i32.const 13) (i32.const 11) (i32.const 4))
+    (table.copy (i32.const 19) (i32.const 20) (i32.const 5))`,
          [e,e,3,1,4, 1,e,2,7,1, 8,e,7,e,7, 5,2,7,e,9, e,7,e,8,8, e,e,e,e,e]);
 
 
@@ -161,8 +160,7 @@ function do_test(insn1, insn2, errText)
   (func (result i32) (i32.const 9))
   (func (export "test")
     ${insn1}
-    ${insn2}))
-`);
+    ${insn2}))`);
 
     if (errText !== undefined) {
         print(`(assert_trap (invoke "test") "${errText}")`);
@@ -171,6 +169,10 @@ function do_test(insn1, insn2, errText)
     }
 }
 
+function tab_test1(insn1, errText) {
+    do_test(insn1, "", errText);
+}
+
 function tab_test2(insn1, insn2, errText) {
     do_test(insn1, insn2, errText);
 }
@@ -180,12 +182,12 @@ function tab_test_nofail(insn1, insn2) {
 }
 
 // drop with elem seg ix indicating an active segment
-tab_test2("elem.drop 2", "",
+tab_test1("(elem.drop 2)",
           "elements segment dropped");
 
 // init with elem seg ix indicating an active segment
-tab_test2("(table.init 2 (i32.const 12) (i32.const 1) (i32.const 1))", "",
-         "elements segment dropped");
+tab_test1("(table.init 2 (i32.const 12) (i32.const 1) (i32.const 1))",
+          "elements segment dropped");
 
 // init, using an elem seg ix more than once is OK
 tab_test_nofail(
@@ -193,41 +195,36 @@ tab_test_nofail(
     "(table.init 1 (i32.const 21) (i32.const 1) (i32.const 1))");
 
 // drop, then drop
-tab_test2("elem.drop 1",
-          "elem.drop 1",
+tab_test2("(elem.drop 1)",
+          "(elem.drop 1)",
           "elements segment dropped");
 
 // drop, then init
-tab_test2("elem.drop 1",
-         "(table.init 1 (i32.const 12) (i32.const 1) (i32.const 1))",
-         "elements segment dropped");
+tab_test2("(elem.drop 1)",
+          "(table.init 1 (i32.const 12) (i32.const 1) (i32.const 1))",
+          "elements segment dropped");
 
 // init: seg ix is valid passive, but length to copy > len of seg
-tab_test2("",
-         "(table.init 1 (i32.const 12) (i32.const 0) (i32.const 5))",
-         "out of bounds");
+tab_test1("(table.init 1 (i32.const 12) (i32.const 0) (i32.const 5))",
+          "out of bounds");
 
 // init: seg ix is valid passive, but implies copying beyond end of seg
-tab_test2("",
-         "(table.init 1 (i32.const 12) (i32.const 2) (i32.const 3))",
-         "out of bounds");
+tab_test1("(table.init 1 (i32.const 12) (i32.const 2) (i32.const 3))",
+          "out of bounds");
 
 // init: seg ix is valid passive, but implies copying beyond end of dst
-tab_test2("",
-         "(table.init 1 (i32.const 28) (i32.const 1) (i32.const 3))",
-         "out of bounds");
+tab_test1("(table.init 1 (i32.const 28) (i32.const 1) (i32.const 3))",
+          "out of bounds");
 
 // init: seg ix is valid passive, zero len, and src offset out of bounds at the
 // end of the table - this is allowed
-tab_test2("",
-         "(table.init 1 (i32.const 12) (i32.const 4) (i32.const 0))",
-         undefined);
+tab_test1("(table.init 1 (i32.const 12) (i32.const 4) (i32.const 0))",
+          undefined);
 
 // init: seg ix is valid passive, zero len, and dst offset out of bounds at the
 // end of the table - this is allowed
-tab_test2("",
-         "(table.init 1 (i32.const 30) (i32.const 2) (i32.const 0))",
-         undefined);
+tab_test1("(table.init 1 (i32.const 30) (i32.const 2) (i32.const 0))",
+          undefined);
 
 // invalid argument types
 {
@@ -239,15 +236,15 @@ tab_test2("",
         if (ty1 == 'i32' && ty2 == 'i32' && ty3 == 'i32')
             continue;  // this is the only valid case
         print(
-`(assert_invalid
-   (module
-     (table 10 funcref)
-     (elem passive funcref $f0 $f0 $f0)
-     (func $f0)
-     (func (export "test")
-       (table.init 0 (${ty1}.const 1) (${ty2}.const 1) (${ty3}.const 1))))
-   "type mismatch")
-`);
+`
+(assert_invalid
+  (module
+    (table 10 funcref)
+    (elem passive funcref $f0 $f0 $f0)
+    (func $f0)
+    (func (export "test")
+      (table.init 0 (${ty1}.const 1) (${ty2}.const 1) (${ty3}.const 1))))
+  "type mismatch")`);
     }}}
 }
 
@@ -262,30 +259,32 @@ const tbl_init_len = 16;
 
 function tbl_init(min, max, backup, write, segoffs=0) {
     print(
-        `(module
-           (type (func (result i32)))
-           (table ${min} ${max} funcref)
-           (elem passive funcref $f0 $f1 $f2 $f3 $f4 $f5 $f6 $f7 $f8 $f9 $f10 $f11 $f12 $f13 $f14 $f15)
-           (func $f0 (export "f0") (result i32) (i32.const 0))
-           (func $f1 (export "f1") (result i32) (i32.const 1))
-           (func $f2 (export "f2") (result i32) (i32.const 2))
-           (func $f3 (export "f3") (result i32) (i32.const 3))
-           (func $f4 (export "f4") (result i32) (i32.const 4))
-           (func $f5 (export "f5") (result i32) (i32.const 5))
-           (func $f6 (export "f6") (result i32) (i32.const 6))
-           (func $f7 (export "f7") (result i32) (i32.const 7))
-           (func $f8 (export "f8") (result i32) (i32.const 8))
-           (func $f9 (export "f9") (result i32) (i32.const 9))
-           (func $f10 (export "f10") (result i32) (i32.const 10))
-           (func $f11 (export "f11") (result i32) (i32.const 11))
-           (func $f12 (export "f12") (result i32) (i32.const 12))
-           (func $f13 (export "f13") (result i32) (i32.const 13))
-           (func $f14 (export "f14") (result i32) (i32.const 14))
-           (func $f15 (export "f15") (result i32) (i32.const 15))
-           (func (export "test") (param $n i32) (result i32)
-             (call_indirect (type 0) (local.get $n)))
-           (func (export "run") (param $offs i32) (param $len i32)
-             (table.init 0 (local.get $offs) (i32.const ${segoffs}) (local.get $len))))`);
+        `
+(module
+  (type (func (result i32)))
+  (table ${min} ${max} funcref)
+  (elem passive funcref $f0 $f1 $f2 $f3 $f4 $f5 $f6 $f7 $f8 $f9 $f10 $f11 $f12 $f13 $f14 $f15)
+  (func $f0 (export "f0") (result i32) (i32.const 0))
+  (func $f1 (export "f1") (result i32) (i32.const 1))
+  (func $f2 (export "f2") (result i32) (i32.const 2))
+  (func $f3 (export "f3") (result i32) (i32.const 3))
+  (func $f4 (export "f4") (result i32) (i32.const 4))
+  (func $f5 (export "f5") (result i32) (i32.const 5))
+  (func $f6 (export "f6") (result i32) (i32.const 6))
+  (func $f7 (export "f7") (result i32) (i32.const 7))
+  (func $f8 (export "f8") (result i32) (i32.const 8))
+  (func $f9 (export "f9") (result i32) (i32.const 9))
+  (func $f10 (export "f10") (result i32) (i32.const 10))
+  (func $f11 (export "f11") (result i32) (i32.const 11))
+  (func $f12 (export "f12") (result i32) (i32.const 12))
+  (func $f13 (export "f13") (result i32) (i32.const 13))
+  (func $f14 (export "f14") (result i32) (i32.const 14))
+  (func $f15 (export "f15") (result i32) (i32.const 15))
+  (func (export "test") (param $n i32) (result i32)
+    (call_indirect (type 0) (local.get $n)))
+  (func (export "run") (param $offs i32) (param $len i32)
+    (table.init 0 (local.get $offs) (i32.const ${segoffs}) (local.get $len))))`);
+
     // A fill writing past the end of the table should throw *and* have filled
     // all the way up to the end.
     //

From 63cceba2151e769046f53951ca50775f33cec9db Mon Sep 17 00:00:00 2001
From: Lars T Hansen 
Date: Thu, 7 Mar 2019 08:11:48 +0100
Subject: [PATCH 069/199] Remove irrelevant comment + support node.js (#70)

* Remove irrelevant comment

* Support node.js as well
---
 test/meta/Makefile               |  7 ++++++-
 test/meta/common.js              |  8 --------
 test/meta/generate_table_copy.js |  3 ---
 test/meta/noderun.sh             | 16 ++++++++++++++++
 4 files changed, 22 insertions(+), 12 deletions(-)
 create mode 100755 test/meta/noderun.sh

diff --git a/test/meta/Makefile b/test/meta/Makefile
index 11c8c0cad1..7f9e680552 100644
--- a/test/meta/Makefile
+++ b/test/meta/Makefile
@@ -1,5 +1,10 @@
+SHARED_MEM=false
+
 # SpiderMonkey shell
-JSSHELL=~/m-i/js/src/build-debug/dist/bin/js -e 'const WITH_SHARED_MEMORY=false;' -f common.js
+JSSHELL=~/m-i/js/src/build-debug/dist/bin/js -e 'const WITH_SHARED_MEMORY=$(SHARED_MEM);' -f common.js
+
+# Node.js
+#JSSHELL=./noderun.sh $(SHARED_MEM)
 
 TARGETDIR=../core
 
diff --git a/test/meta/common.js b/test/meta/common.js
index dd117b4760..16d80726a6 100644
--- a/test/meta/common.js
+++ b/test/meta/common.js
@@ -1,11 +1,3 @@
-// WITH_SHARED_MEMORY can be overridden in a preamble, see `Makefile`.
-//
-// Set WITH_SHARED_MEMORY to true to get additional testing on memory backed by
-// SharedArrayBuffer.
-if (typeof this.WITH_SHARED_MEMORY == "undefined") {
-    this.WITH_SHARED_MEMORY = false;
-}
-
 const PAGESIZE = 65536;
 
 function print_origin(origin) {
diff --git a/test/meta/generate_table_copy.js b/test/meta/generate_table_copy.js
index b8d1af8068..9058281b6d 100644
--- a/test/meta/generate_table_copy.js
+++ b/test/meta/generate_table_copy.js
@@ -205,9 +205,6 @@ tab_test2("(table.copy (i32.const 15) (i32.const 30) (i32.const 0))",
 // - src address oob
 // - target address oob
 // - both oob
-//
-// Note we do not test the multi-table case here because that is part of the
-// reftypes proposal; tests are in the gc/ subdirectory.
 
 const tbl_copy_len = 16;
 
diff --git a/test/meta/noderun.sh b/test/meta/noderun.sh
new file mode 100755
index 0000000000..7b07a28cf9
--- /dev/null
+++ b/test/meta/noderun.sh
@@ -0,0 +1,16 @@
+if [ $# -ne 2 ]; then
+    echo "Bad args"
+    exit 1
+fi
+
+rm -f nodeprog.js
+cat <> nodeprog.js
+const WITH_SHARED_MEMORY=$1;
+function print(x) {
+    console.log(x);
+}
+EOF
+cat common.js >> nodeprog.js
+cat $2 >> nodeprog.js
+node nodeprog.js
+rm nodeprog.js

From 0cf128e98be41aae55d58d0b5edc65c1cf26b416 Mon Sep 17 00:00:00 2001
From: Andreas Rossberg 
Date: Fri, 8 Mar 2019 20:27:51 +0100
Subject: [PATCH 070/199] [interpreter] Refactor element type in passive
 segments (#71)

* Refactor type in passive segments

* Make tests more specific
---
 interpreter/binary/decode.ml    | 39 +++++++++----------
 interpreter/binary/encode.ml    | 28 +++++++-------
 interpreter/exec/eval.ml        | 68 +++++++++++++++++----------------
 interpreter/runtime/instance.ml |  8 ++--
 interpreter/syntax/ast.ml       | 20 +++++-----
 interpreter/text/arrange.ml     | 10 ++---
 interpreter/text/parser.mly     | 22 +++++------
 interpreter/valid/valid.ml      | 36 ++++++++---------
 test/core/binary.wast           | 10 ++++-
 test/core/bulk.wast             |  8 ++--
 test/core/table_init.wast       |  8 ++--
 11 files changed, 130 insertions(+), 127 deletions(-)

diff --git a/interpreter/binary/decode.ml b/interpreter/binary/decode.ml
index 00b13d5442..0686703613 100644
--- a/interpreter/binary/decode.ml
+++ b/interpreter/binary/decode.ml
@@ -5,12 +5,12 @@ type stream =
   name : string;
   bytes : string;
   pos : int ref;
-  has_data_count : bool ref;
+  need_data_count : bool ref;
 }
 
 exception EOS
 
-let stream name bs = {name; bytes = bs; pos = ref 0; has_data_count = ref false}
+let stream name bs = {name; bytes = bs; pos = ref 0; need_data_count = ref false}
 
 let len s = String.length s.bytes
 let pos s = !(s.pos)
@@ -202,18 +202,15 @@ let memop s =
   let offset = vu32 s in
   Int32.to_int align, offset
 
-let check_data_count s =
-  require !(s.has_data_count) s (pos s - 1) "data count section required"
-
 let misc_instr s =
   let pos = pos s in
   match op s with
   | 0x08 ->
-    check_data_count s;
     let x = at var s in
     zero_flag s;
+    s.need_data_count := true;
     memory_init x
-  | 0x09 -> check_data_count s; data_drop (at var s)
+  | 0x09 -> s.need_data_count := true; data_drop (at var s)
   | 0x0a -> zero_flag s; zero_flag s; memory_copy
   | 0x0b -> zero_flag s; memory_fill
   | 0x0c ->
@@ -625,8 +622,8 @@ let segment active passive s =
     let init = active s in
     Active {index; offset; init}
   | 1l ->
-    let init = passive s in
-    Passive init
+    let etype, data = passive s in
+    Passive {etype; data}
   | 2l ->
     let index = at var s in
     let offset = const s in
@@ -634,7 +631,8 @@ let segment active passive s =
     Active {index; offset; init}
   | _ -> error s (pos s - 1) "invalid segment kind"
 
-let active_elem s = Func (at var s)
+let active_elem s =
+  Func (at var s)
 
 let passive_elem s =
   match u8 s with
@@ -646,7 +644,7 @@ let passive_elem s =
   | _ -> error s (pos s - 1) "invalid elem"
 
 let active_elem_segment s =
-  FuncRefType, vec (at active_elem) s
+  vec (at active_elem) s
 
 let passive_elem_segment s =
   let etype = elem_type s in
@@ -663,7 +661,7 @@ let elem_section s =
 (* Data section *)
 
 let memory_segment s =
-  segment string string s
+  segment string (fun s -> (), string s) s
 
 let data_section s =
   section `DataSection (vec (at memory_segment)) [] s
@@ -671,11 +669,11 @@ let data_section s =
 
 (* DataCount section *)
 
+let data_count s =
+  Some (vu32 s)
+
 let data_count_section s =
-  let contents s =
-    s.has_data_count := true;
-    opt vu32 true s
-  in section `DataCountSection contents None s
+  section `DataCountSection data_count None s
 
 
 (* Custom section *)
@@ -722,18 +720,19 @@ let module_ s =
   iterate custom_section s;
   let func_bodies = code_section s in
   iterate custom_section s;
-  let data = data_section s in
+  let datas = data_section s in
   iterate custom_section s;
   require (pos s = len s) s (len s) "junk after last section";
   require (List.length func_types = List.length func_bodies)
     s (len s) "function and code section have inconsistent lengths";
-  require
-    (data_count = None || data_count = Some (Int32.of_int (List.length data)))
+  require (data_count = None || data_count = Some (Lib.List32.length datas))
     s (len s) "data count and data section have inconsistent lengths";
+  require (not !(s.need_data_count) || data_count <> None)
+    s (len s) "data count section required";
   let funcs =
     List.map2 Source.(fun t f -> {f.it with ftype = t} @@ f.at)
       func_types func_bodies
-  in {types; tables; memories; globals; funcs; imports; exports; elems; data; start}
+  in {types; tables; memories; globals; funcs; imports; exports; elems; datas; start}
 
 
 let decode name bs = at module_ (stream name bs)
diff --git a/interpreter/binary/encode.ml b/interpreter/binary/encode.ml
index c983ca81c8..87abace93d 100644
--- a/interpreter/binary/encode.ml
+++ b/interpreter/binary/encode.ml
@@ -485,10 +485,9 @@ let encode m =
         else begin
           u8 0x02; var index
         end;
-        const offset;
-        active init
-      | Passive init ->
-        u8 0x01; passive init
+        const offset; active init
+      | Passive {etype; data} ->
+        u8 0x01; passive etype data
 
     let active_elem el =
       match el.it with
@@ -501,8 +500,8 @@ let encode m =
       | Func x -> u8 0xd2; var x; end_ ()
 
     let table_segment seg =
-      let active (_,init) = vec active_elem init in
-      let passive (etype,init) = elem_type etype; vec passive_elem init in
+      let active init = vec active_elem init in
+      let passive etype data = elem_type etype; vec passive_elem data in
       segment active passive seg
 
     let elem_section elems =
@@ -510,15 +509,14 @@ let encode m =
 
     (* Data section *)
     let memory_segment seg =
-      segment string string seg
+      segment string (fun _ s -> string s) seg
 
-    let data_section data =
-      section 11 (vec memory_segment) data (data <> [])
+    let data_section datas =
+      section 11 (vec memory_segment) datas (datas <> [])
 
-    (* DataCount section *)
-
-    let data_count_section data =
-      section 12 len (List.length data) (data <> [])
+    (* Data count section *)
+    let data_count_section datas =
+      section 12 len (List.length datas) true
 
     (* Module *)
 
@@ -534,8 +532,8 @@ let encode m =
       export_section m.it.exports;
       start_section m.it.start;
       elem_section m.it.elems;
-      data_count_section m.it.data;
+      data_count_section m.it.datas;
       code_section m.it.funcs;
-      data_section m.it.data
+      data_section m.it.datas
   end
   in E.module_ m; to_string s
diff --git a/interpreter/exec/eval.ml b/interpreter/exec/eval.ml
index 13220ae57b..fb6f134b4e 100644
--- a/interpreter/exec/eval.ml
+++ b/interpreter/exec/eval.ml
@@ -82,11 +82,11 @@ let func (inst : module_inst) x = lookup "function" inst.funcs x
 let table (inst : module_inst) x = lookup "table" inst.tables x
 let memory (inst : module_inst) x = lookup "memory" inst.memories x
 let global (inst : module_inst) x = lookup "global" inst.globals x
-let elems (inst : module_inst) x = lookup "elems" inst.elems x
-let data (inst : module_inst) x = lookup "data" inst.data x
+let elem (inst : module_inst) x = lookup "element segment" inst.elems x
+let data (inst : module_inst) x = lookup "data segment" inst.datas x
 let local (frame : frame) x = lookup "local" frame.locals x
 
-let elem inst x i at =
+let any_elem inst x i at =
   match Table.load (table inst x) i with
   | Table.Uninitialized ->
     Trap.error at ("uninitialized element " ^ Int32.to_string i)
@@ -95,7 +95,7 @@ let elem inst x i at =
     Trap.error at ("undefined element " ^ Int32.to_string i)
 
 let func_elem inst x i at =
-  match elem inst x i at with
+  match any_elem inst x i at with
   | FuncElem f -> f
   | _ -> Crash.error at ("type mismatch for element " ^ Int32.to_string i)
 
@@ -263,13 +263,8 @@ let rec step (c : config) : config =
           let src = I64_convert.extend_i32_u s in
           (try Memory.init mem bs dst src n; vs', []
           with exn -> vs', [Trapping (memory_error e.at exn) @@ e.at])
-        | None -> vs', [Trapping "data segment dropped" @@ e.at])
-
-      | DataDrop x, vs ->
-        let seg = data frame.inst x in
-        (match !seg with
-        | Some _ -> seg := None; vs, []
-        | None -> vs, [Trapping "data segment dropped" @@ e.at])
+        | None -> vs', [Trapping "data segment dropped" @@ e.at]
+        )
 
       | MemoryCopy, I32 n :: I32 s :: I32 d :: vs' ->
         let mem = memory frame.inst (0l @@ e.at) in
@@ -286,23 +281,32 @@ let rec step (c : config) : config =
 
       | TableInit x, I32 n :: I32 s :: I32 d :: vs' ->
         let tab = table frame.inst (0l @@ e.at) in
-        (match !(elems frame.inst x) with
+        (match !(elem frame.inst x) with
         | Some es ->
           (try Table.init tab es d s n; vs', []
           with exn -> vs', [Trapping (table_error e.at exn) @@ e.at])
-        | None -> vs', [Trapping "elements segment dropped" @@ e.at])
-
-      | ElemDrop x, vs ->
-        let seg = elems frame.inst x in
-        (match !seg with
-        | Some _ -> seg := None; vs, []
-        | None -> vs, [Trapping "elements segment dropped" @@ e.at])
+        | None -> vs', [Trapping "element segment dropped" @@ e.at]
+        )
 
       | TableCopy, I32 n :: I32 s :: I32 d :: vs' ->
         let tab = table frame.inst (0l @@ e.at) in
         (try Table.copy tab d s n; vs', []
         with exn -> vs', [Trapping (table_error e.at exn) @@ e.at])
 
+      | DataDrop x, vs ->
+        let seg = data frame.inst x in
+        (match !seg with
+        | Some _ -> seg := None; vs, []
+        | None -> vs, [Trapping "data segment dropped" @@ e.at]
+        )
+
+      | ElemDrop x, vs ->
+        let seg = elem frame.inst x in
+        (match !seg with
+        | Some _ -> seg := None; vs, []
+        | None -> vs, [Trapping "element segment dropped" @@ e.at]
+        )
+
       | _ ->
         let s1 = string_of_values (List.rev vs) in
         let s2 = string_of_value_types (List.map type_of (List.rev vs)) in
@@ -435,22 +439,22 @@ let create_export (inst : module_inst) (ex : export) : export_inst =
     | GlobalExport x -> ExternGlobal (global inst x)
   in name, ext
 
-let elems_list inst init =
+let elem_list inst init =
   let to_elem el =
     match el.it with
     | Null -> Table.Uninitialized
     | Func x -> FuncElem (func inst x)
   in List.map to_elem init
 
-let create_elems (inst : module_inst) (seg : table_segment) : elems_inst =
+let create_elem (inst : module_inst) (seg : table_segment) : elem_inst =
   match seg.it with
   | Active _ -> ref None
-  | Passive (_,init) -> ref (Some (elems_list inst init))
+  | Passive {data; _} -> ref (Some (elem_list inst data))
 
 let create_data (inst : module_inst) (seg : memory_segment) : data_inst =
   match seg.it with
   | Active _ -> ref None
-  | Passive init -> ref (Some init)
+  | Passive {data; _} -> ref (Some data)
 
 
 let init_func (inst : module_inst) (func : func_inst) =
@@ -460,14 +464,14 @@ let init_func (inst : module_inst) (func : func_inst) =
 
 let init_table (inst : module_inst) (seg : table_segment) =
   match seg.it with
-  | Active {index; offset = const; init = (_,init)} ->
+  | Active {index; offset = const; init} ->
     let tab = table inst index in
     let offset = i32 (eval_const inst const) const.at in
-    let elems = elems_list inst init in
+    let elems = elem_list inst init in
     let len = Int32.of_int (List.length elems) in
     (try Table.init tab elems offset 0l len
     with Table.Bounds -> Link.error seg.at "elements segment does not fit table")
-  | Passive init -> ()
+  | Passive _ -> ()
 
 let init_memory (inst : module_inst) (seg : memory_segment) =
   match seg.it with
@@ -478,7 +482,7 @@ let init_memory (inst : module_inst) (seg : memory_segment) =
     let len = Int32.of_int (String.length init) in
     (try Memory.init mem init offset 0L len
     with Memory.Bounds -> Link.error seg.at "data segment does not fit memory")
-  | Passive init -> ()
+  | Passive _ -> ()
 
 
 let add_import (m : module_) (ext : extern) (im : import) (inst : module_inst)
@@ -494,7 +498,7 @@ let add_import (m : module_) (ext : extern) (im : import) (inst : module_inst)
 let init (m : module_) (exts : extern list) : module_inst =
   let
     { imports; tables; memories; globals; funcs; types;
-      exports; elems; data; start
+      exports; elems; datas; start
     } = m.it
   in
   if List.length exts <> List.length imports then
@@ -509,18 +513,18 @@ let init (m : module_) (exts : extern list) : module_inst =
       funcs = inst0.funcs @ fs;
       tables = inst0.tables @ List.map (create_table inst0) tables;
       memories = inst0.memories @ List.map (create_memory inst0) memories;
-      globals = inst0.globals @ List.map (create_global inst0) globals
+      globals = inst0.globals @ List.map (create_global inst0) globals;
     }
   in
   let inst =
     { inst1 with
       exports = List.map (create_export inst1) exports;
-      elems = List.map (create_elems inst1) elems;
-      data = List.map (create_data inst1) data
+      elems = List.map (create_elem inst1) elems;
+      datas = List.map (create_data inst1) datas;
     }
   in
   List.iter (init_func inst) fs;
   List.iter (init_table inst) elems;
-  List.iter (init_memory inst) data;
+  List.iter (init_memory inst) datas;
   Lib.Option.app (fun x -> ignore (invoke (func inst x) [])) start;
   inst
diff --git a/interpreter/runtime/instance.ml b/interpreter/runtime/instance.ml
index eb821d2ee0..de0e814189 100644
--- a/interpreter/runtime/instance.ml
+++ b/interpreter/runtime/instance.ml
@@ -8,8 +8,8 @@ type module_inst =
   memories : memory_inst list;
   globals : global_inst list;
   exports : export_inst list;
-  elems : elems_inst list;
-  data : data_inst list;
+  elems : elem_inst list;
+  datas : data_inst list;
 }
 
 and func_inst = module_inst ref Func.t
@@ -17,7 +17,7 @@ and table_inst = Table.t
 and memory_inst = Memory.t
 and global_inst = Global.t
 and export_inst = Ast.name * extern
-and elems_inst = Table.elem list option ref
+and elem_inst = Table.elem list option ref
 and data_inst = string option ref
 
 and extern =
@@ -33,7 +33,7 @@ type Table.elem += FuncElem of func_inst
 
 let empty_module_inst =
   { types = []; funcs = []; tables = []; memories = []; globals = [];
-    exports = []; elems = []; data = [] }
+    exports = []; elems = []; datas = [] }
 
 let extern_type_of = function
   | ExternFunc func -> ExternFuncType (Func.type_of func)
diff --git a/interpreter/syntax/ast.ml b/interpreter/syntax/ast.ml
index d33ed8a41b..3bcbc3a53b 100644
--- a/interpreter/syntax/ast.ml
+++ b/interpreter/syntax/ast.ml
@@ -98,12 +98,12 @@ and instr' =
   | Binary of binop                   (* binary numeric operator *)
   | Convert of cvtop                  (* conversion *)
   | MemoryInit of var                 (* initialize memory from segment *)
-  | DataDrop of var                   (* drop passive data segment *)
   | MemoryCopy                        (* copy memory regions *)
   | MemoryFill                        (* fill memory region with value *)
   | TableInit of var                  (* initialize table from segment *)
-  | ElemDrop of var                   (* drop passive element segment *)
   | TableCopy                         (* copy elements between table regions *)
+  | DataDrop of var                   (* drop passive data segment *)
+  | ElemDrop of var                   (* drop passive element segment *)
 
 
 (* Globals & Functions *)
@@ -140,18 +140,18 @@ and memory' =
   mtype : memory_type;
 }
 
-type 'data segment = 'data segment' Source.phrase
-and 'data segment' =
+type ('data, 'ty) segment = ('data, 'ty) segment' Source.phrase
+and ('data, 'ty) segment' =
   | Active of {index : var; offset : const; init : 'data}
-  | Passive of 'data
+  | Passive of {etype : 'ty; data : 'data}
 
 type elem = elem' Source.phrase
 and elem' =
   | Null
   | Func of var
 
-type table_segment = (elem_type * (elem list)) segment
-type memory_segment = string segment
+type table_segment = (elem list, elem_type) segment
+type memory_segment = (string, unit) segment
 
 
 (* Modules *)
@@ -197,7 +197,7 @@ and module_' =
   funcs : func list;
   start : var option;
   elems : table_segment list;
-  data : memory_segment list;
+  datas : memory_segment list;
   imports : import list;
   exports : export list;
 }
@@ -213,8 +213,8 @@ let empty_module =
   memories = [];
   funcs = [];
   start = None;
-  elems  = [];
-  data = [];
+  elems = [];
+  datas = [];
   imports = [];
   exports = [];
 }
diff --git a/interpreter/text/arrange.ml b/interpreter/text/arrange.ml
index da39e9fba0..42014540d2 100644
--- a/interpreter/text/arrange.ml
+++ b/interpreter/text/arrange.ml
@@ -300,7 +300,7 @@ let segment head active passive seg =
   match seg.it with
   | Active {index; offset; init} ->
     Node (head, atom var index :: Node ("offset", const offset) :: active init)
-  | Passive init -> Node (head ^ " passive", passive init)
+  | Passive {etype; data} -> Node (head ^ " passive", passive etype data)
 
 let active_elem el =
   match el.it with
@@ -313,12 +313,12 @@ let passive_elem el =
   | Func x -> Node ("ref.func", [atom var x])
 
 let elems seg =
-  let active (_,init) = list active_elem init in
-  let passive (etype,init) = atom elem_type etype :: list passive_elem init in
+  let active init = list active_elem init in
+  let passive etype init = atom elem_type etype :: list passive_elem init in
   segment "elem" active passive seg
 
 let data seg =
-  segment "data" break_bytes break_bytes seg
+  segment "data" break_bytes (fun _ bs -> break_bytes bs) seg
 
 
 (* Modules *)
@@ -389,7 +389,7 @@ let module_with_var_opt x_opt m =
     list export m.it.exports @
     opt start m.it.start @
     list elems m.it.elems @
-    list data m.it.data
+    list data m.it.datas
   )
 
 let binary_module_with_var_opt x_opt bs =
diff --git a/interpreter/text/parser.mly b/interpreter/text/parser.mly
index f8871a2ea3..ffb90b2808 100644
--- a/interpreter/text/parser.mly
+++ b/interpreter/text/parser.mly
@@ -587,25 +587,21 @@ elem :
   | LPAR ELEM bind_var_opt PASSIVE elem_type passive_elemref_list RPAR
     { let at = at () in
       fun c -> ignore ($3 c anon_elem bind_elem);
-      fun () -> Passive ($5, ($6 c)) @@ at }
+      fun () -> Passive {etype = $5; data = $6 c} @@ at }
   | LPAR ELEM bind_var var offset active_elemref_list RPAR
     { let at = at () in
       fun c -> ignore (bind_elem c $3);
       fun () ->
-      let init = FuncRefType, ($6 c func) in
-      Active {index = $4 c table; offset = $5 c; init} @@ at }
+      Active {index = $4 c table; offset = $5 c; init = $6 c func} @@ at }
   | LPAR ELEM var offset active_elemref_list RPAR
     { let at = at () in
       fun c -> ignore (anon_elem c);
       fun () ->
-      let init = FuncRefType, $5 c func in
-      Active {index = $3 c table; offset = $4 c; init} @@ at }
+      Active {index = $3 c table; offset = $4 c; init = $5 c func} @@ at }
   | LPAR ELEM offset active_elemref_list RPAR  /* Sugar */
     { let at = at () in
       fun c -> ignore (anon_elem c);
-      fun () ->
-      let init = FuncRefType, $4 c func in
-      Active {index = 0l @@ at; offset = $3 c; init} @@ at }
+      fun () -> Active {index = 0l @@ at; offset = $3 c; init = $4 c func} @@ at }
 
 table :
   | LPAR TABLE bind_var_opt table_fields RPAR
@@ -627,8 +623,8 @@ table_fields :
   | elem_type LPAR ELEM active_elemref_list RPAR  /* Sugar */
     { fun c x at ->
       let offset = [i32_const (0l @@ at) @@ at] @@ at in
-      let init' = $4 c func in let size = Int32.of_int (List.length init') in
-      let init = FuncRefType, init' in
+      let init = $4 c func in
+      let size = Lib.List32.length init in
       [{ttype = TableType ({min = size; max = Some size}, $1)} @@ at],
       [Active {index = x; offset; init} @@ at],
       [], [] }
@@ -637,7 +633,7 @@ data :
   | LPAR DATA bind_var_opt PASSIVE string_list RPAR
     { let at = at () in
       fun c -> ignore ($3 c anon_data bind_data);
-      fun () -> Passive $5 @@ at }
+      fun () -> Passive {etype = (); data = $5} @@ at }
  | LPAR DATA bind_var var offset string_list RPAR
    { let at = at () in
      fun c -> ignore (bind_data c $3);
@@ -782,7 +778,7 @@ module_fields1 :
       fun () -> let mems, data, ims, exs = mmf () in let m = mf () in
       if mems <> [] && m.imports <> [] then
         error (List.hd m.imports).at "import after memory definition";
-      { m with memories = mems @ m.memories; data = data @ m.data;
+      { m with memories = mems @ m.memories; datas = data @ m.datas;
         imports = ims @ m.imports; exports = exs @ m.exports } }
   | func module_fields
     { fun c -> let ff = $1 c in let mf = $2 c in
@@ -798,7 +794,7 @@ module_fields1 :
   | data module_fields
     { fun c -> let df = $1 c in let mf = $2 c in
       fun () -> let data = df () in let m = mf () in
-      {m with data = data :: m.data} }
+      {m with datas = data :: m.datas} }
   | start module_fields
     { fun c -> let mf = $2 c in
       fun () -> let m = mf () in let x = $1 c in
diff --git a/interpreter/valid/valid.ml b/interpreter/valid/valid.ml
index 955e2ce113..451aeeecb9 100644
--- a/interpreter/valid/valid.ml
+++ b/interpreter/valid/valid.ml
@@ -21,7 +21,7 @@ type context =
   tables : table_type list;
   memories : memory_type list;
   globals : global_type list;
-  data : segment_type list;
+  datas : segment_type list;
   elems : segment_type list;
   locals : value_type list;
   results : value_type list;
@@ -30,7 +30,7 @@ type context =
 
 let empty_context =
   { types = []; funcs = []; tables = []; memories = [];
-    globals = []; data = []; elems = [];
+    globals = []; datas = []; elems = [];
     locals = []; results = []; labels = [] }
 
 let lookup category list x =
@@ -42,7 +42,7 @@ let func (c : context) x = lookup "function" c.funcs x
 let table (c : context) x = lookup "table" c.tables x
 let memory (c : context) x = lookup "memory" c.memories x
 let global (c : context) x = lookup "global" c.globals x
-let data (c : context) x = lookup "data segment" c.data x
+let data (c : context) x = lookup "data segment" c.datas x
 let elem (c : context) x = lookup "elem segment" c.elems x
 let local (c : context) x = lookup "local" c.locals x
 let label (c : context) x = lookup "label" c.labels x
@@ -298,11 +298,6 @@ let rec check_instr (c : context) (e : instr) (s : infer_stack_type) : op_type =
     ignore (data c x);
     [I32Type; I32Type; I32Type] --> []
 
-  | DataDrop x ->
-    ignore (memory c (0l @@ e.at));
-    ignore (data c x);
-    [] --> []
-
   | MemoryCopy ->
     ignore (memory c (0l @@ e.at));
     [I32Type; I32Type; I32Type] --> []
@@ -316,14 +311,19 @@ let rec check_instr (c : context) (e : instr) (s : infer_stack_type) : op_type =
     ignore (elem c x);
     [I32Type; I32Type; I32Type] --> []
 
-  | ElemDrop x ->
+  | TableCopy ->
     ignore (table c (0l @@ e.at));
-    ignore (elem c x);
+    [I32Type; I32Type; I32Type] --> []
+
+  | DataDrop x ->
+    ignore (memory c (0l @@ e.at));
+    ignore (data c x);
     [] --> []
 
-  | TableCopy ->
+  | ElemDrop x ->
     ignore (table c (0l @@ e.at));
-    [I32Type; I32Type; I32Type] --> []
+    ignore (elem c x);
+    [] --> []
 
 and check_seq (c : context) (es : instr list) : infer_stack_type =
   match es with
@@ -431,12 +431,12 @@ let check_elemref (c : context) (el : elem) =
 
 let check_elem (c : context) (seg : table_segment) =
   match seg.it with
-  | Active {index; offset; init = (_,init)} ->
+  | Active {index; offset; init} ->
     ignore (table c index);
     check_const c offset I32Type;
     List.iter (check_elemref c) init
-  | Passive (etype,init) ->
-    List.iter (check_elemref c) init
+  | Passive {etype; data} ->
+    List.iter (check_elemref c) data
 
 let check_data (c : context) (seg : memory_segment) =
   match seg.it with
@@ -489,7 +489,7 @@ let check_export (c : context) (set : NameSet.t) (ex : export) : NameSet.t =
 
 let check_module (m : module_) =
   let
-    { types; imports; tables; memories; globals; funcs; start; elems; data;
+    { types; imports; tables; memories; globals; funcs; start; elems; datas;
       exports } = m.it
   in
   let c0 =
@@ -502,7 +502,7 @@ let check_module (m : module_) =
       tables = c0.tables @ List.map (fun tab -> tab.it.ttype) tables;
       memories = c0.memories @ List.map (fun mem -> mem.it.mtype) memories;
       elems = List.map (fun elem -> SegmentType) elems;
-      data = List.map (fun data -> SegmentType) data;
+      datas = List.map (fun data -> SegmentType) datas;
     }
   in
   let c =
@@ -513,7 +513,7 @@ let check_module (m : module_) =
   List.iter (check_table c1) tables;
   List.iter (check_memory c1) memories;
   List.iter (check_elem c1) elems;
-  List.iter (check_data c1) data;
+  List.iter (check_data c1) datas;
   List.iter (check_func c) funcs;
   check_start c start;
   ignore (List.fold_left (check_export c) NameSet.empty exports);
diff --git a/test/core/binary.wast b/test/core/binary.wast
index 711bfbc64b..3a98f9f0ad 100644
--- a/test/core/binary.wast
+++ b/test/core/binary.wast
@@ -678,7 +678,10 @@
     "\41\00"
     "\41\00"
     "\fc\08\00\00"             ;; memory.init
-    "\0b")                     ;; end
+    "\0b"
+
+    "\0b\03\01\01\00"          ;; Data section
+  )                            ;; end
   "data count section required")
 
 ;; data.drop requires a datacount section
@@ -694,7 +697,10 @@
     ;; function 0
     "\05\00"
     "\fc\09\00"                ;; data.drop
-    "\0b")                     ;; end
+    "\0b"
+
+    "\0b\03\01\01\00"          ;; Data section
+  )                            ;; end
   "data count section required")
 
 ;; passive element segment containing opcode other than ref.func or ref.null
diff --git a/test/core/bulk.wast b/test/core/bulk.wast
index fd4194c289..bb71f493d6 100644
--- a/test/core/bulk.wast
+++ b/test/core/bulk.wast
@@ -241,10 +241,10 @@
 
 (invoke "init_passive")
 (invoke "drop_passive")
-(assert_trap (invoke "drop_passive") "elements segment dropped")
-(assert_trap (invoke "init_passive") "elements segment dropped")
-(assert_trap (invoke "drop_active") "elements segment dropped")
-(assert_trap (invoke "init_active") "elements segment dropped")
+(assert_trap (invoke "drop_passive") "element segment dropped")
+(assert_trap (invoke "init_passive") "element segment dropped")
+(assert_trap (invoke "drop_active") "element segment dropped")
+(assert_trap (invoke "init_active") "element segment dropped")
 
 
 ;; table.copy
diff --git a/test/core/table_init.wast b/test/core/table_init.wast
index 6f98b25473..11012a317a 100644
--- a/test/core/table_init.wast
+++ b/test/core/table_init.wast
@@ -231,7 +231,7 @@
   (func (export "test")
     (elem.drop 2)
     ))
-(assert_trap (invoke "test") "elements segment dropped")
+(assert_trap (invoke "test") "element segment dropped")
 
 (module
   (table 30 30 funcref)
@@ -252,7 +252,7 @@
   (func (export "test")
     (table.init 2 (i32.const 12) (i32.const 1) (i32.const 1))
     ))
-(assert_trap (invoke "test") "elements segment dropped")
+(assert_trap (invoke "test") "element segment dropped")
 
 (module
   (table 30 30 funcref)
@@ -294,7 +294,7 @@
   (func (export "test")
     (elem.drop 1)
     (elem.drop 1)))
-(assert_trap (invoke "test") "elements segment dropped")
+(assert_trap (invoke "test") "element segment dropped")
 
 (module
   (table 30 30 funcref)
@@ -315,7 +315,7 @@
   (func (export "test")
     (elem.drop 1)
     (table.init 1 (i32.const 12) (i32.const 1) (i32.const 1))))
-(assert_trap (invoke "test") "elements segment dropped")
+(assert_trap (invoke "test") "element segment dropped")
 
 (module
   (table 30 30 funcref)

From c2cd260a24ef5a15880c87cd9ae7fca20296b17e Mon Sep 17 00:00:00 2001
From: Andreas Rossberg 
Date: Sat, 9 Mar 2019 10:57:09 +0100
Subject: [PATCH 071/199] Replace decoding flag with condition on free vars
 (#72)

---
 interpreter/binary/decode.ml |   9 +--
 interpreter/binary/encode.ml |   6 +-
 interpreter/syntax/free.ml   | 141 +++++++++++++++++++++++++++++++++++
 interpreter/syntax/free.mli  |  34 +++++++++
 4 files changed, 182 insertions(+), 8 deletions(-)
 create mode 100644 interpreter/syntax/free.ml
 create mode 100644 interpreter/syntax/free.mli

diff --git a/interpreter/binary/decode.ml b/interpreter/binary/decode.ml
index 0686703613..5a7aa6f5c5 100644
--- a/interpreter/binary/decode.ml
+++ b/interpreter/binary/decode.ml
@@ -5,12 +5,11 @@ type stream =
   name : string;
   bytes : string;
   pos : int ref;
-  need_data_count : bool ref;
 }
 
 exception EOS
 
-let stream name bs = {name; bytes = bs; pos = ref 0; need_data_count = ref false}
+let stream name bs = {name; bytes = bs; pos = ref 0}
 
 let len s = String.length s.bytes
 let pos s = !(s.pos)
@@ -208,9 +207,8 @@ let misc_instr s =
   | 0x08 ->
     let x = at var s in
     zero_flag s;
-    s.need_data_count := true;
     memory_init x
-  | 0x09 -> s.need_data_count := true; data_drop (at var s)
+  | 0x09 -> data_drop (at var s)
   | 0x0a -> zero_flag s; zero_flag s; memory_copy
   | 0x0b -> zero_flag s; memory_fill
   | 0x0c ->
@@ -727,7 +725,8 @@ let module_ s =
     s (len s) "function and code section have inconsistent lengths";
   require (data_count = None || data_count = Some (Lib.List32.length datas))
     s (len s) "data count and data section have inconsistent lengths";
-  require (not !(s.need_data_count) || data_count <> None)
+  require (data_count <> None ||
+    List.for_all Free.(fun f -> (func f).datas = Set.empty) func_bodies)
     s (len s) "data count section required";
   let funcs =
     List.map2 Source.(fun t f -> {f.it with ftype = t} @@ f.at)
diff --git a/interpreter/binary/encode.ml b/interpreter/binary/encode.ml
index 87abace93d..6d60a74b21 100644
--- a/interpreter/binary/encode.ml
+++ b/interpreter/binary/encode.ml
@@ -515,8 +515,8 @@ let encode m =
       section 11 (vec memory_segment) datas (datas <> [])
 
     (* Data count section *)
-    let data_count_section datas =
-      section 12 len (List.length datas) true
+    let data_count_section datas m =
+      section 12 len (List.length datas) Free.((module_ m).datas <> Set.empty)
 
     (* Module *)
 
@@ -532,7 +532,7 @@ let encode m =
       export_section m.it.exports;
       start_section m.it.start;
       elem_section m.it.elems;
-      data_count_section m.it.datas;
+      data_count_section m.it.datas m;
       code_section m.it.funcs;
       data_section m.it.datas
   end
diff --git a/interpreter/syntax/free.ml b/interpreter/syntax/free.ml
new file mode 100644
index 0000000000..46727fc634
--- /dev/null
+++ b/interpreter/syntax/free.ml
@@ -0,0 +1,141 @@
+open Source
+open Ast
+
+module Set = Set.Make(Int32)
+
+type t =
+{
+  types : Set.t;
+  globals : Set.t;
+  tables : Set.t;
+  memories : Set.t;
+  funcs : Set.t;
+  elems : Set.t;
+  datas : Set.t;
+  locals : Set.t;
+  labels : Set.t;
+}
+
+let empty : t =
+{
+  types = Set.empty;
+  globals = Set.empty;
+  tables = Set.empty;
+  memories = Set.empty;
+  funcs = Set.empty;
+  elems = Set.empty;
+  datas = Set.empty;
+  locals = Set.empty;
+  labels = Set.empty;
+}
+
+let union (s1 : t) (s2 : t) : t =
+{
+  types = Set.union s1.types s2.types;
+  globals = Set.union s1.globals s2.globals;
+  tables = Set.union s1.tables s2.tables;
+  memories = Set.union s1.memories s2.memories;
+  funcs = Set.union s1.funcs s2.funcs;
+  elems = Set.union s1.elems s2.elems;
+  datas = Set.union s1.datas s2.datas;
+  locals = Set.union s1.locals s2.locals;
+  labels = Set.union s1.labels s2.labels;
+}
+
+let types s = {empty with types = s}
+let globals s = {empty with globals = s}
+let tables s = {empty with tables = s}
+let memories s = {empty with memories = s}
+let funcs s = {empty with funcs = s}
+let elems s = {empty with elems = s}
+let datas s = {empty with datas = s}
+let locals s = {empty with locals = s}
+let labels s = {empty with labels = s}
+
+let var x = Set.singleton x.it
+let zero = Set.singleton 0l
+let shift s = Set.map (Int32.add (-1l)) (Set.remove 0l s)
+
+let (++) = union
+let list free xs = List.fold_left union empty (List.map free xs)
+
+let rec instr (e : instr) =
+  match e.it with
+  | Unreachable | Nop | Drop | Select -> empty
+  | Const _ | Test _ | Compare _ | Unary _ | Binary _ | Convert _ -> empty
+  | Block (_, es) | Loop (_, es) -> block es
+  | If (_, es1, es2) -> block es1 ++ block es2
+  | Br x | BrIf x -> labels (var x)
+  | BrTable (xs, x) -> list (fun x -> labels (var x)) (x::xs)
+  | Return -> empty
+  | Call x -> funcs (var x)
+  | CallIndirect x -> types (var x) ++ tables zero
+  | LocalGet x | LocalSet x | LocalTee x -> locals (var x)
+  | GlobalGet x | GlobalSet x -> globals (var x)
+  | Load _ | Store _ | MemorySize | MemoryGrow | MemoryCopy | MemoryFill ->
+    memories zero
+  | MemoryInit x -> memories zero ++ datas (var x)
+  | TableCopy -> tables zero
+  | TableInit x -> tables zero ++ elems (var x)
+  | DataDrop x -> datas (var x)
+  | ElemDrop x -> elems (var x)
+
+and block (es : instr list) =
+  let free = list instr es in {free with labels = shift free.labels}
+
+let const (c : const) = block c.it
+
+let global (g : global) = const g.it.value
+let func (f : func) = {(block f.it.body) with locals = Set.empty}
+let table (t : table) = empty
+let memory (m : memory) = empty
+
+let elem (e : elem) =
+  match e.it with
+  | Null -> empty
+  | Func x -> funcs (var x)
+
+let table_segment (s : table_segment) =
+  match s.it with
+  | Active {index; offset; init} ->
+    tables (var index) ++ const offset ++ list elem init
+  | Passive {etype; data} -> list elem data
+
+let memory_segment (s : memory_segment) =
+  match s.it with
+  | Active {index; offset; init} -> memories (var index) ++ const offset
+  | Passive {etype; data} -> empty
+
+let type_ (t : type_) = empty
+
+let export_desc (d : export_desc) =
+  match d.it with
+  | FuncExport x -> funcs (var x)
+  | TableExport x -> tables (var x)
+  | MemoryExport x -> memories (var x)
+  | GlobalExport x -> globals (var x)
+
+let import_desc (d : import_desc) =
+  match d.it with
+  | FuncImport x -> types (var x)
+  | TableImport tt -> empty
+  | MemoryImport mt -> empty
+  | GlobalImport gt -> empty
+
+let export (e : export) = export_desc e.it.edesc
+let import (i : import) = import_desc i.it.idesc
+
+let start (s : var option) =
+  funcs (Lib.Option.get (Lib.Option.map var s) Set.empty)
+
+let module_ (m : module_) =
+  list type_ m.it.types ++
+  list global m.it.globals ++
+  list table m.it.tables ++
+  list memory m.it.memories ++
+  list func m.it.funcs ++
+  start m.it.start ++
+  list table_segment m.it.elems ++
+  list memory_segment m.it.datas ++
+  list import m.it.imports ++
+  list export m.it.exports
diff --git a/interpreter/syntax/free.mli b/interpreter/syntax/free.mli
new file mode 100644
index 0000000000..b7ea2d7480
--- /dev/null
+++ b/interpreter/syntax/free.mli
@@ -0,0 +1,34 @@
+module Set : Set.S with type elt = int32
+
+type t =
+{
+  types : Set.t;
+  globals : Set.t;
+  tables : Set.t;
+  memories : Set.t;
+  funcs : Set.t;
+  elems : Set.t;
+  datas : Set.t;
+  locals : Set.t;
+  labels : Set.t;
+}
+
+val empty : t
+val union : t -> t -> t
+
+val instr : Ast.instr -> t
+val block : Ast.instr list -> t
+val const : Ast.const -> t
+
+val type_ : Ast.type_ -> t
+val global : Ast.global -> t
+val func : Ast.func -> t
+val table : Ast.table -> t
+val memory : Ast.memory -> t
+val table_segment : Ast.table_segment -> t
+val memory_segment : Ast.memory_segment -> t
+val export : Ast.export -> t
+val import : Ast.import -> t
+val start : Ast.var option -> t
+
+val module_ : Ast.module_ -> t

From d9ebd33c3bc1e1c13ce9645b20013f5cfd372b16 Mon Sep 17 00:00:00 2001
From: Andreas Rossberg 
Date: Sat, 30 Mar 2019 08:59:07 +0100
Subject: [PATCH 072/199] [interpreter] Fix JS generator (#34)

* Add missing eq_ref
* Fix export index computation
* Remove bogus test
---
 interpreter/script/js.ml   | 13 +++++++++++--
 test/core/ref_is_null.wast |  1 -
 2 files changed, 11 insertions(+), 3 deletions(-)

diff --git a/interpreter/script/js.ml b/interpreter/script/js.ml
index ee56e82219..469140c0f8 100644
--- a/interpreter/script/js.ml
+++ b/interpreter/script/js.ml
@@ -21,11 +21,15 @@ let harness =
   "function is_funcref(x) {\n" ^
   "  return typeof x === \"function\" ? 1 : 0;\n" ^
   "}\n" ^
+  "function eq_ref(x, y) {\n" ^
+  "  return x === y ? 1 : 0;\n" ^
+  "}\n" ^
   "\n" ^
   "let spectest = {\n" ^
   "  hostref: hostref,\n" ^
   "  is_hostref: is_hostref,\n" ^
   "  is_funcref: is_funcref,\n" ^
+  "  eq_ref: eq_ref,\n" ^
   "  print: console.log.bind(console),\n" ^
   "  print_i32: console.log.bind(console),\n" ^
   "  print_i32_f32: console.log.bind(console),\n" ^
@@ -83,7 +87,7 @@ let harness =
   "}\n" ^
   "\n" ^
   "function exports(instance) {\n" ^
-  "  return {module: instance.exports, host: {ref: hostref}};\n" ^
+  "  return {module: instance.exports, spectest: spectest};\n" ^
   "}\n" ^
   "\n" ^
   "function run(action) {\n" ^
@@ -327,7 +331,6 @@ let assert_return_func ts at =
 let wrap item_name wrap_action wrap_assertion at =
   let itypes, idesc, action = wrap_action at in
   let locals, assertion = wrap_assertion at in
-  let item = Lib.List32.length itypes @@ at in
   let types =
     (FuncType ([], []) @@ at) ::
     (FuncType ([NumType I32Type], [RefType AnyRefType]) @@ at) ::
@@ -347,6 +350,12 @@ let wrap item_name wrap_action wrap_assertion at =
       {module_name = Utf8.decode "spectest"; item_name = Utf8.decode "eq_ref";
        idesc = FuncImport (4l @@ at) @@ at} @@ at ]
   in
+  let item =
+    List.fold_left
+      (fun i im ->
+        match im.it.idesc.it with FuncImport _ -> Int32.add i 1l | _ -> i
+      ) 0l imports @@ at
+  in
   let edesc = FuncExport item @@ at in
   let exports = [{name = Utf8.decode "run"; edesc} @@ at] in
   let body =
diff --git a/test/core/ref_is_null.wast b/test/core/ref_is_null.wast
index ca4bddbae0..7edc8e2832 100644
--- a/test/core/ref_is_null.wast
+++ b/test/core/ref_is_null.wast
@@ -30,7 +30,6 @@
 (assert_return (invoke "funcref" (ref.null)) (i32.const 1))
 
 (assert_return (invoke "anyref" (ref.host 1)) (i32.const 0))
-(assert_return (invoke "funcref" (ref.host 1)) (i32.const 0))
 
 (invoke "init" (ref.host 0))
 

From 726d7ec78585d022c29c0677657b823c9b781177 Mon Sep 17 00:00:00 2001
From: Andreas Rossberg 
Date: Sun, 31 Mar 2019 00:48:51 +0100
Subject: [PATCH 073/199] [spec/interpreter] Rename elem/data.drop; update
 README; reorder (#75)

* Rename elem/data.drop
* Reorder bulk instructions
* Rename interpreter AST ref constructors to match reftype repo
* Update interpreter README
---
 document/core/binary/instructions.rst |  48 ++++----
 document/core/syntax/instructions.rst |  68 +++++------
 document/core/text/instructions.rst   |  44 +++----
 document/core/util/macros.def         |  14 +--
 document/core/valid/instructions.rst  | 160 +++++++++++++-------------
 interpreter/README.md                 |   7 ++
 interpreter/binary/decode.ml          |  51 ++++----
 interpreter/binary/encode.ml          |  24 ++--
 interpreter/exec/eval.ml              | 108 ++++++++---------
 interpreter/syntax/ast.ml             |  18 +--
 interpreter/syntax/free.ml            |   4 +-
 interpreter/syntax/operators.ml       |  23 ++--
 interpreter/text/arrange.ml           |  22 ++--
 interpreter/text/lexer.mll            |  35 +++---
 interpreter/text/parser.mly           |  37 +++---
 interpreter/valid/valid.ml            |  70 ++++++-----
 16 files changed, 371 insertions(+), 362 deletions(-)

diff --git a/document/core/binary/instructions.rst b/document/core/binary/instructions.rst
index 010462dd72..3321dbf879 100644
--- a/document/core/binary/instructions.rst
+++ b/document/core/binary/instructions.rst
@@ -110,6 +110,27 @@ Variable Instructions
    \end{array}
 
 
+Table Instructions
+~~~~~~~~~~~~~~~~~~
+
+Each variant of :ref:`table instruction ` is encoded with a different byte code.
+
+.. _binary-table.copy:
+.. _binary-table.init:
+.. _binary-elem.drop:
+
+.. math::
+   \begin{array}{llclll}
+   \production{instruction} & \Binstr &::=& \dots \\ &&|&
+     \hex{FC}~\hex{0C}~~\hex{00}~x{:}\Belemidx &\Rightarrow& \TABLEINIT~x \\ &&|&
+     \hex{FC}~\hex{0D}~~x{:}\Belemidx &\Rightarrow& \ELEMDROP~x \\ &&|&
+     \hex{FC}~\hex{0E}~~\hex{00}~~\hex{00} &\Rightarrow& \TABLECOPY \\
+   \end{array}
+
+.. note::
+   In future versions of WebAssembly, the additional zero bytes occurring in the encoding of the |TABLECOPY| instruction may be used to index additional tables.
+
+
 .. index:: memory instruction, memory index
    pair: binary format; instruction
 .. _binary-instr-memory:
@@ -126,10 +147,10 @@ Each variant of :ref:`memory instruction ` is encoded with
 .. _binary-storen:
 .. _binary-memory.size:
 .. _binary-memory.grow:
-.. _binary-memory.init:
-.. _binary-memory.drop:
-.. _binary-memory.copy:
 .. _binary-memory.fill:
+.. _binary-memory.copy:
+.. _binary-memory.init:
+.. _binary-data.drop:
 
 .. math::
    \begin{array}{llclll}
@@ -171,27 +192,6 @@ Each variant of :ref:`memory instruction ` is encoded with
    In future versions of WebAssembly, the additional zero bytes occurring in the encoding of the |MEMORYSIZE|, |MEMORYGROW|, |MEMORYCOPY|, and |MEMORYFILL| instructions may be used to index additional memories.
 
 
-Table Instructions
-~~~~~~~~~~~~~~~~~~
-
-Each variant of :ref:`table instruction ` is encoded with a different byte code.
-
-.. _binary-table.init:
-.. _binary-table.drop:
-.. _binary-table.copy:
-
-.. math::
-   \begin{array}{llclll}
-   \production{instruction} & \Binstr &::=& \dots \\ &&|&
-     \hex{FC}~\hex{0C}~~\hex{00}~x{:}\Belemidx &\Rightarrow& \TABLEINIT~x \\ &&|&
-     \hex{FC}~\hex{0D}~~x{:}\Belemidx &\Rightarrow& \TABLEDROP~x \\ &&|&
-     \hex{FC}~\hex{0E}~~\hex{00}~~\hex{00} &\Rightarrow& \TABLECOPY \\
-   \end{array}
-
-.. note::
-   In future versions of WebAssembly, the additional zero bytes occurring in the encoding of the |TABLECOPY| instruction may be used to index additional tables.
-
-
 .. index:: numeric instruction
    pair: binary format; instruction
 .. _binary-instr-numeric:
diff --git a/document/core/syntax/instructions.rst b/document/core/syntax/instructions.rst
index 7470c7354c..ecf6235fed 100644
--- a/document/core/syntax/instructions.rst
+++ b/document/core/syntax/instructions.rst
@@ -213,6 +213,34 @@ These instructions get or set the values of variables, respectively.
 The |LOCALTEE| instruction is like |LOCALSET| but also returns its argument.
 
 
+.. index:: ! table instruction, table, table index
+   pair: abstract syntax; instruction
+.. _syntax-instr-table:
+
+Table Instructions
+~~~~~~~~~~~~~~~~~~
+
+Instructions in this group are concerned with tables :ref:`table `.
+
+.. math::
+   \begin{array}{llcl}
+   \production{instruction} & \instr &::=&
+     \dots \\&&|&
+     \TABLECOPY \\&&|&
+     \TABLEINIT~\elemidx \\&&|&
+     \ELEMDROP~\elemidx \\
+   \end{array}
+
+The |TABLECOPY| instruction copies elements from a source table region to a possibly overlapping destination region.
+The |TABLEINIT| instruction copies elements from a :ref:`passive element segment ` into a table.
+The |ELEMDROP| instruction prevents further use of a passive element segment. This instruction is intended to be used as an optimization hint. After an element segment is dropped its elements can no longer be retrieved, so the memory used by this segment may be freed.
+
+.. note::
+   In the current version of WebAssembly,
+   all table instructions implicitly operate on :ref:`table ` :ref:`index ` :math:`0`.
+   This restriction may be lifted in future versions.
+
+
 .. index:: ! memory instruction, memory, memory index, page size, little endian, trap
    pair: abstract syntax; instruction
 .. _syntax-loadn:
@@ -243,10 +271,10 @@ Instructions in this group are concerned with linear :ref:`memory `.
      \K{i64.}\STORE\K{32}~\memarg \\&&|&
      \MEMORYSIZE \\&&|&
      \MEMORYGROW \\&&|&
-     \MEMORYINIT~\dataidx \\&&|&
-     \MEMORYDROP~\dataidx \\&&|&
+     \MEMORYFILL \\&&|&
      \MEMORYCOPY \\&&|&
-     \MEMORYFILL \\
+     \MEMORYINIT~\dataidx \\&&|&
+     \DATADROP~\dataidx \\
    \end{array}
 
 Memory is accessed with |LOAD| and |STORE| instructions for the different :ref:`value types `.
@@ -265,10 +293,10 @@ The |MEMORYSIZE| instruction returns the current size of a memory.
 The |MEMORYGROW| instruction grows memory by a given delta and returns the previous size, or :math:`-1` if enough memory cannot be allocated.
 Both instructions operate in units of :ref:`page size `.
 
-The |MEMORYINIT| instruction copies data from a :ref:`passive data segment ` into a memory.
-The |MEMORYDROP| instruction prevents further use of a passive data segment. This instruction is intended to be used as an optimization hint. After a data segment is dropped its data can no longer be retrieved, so the memory used by this segment may be freed.
-The |MEMORYCOPY| instruction copies data from a source memory region to a possibly overlapping destination region.
 The |MEMORYFILL| instruction sets all values in a region to a given byte.
+The |MEMORYCOPY| instruction copies data from a source memory region to a possibly overlapping destination region.
+The |MEMORYINIT| instruction copies data from a :ref:`passive data segment ` into a memory.
+The |DATADROP| instruction prevents further use of a passive data segment. This instruction is intended to be used as an optimization hint. After a data segment is dropped its data can no longer be retrieved, so the memory used by this segment may be freed.
 
 .. note::
    In the current version of WebAssembly,
@@ -276,34 +304,6 @@ The |MEMORYFILL| instruction sets all values in a region to a given byte.
    This restriction may be lifted in future versions.
 
 
-.. index:: ! table instruction, table, table index
-   pair: abstract syntax; instruction
-.. _syntax-instr-table:
-
-Table Instructions
-~~~~~~~~~~~~~~~~~~
-
-Instructions in this group are concerned with tables :ref:`table `.
-
-.. math::
-   \begin{array}{llcl}
-   \production{instruction} & \instr &::=&
-     \dots \\&&|&
-     \TABLEINIT~\elemidx \\&&|&
-     \TABLEDROP~\elemidx \\&&|&
-     \TABLECOPY \\
-   \end{array}
-
-The |TABLEINIT| instruction copies elements from a :ref:`passive element segment ` into a table.
-The |TABLEDROP| instruction prevents further use of a passive element segment. This instruction is intended to be used as an optimization hint. After an element segment is dropped its elements can no longer be retrieved, so the memory used by this segment may be freed.
-The |TABLECOPY| instruction copies elements from a source table region to a possibly overlapping destination region.
-
-.. note::
-   In the current version of WebAssembly,
-   all table instructions implicitly operate on :ref:`table ` :ref:`index ` :math:`0`.
-   This restriction may be lifted in future versions.
-
-
 .. index:: ! control instruction, ! structured control, ! label, ! block, ! branch, ! unwinding, result type, label index, function index, type index, vector, trap, function, table, function type
    pair: abstract syntax; instruction
 .. _syntax-nop:
diff --git a/document/core/text/instructions.rst b/document/core/text/instructions.rst
index c94b77009c..b8e0ff4043 100644
--- a/document/core/text/instructions.rst
+++ b/document/core/text/instructions.rst
@@ -161,6 +161,22 @@ Variable Instructions
    \end{array}
 
 
+Table Instructions
+~~~~~~~~~~~~~~~~~~
+
+.. _text-table.copy:
+.. _text-table.init:
+.. _text-elem.drop:
+
+.. math::
+   \begin{array}{llcllll}
+   \production{instruction} & \Tplaininstr_I &::=& \dots \\ &&|&
+     \text{table.copy} &\Rightarrow& \TABLECOPY \\ &&|&
+     \text{table.init}~~x{:}\Telemidx_I &\Rightarrow& \TABLEINIT~x \\ &&|&
+     \text{elem.drop}~~x{:}\Telemidx_I &\Rightarrow& \ELEMDROP~x \\
+   \end{array}
+
+
 .. index:: memory instruction, memory index
    pair: text format; instruction
 .. _text-instr-memory:
@@ -175,10 +191,10 @@ Memory Instructions
 .. _text-storen:
 .. _text-memory.size:
 .. _text-memory.grow:
-.. _text-memory.init:
-.. _text-memory.drop:
-.. _text-memory.copy:
 .. _text-memory.fill:
+.. _text-memory.copy:
+.. _text-memory.init:
+.. _text-data.drop:
 
 The offset and alignment immediates to memory instructions are optional.
 The offset defaults to :math:`\T{0}`, the alignment to the storage size of the respective memory access, which is its *natural alignment*.
@@ -220,26 +236,10 @@ Lexically, an |Toffset| or |Talign| phrase is considered a single :ref:`keyword
      \text{i64.store32}~~m{:}\Tmemarg_4 &\Rightarrow& \I64.\STORE\K{32}~m \\ &&|&
      \text{memory.size} &\Rightarrow& \MEMORYSIZE \\ &&|&
      \text{memory.grow} &\Rightarrow& \MEMORYGROW \\ &&|&
-     \text{memory.init}~~x{:}\Tdataidx_I &\Rightarrow& \MEMORYINIT~x \\ &&|&
-     \text{memory.drop}~~x{:}\Tdataidx_I &\Rightarrow& \MEMORYDROP~x \\ &&|&
+     \text{memory.fill} &\Rightarrow& \MEMORYFILL \\ &&|&
      \text{memory.copy} &\Rightarrow& \MEMORYCOPY \\ &&|&
-     \text{memory.fill} &\Rightarrow& \MEMORYFILL \\
-   \end{array}
-
-
-Table Instructions
-~~~~~~~~~~~~~~~~~~
-
-.. _text-table.init:
-.. _text-table.drop:
-.. _text-table.copy:
-
-.. math::
-   \begin{array}{llcllll}
-   \production{instruction} & \Tplaininstr_I &::=& \dots \\ &&|&
-     \text{table.init}~~x{:}\Telemidx_I &\Rightarrow& \TABLEINIT~x \\ &&|&
-     \text{table.drop}~~x{:}\Telemidx_I &\Rightarrow& \TABLEDROP~x \\ &&|&
-     \text{table.copy} &\Rightarrow& \TABLECOPY \\
+     \text{memory.init}~~x{:}\Tdataidx_I &\Rightarrow& \MEMORYINIT~x \\ &&|&
+     \text{data.drop}~~x{:}\Tdataidx_I &\Rightarrow& \DATADROP~x \\
    \end{array}
 
 
diff --git a/document/core/util/macros.def b/document/core/util/macros.def
index dca776786a..ba53ce142c 100644
--- a/document/core/util/macros.def
+++ b/document/core/util/macros.def
@@ -329,18 +329,18 @@
 .. |GLOBALGET| mathdef:: \xref{syntax/instructions}{syntax-instr-variable}{\K{global.get}}
 .. |GLOBALSET| mathdef:: \xref{syntax/instructions}{syntax-instr-variable}{\K{global.set}}
 
+.. |TABLECOPY| mathdef:: \xref{syntax/instructions}{syntax-instr-table}{\K{table.copy}}
+.. |TABLEINIT| mathdef:: \xref{syntax/instructions}{syntax-instr-table}{\K{table.init}}
+.. |ELEMDROP| mathdef:: \xref{syntax/instructions}{syntax-instr-table}{\K{elem.drop}}
+
 .. |LOAD| mathdef:: \xref{syntax/instructions}{syntax-instr-memory}{\K{load}}
 .. |STORE| mathdef:: \xref{syntax/instructions}{syntax-instr-memory}{\K{store}}
 .. |MEMORYSIZE| mathdef:: \xref{syntax/instructions}{syntax-instr-memory}{\K{memory.size}}
 .. |MEMORYGROW| mathdef:: \xref{syntax/instructions}{syntax-instr-memory}{\K{memory.grow}}
-.. |MEMORYINIT| mathdef:: \xref{syntax/instructions}{syntax-instr-memory}{\K{memory.init}}
-.. |MEMORYDROP| mathdef:: \xref{syntax/instructions}{syntax-instr-memory}{\K{memory.drop}}
-.. |MEMORYCOPY| mathdef:: \xref{syntax/instructions}{syntax-instr-memory}{\K{memory.copy}}
 .. |MEMORYFILL| mathdef:: \xref{syntax/instructions}{syntax-instr-memory}{\K{memory.fill}}
-
-.. |TABLEINIT| mathdef:: \xref{syntax/instructions}{syntax-instr-table}{\K{table.init}}
-.. |TABLEDROP| mathdef:: \xref{syntax/instructions}{syntax-instr-table}{\K{table.drop}}
-.. |TABLECOPY| mathdef:: \xref{syntax/instructions}{syntax-instr-table}{\K{table.copy}}
+.. |MEMORYCOPY| mathdef:: \xref{syntax/instructions}{syntax-instr-memory}{\K{memory.copy}}
+.. |MEMORYINIT| mathdef:: \xref{syntax/instructions}{syntax-instr-memory}{\K{memory.init}}
+.. |DATADROP| mathdef:: \xref{syntax/instructions}{syntax-instr-memory}{\K{data.drop}}
 
 .. |CONST| mathdef:: \xref{syntax/instructions}{syntax-instr-numeric}{\K{const}}
 .. |EQZ| mathdef:: \xref{syntax/instructions}{syntax-instr-numeric}{\K{eqz}}
diff --git a/document/core/valid/instructions.rst b/document/core/valid/instructions.rst
index 2545f1e30f..c2ff7c7f0e 100644
--- a/document/core/valid/instructions.rst
+++ b/document/core/valid/instructions.rst
@@ -298,6 +298,69 @@ Variable Instructions
    }
 
 
+.. index:: table instruction, table index, context
+   pair: validation; instruction
+   single: abstract syntax; instruction
+.. _valid-instr-table:
+
+Table Instructions
+~~~~~~~~~~~~~~~~~~
+
+.. _valid-table.copy:
+
+:math:`\TABLECOPY`
+.....................
+
+* The table :math:`C.\CTABLES[0]` must be defined in the context.
+
+* Then the instruction is valid with type :math:`[\I32~\I32~\I32] \to []`.
+
+.. math::
+   \frac{
+     C.\CTABLES[0] = \tabletype
+   }{
+     C \vdashinstr \TABLECOPY : [\I32~\I32~\I32] \to []
+   }
+
+
+.. _valid-table.init:
+
+:math:`\TABLEINIT~x`
+.....................
+
+* The table :math:`C.\CTABLES[0]` must be defined in the context.
+
+* The element segment :math:`C.\CELEM[x]` must be defined in the context.
+
+* Then the instruction is valid with type :math:`[\I32~\I32~\I32] \to []`.
+
+.. math::
+   \frac{
+     C.\CTABLES[0] = \tabletype
+     \qquad
+     C.\CELEM[x] = \segtype
+   }{
+     C \vdashinstr \TABLEINIT~x : [\I32~\I32~\I32] \to []
+   }
+
+
+.. _valid-elem.drop:
+
+:math:`\ELEMDROP~x`
+...................
+
+* The element segment :math:`C.\CELEM[x]` must be defined in the context.
+
+* Then the instruction is valid with type :math:`[] \to []`.
+
+.. math::
+   \frac{
+     C.\CELEM[x] = \segtype
+   }{
+     C \vdashinstr \DATADROP~x : [] \to []
+   }
+
+
 .. index:: memory instruction, memory index, context
    pair: validation; instruction
    single: abstract syntax; instruction
@@ -423,43 +486,20 @@ Memory Instructions
    }
 
 
-.. _valid-memory.init:
+.. _valid-memory.fill:
 
-:math:`\MEMORYINIT~x`
+:math:`\MEMORYFILL`
 .....................
 
 * The memory :math:`C.\CMEMS[0]` must be defined in the context.
 
-* The data segment :math:`C.\CDATA[x]` must be defined in the context.
-
 * Then the instruction is valid with type :math:`[\I32~\I32~\I32] \to []`.
 
 .. math::
    \frac{
      C.\CMEMS[0] = \memtype
-     \qquad
-     C.\CDATA[x] = \segtype
-   }{
-     C \vdashinstr \MEMORYINIT~x : [\I32~\I32~\I32] \to []
-   }
-
-
-.. _valid-memory.drop:
-
-:math:`\MEMORYDROP~x`
-.....................
-
-* The data segment :math:`C.\CDATA[x]` must be defined in the context.
-
-* The :ref:`segment type ` :math:`C.\CDATA[x]` must be |SPASSIVE|.
-
-* Then the instruction is valid with type :math:`[] \to []`.
-
-.. math::
-   \frac{
-     C.\CDATA[x] = \segtype
    }{
-     C \vdashinstr \MEMORYDROP~x : [] \to []
+     C \vdashinstr \MEMORYFILL : [\I32~\I32~\I32] \to []
    }
 
 
@@ -480,83 +520,43 @@ Memory Instructions
    }
 
 
-.. _valid-memory.fill:
+.. _valid-memory.init:
 
-:math:`\MEMORYFILL`
+:math:`\MEMORYINIT~x`
 .....................
 
 * The memory :math:`C.\CMEMS[0]` must be defined in the context.
 
-* Then the instruction is valid with type :math:`[\I32~\I32~\I32] \to []`.
-
-.. math::
-   \frac{
-     C.\CMEMS[0] = \memtype
-   }{
-     C \vdashinstr \MEMORYFILL : [\I32~\I32~\I32] \to []
-   }
-
-
-.. index:: table instruction, table index, context
-   pair: validation; instruction
-   single: abstract syntax; instruction
-.. _valid-instr-table:
-
-Table Instructions
-~~~~~~~~~~~~~~~~~~
-
-.. _valid-table.init:
-
-:math:`\TABLEINIT~x`
-.....................
-
-* The table :math:`C.\CTABLES[0]` must be defined in the context.
-
-* The element segment :math:`C.\CELEM[x]` must be defined in the context.
+* The data segment :math:`C.\CDATA[x]` must be defined in the context.
 
 * Then the instruction is valid with type :math:`[\I32~\I32~\I32] \to []`.
 
 .. math::
    \frac{
-     C.\CTABLES[0] = \tabletype
+     C.\CMEMS[0] = \memtype
      \qquad
-     C.\CELEM[x] = \segtype
+     C.\CDATA[x] = \segtype
    }{
-     C \vdashinstr \TABLEINIT~x : [\I32~\I32~\I32] \to []
+     C \vdashinstr \MEMORYINIT~x : [\I32~\I32~\I32] \to []
    }
 
 
-.. _valid-table.drop:
+.. _valid-data.drop:
 
-:math:`\TABLEDROP~x`
-.....................
-
-* The element segment :math:`C.\CELEM[x]` must be defined in the context.
-
-* Then the instruction is valid with type :math:`[] \to []`.
-
-.. math::
-   \frac{
-     C.\CELEM[x] = \segtype
-   }{
-     C \vdashinstr \TABLEDROP~x : [] \to []
-   }
-
-
-.. _valid-table.copy:
+:math:`\DATADROP~x`
+...................
 
-:math:`\TABLECOPY`
-.....................
+* The data segment :math:`C.\CDATA[x]` must be defined in the context.
 
-* The table :math:`C.\CTABLES[0]` must be defined in the context.
+* The :ref:`segment type ` :math:`C.\CDATA[x]` must be |SPASSIVE|.
 
-* Then the instruction is valid with type :math:`[\I32~\I32~\I32] \to []`.
+* Then the instruction is valid with type :math:`[] \to []`.
 
 .. math::
    \frac{
-     C.\CTABLES[0] = \tabletype
+     C.\CDATA[x] = \segtype
    }{
-     C \vdashinstr \TABLECOPY : [\I32~\I32~\I32] \to []
+     C \vdashinstr \DATADROP~x : [] \to []
    }
 
 
diff --git a/interpreter/README.md b/interpreter/README.md
index 1cac7a7592..32acc4b90c 100644
--- a/interpreter/README.md
+++ b/interpreter/README.md
@@ -223,10 +223,17 @@ op:
   local.tee 
   global.get 
   global.set 
+  table.copy
+  table.init 
+  elem.drop 
   .load((8|16|32)_)? ? ?
   .store(8|16|32)? ? ?
   memory.size
   memory.grow
+  memory.fill
+  memory.copy
+  memory.init 
+  data.drop 
   .const 
   .
   .
diff --git a/interpreter/binary/decode.ml b/interpreter/binary/decode.ml
index 5a7aa6f5c5..65208bc8cb 100644
--- a/interpreter/binary/decode.ml
+++ b/interpreter/binary/decode.ml
@@ -47,6 +47,8 @@ let skip n = guard (skip n)
 
 let expect b s msg = require (guard get s = b) s (pos s - 1) msg
 let illegal s pos b = error s pos ("illegal opcode " ^ string_of_byte b)
+let illegal2 s pos b1 b2 =
+  error s pos ("illegal opcode " ^ string_of_byte b1 ^ " " ^ string_of_byte b2)
 
 let at f s =
   let left = pos s in
@@ -201,25 +203,6 @@ let memop s =
   let offset = vu32 s in
   Int32.to_int align, offset
 
-let misc_instr s =
-  let pos = pos s in
-  match op s with
-  | 0x08 ->
-    let x = at var s in
-    zero_flag s;
-    memory_init x
-  | 0x09 -> data_drop (at var s)
-  | 0x0a -> zero_flag s; zero_flag s; memory_copy
-  | 0x0b -> zero_flag s; memory_fill
-  | 0x0c ->
-    let x = at var s in
-    zero_flag s;
-    table_init x
-  | 0x0d -> elem_drop (at var s)
-  | 0x0e -> zero_flag s; zero_flag s; table_copy
-
-  | b -> illegal s pos b
-
 let rec instr s =
   let pos = pos s in
   match op s with
@@ -264,8 +247,7 @@ let rec instr s =
   | 0x10 -> call (at var s)
   | 0x11 ->
     let x = at var s in
-    zero_flag s;
-    call_indirect x
+    zero_flag s; call_indirect x
 
   | 0x12 | 0x13 | 0x14 | 0x15 | 0x16 | 0x17 | 0x18 | 0x19 as b -> illegal s pos b
 
@@ -448,7 +430,26 @@ let rec instr s =
   | 0xbe -> f32_reinterpret_i32
   | 0xbf -> f64_reinterpret_i64
 
-  | 0xfc -> misc_instr s
+  | 0xfc as b1 ->
+    (match op s with
+    | 0x00 | 0x01 | 0x02 | 0x03 | 0x04 | 0x05 | 0x06 | 0x07 as b2 ->
+      illegal2 s pos b1 b2
+
+    | 0x08 ->
+      let x = at var s in
+      zero_flag s; memory_init x
+    | 0x09 -> data_drop (at var s)
+    | 0x0a -> zero_flag s; zero_flag s; memory_copy
+    | 0x0b -> zero_flag s; memory_fill
+
+    | 0x0c ->
+      let x = at var s in
+      zero_flag s; table_init x
+    | 0x0d -> elem_drop (at var s)
+    | 0x0e -> zero_flag s; zero_flag s; table_copy
+
+    | b2 -> illegal2 s pos b1 b2
+    )
 
   | b -> illegal s pos b
 
@@ -630,15 +631,15 @@ let segment active passive s =
   | _ -> error s (pos s - 1) "invalid segment kind"
 
 let active_elem s =
-  Func (at var s)
+  ref_func (at var s)
 
 let passive_elem s =
   match u8 s with
-  | 0xd0 -> end_ s; Null
+  | 0xd0 -> end_ s; ref_null
   | 0xd2 ->
     let x = at var s in
     end_ s;
-    Func x
+    ref_func x
   | _ -> error s (pos s - 1) "invalid elem"
 
 let active_elem_segment s =
diff --git a/interpreter/binary/encode.ml b/interpreter/binary/encode.ml
index 6d60a74b21..955628a01b 100644
--- a/interpreter/binary/encode.ml
+++ b/interpreter/binary/encode.ml
@@ -167,6 +167,10 @@ let encode m =
       | GlobalGet x -> op 0x23; var x
       | GlobalSet x -> op 0x24; var x
 
+      | TableCopy -> op 0xfc; op 0x0e; u8 0x00; u8 0x00
+      | TableInit x -> op 0xfc; op 0x0c; var x; u8 0x00
+      | ElemDrop x -> op 0xfc; op 0x0d; var x
+
       | Load ({ty = I32Type; sz = None; _} as mo) -> op 0x28; memop mo
       | Load ({ty = I64Type; sz = None; _} as mo) -> op 0x29; memop mo
       | Load ({ty = F32Type; sz = None; _} as mo) -> op 0x2a; memop mo
@@ -210,6 +214,10 @@ let encode m =
 
       | MemorySize -> op 0x3f; u8 0x00
       | MemoryGrow -> op 0x40; u8 0x00
+      | MemoryFill -> op 0xfc; op 0x0b; u8 0x00
+      | MemoryCopy -> op 0xfc; op 0x0a; u8 0x00; u8 0x00
+      | MemoryInit x -> op 0xfc; op 0x08; var x; u8 0x00
+      | DataDrop x -> op 0xfc; op 0x09; var x
 
       | Const {it = I32 c; _} -> op 0x41; vs32 c
       | Const {it = I64 c; _} -> op 0x42; vs64 c
@@ -363,14 +371,6 @@ let encode m =
       | Convert (F64 F64Op.DemoteF64) -> assert false
       | Convert (F64 F64Op.ReinterpretInt) -> op 0xbf
 
-      | MemoryInit x -> op 0xfc; op 0x08; var x; u8 0x00
-      | DataDrop x -> op 0xfc; op 0x09; var x
-      | MemoryCopy -> op 0xfc; op 0x0a; u8 0x00; u8 0x00
-      | MemoryFill -> op 0xfc; op 0x0b; u8 0x00
-      | TableInit x -> op 0xfc; op 0x0c; var x; u8 0x00
-      | ElemDrop x -> op 0xfc; op 0x0d; var x
-      | TableCopy -> op 0xfc; op 0x0e; u8 0x00; u8 0x00
-
     let const c =
       list instr c.it; end_ ()
 
@@ -491,13 +491,13 @@ let encode m =
 
     let active_elem el =
       match el.it with
-      | Null -> assert false
-      | Func x -> var x
+      | RefNull -> assert false
+      | RefFunc x -> var x
 
     let passive_elem el =
       match el.it with
-      | Null -> u8 0xd0; end_ ()
-      | Func x -> u8 0xd2; var x; end_ ()
+      | RefNull -> u8 0xd0; end_ ()
+      | RefFunc x -> u8 0xd2; var x; end_ ()
 
     let table_segment seg =
       let active init = vec active_elem init in
diff --git a/interpreter/exec/eval.ml b/interpreter/exec/eval.ml
index fb6f134b4e..28843e7321 100644
--- a/interpreter/exec/eval.ml
+++ b/interpreter/exec/eval.ml
@@ -198,6 +198,27 @@ let rec step (c : config) : config =
         with Global.NotMutable -> Crash.error e.at "write to immutable global"
            | Global.Type -> Crash.error e.at "type mismatch at global write")
 
+      | TableCopy, I32 n :: I32 s :: I32 d :: vs' ->
+        let tab = table frame.inst (0l @@ e.at) in
+        (try Table.copy tab d s n; vs', []
+        with exn -> vs', [Trapping (table_error e.at exn) @@ e.at])
+
+      | TableInit x, I32 n :: I32 s :: I32 d :: vs' ->
+        let tab = table frame.inst (0l @@ e.at) in
+        (match !(elem frame.inst x) with
+        | Some es ->
+          (try Table.init tab es d s n; vs', []
+          with exn -> vs', [Trapping (table_error e.at exn) @@ e.at])
+        | None -> vs', [Trapping "element segment dropped" @@ e.at]
+        )
+
+      | ElemDrop x, vs ->
+        let seg = elem frame.inst x in
+        (match !seg with
+        | Some _ -> seg := None; vs, []
+        | None -> vs, [Trapping "element segment dropped" @@ e.at]
+        )
+
       | Load {offset; ty; sz; _}, I32 i :: vs' ->
         let mem = memory frame.inst (0l @@ e.at) in
         let addr = I64_convert.extend_i32_u i in
@@ -232,6 +253,37 @@ let rec step (c : config) : config =
           with Memory.SizeOverflow | Memory.SizeLimit | Memory.OutOfMemory -> -1l
         in I32 result :: vs', []
 
+      | MemoryFill, I32 n :: I32 b :: I32 i :: vs' ->
+        let mem = memory frame.inst (0l @@ e.at) in
+        let addr = I64_convert.extend_i32_u i in
+        (try Memory.fill mem addr (Int32.to_int b) n; vs', []
+        with exn -> vs', [Trapping (memory_error e.at exn) @@ e.at])
+
+      | MemoryCopy, I32 n :: I32 s :: I32 d :: vs' ->
+        let mem = memory frame.inst (0l @@ e.at) in
+        let dst = I64_convert.extend_i32_u d in
+        let src = I64_convert.extend_i32_u s in
+        (try Memory.copy mem dst src n; vs', []
+        with exn -> vs', [Trapping (memory_error e.at exn) @@ e.at])
+
+      | MemoryInit x, I32 n :: I32 s :: I32 d :: vs' ->
+        let mem = memory frame.inst (0l @@ e.at) in
+        (match !(data frame.inst x) with
+        | Some bs ->
+          let dst = I64_convert.extend_i32_u d in
+          let src = I64_convert.extend_i32_u s in
+          (try Memory.init mem bs dst src n; vs', []
+          with exn -> vs', [Trapping (memory_error e.at exn) @@ e.at])
+        | None -> vs', [Trapping "data segment dropped" @@ e.at]
+        )
+
+      | DataDrop x, vs ->
+        let seg = data frame.inst x in
+        (match !seg with
+        | Some _ -> seg := None; vs, []
+        | None -> vs, [Trapping "data segment dropped" @@ e.at]
+        )
+
       | Const v, vs ->
         v.it :: vs, []
 
@@ -255,58 +307,6 @@ let rec step (c : config) : config =
         (try Eval_numeric.eval_cvtop cvtop v :: vs', []
         with exn -> vs', [Trapping (numeric_error e.at exn) @@ e.at])
 
-      | MemoryInit x, I32 n :: I32 s :: I32 d :: vs' ->
-        let mem = memory frame.inst (0l @@ e.at) in
-        (match !(data frame.inst x) with
-        | Some bs ->
-          let dst = I64_convert.extend_i32_u d in
-          let src = I64_convert.extend_i32_u s in
-          (try Memory.init mem bs dst src n; vs', []
-          with exn -> vs', [Trapping (memory_error e.at exn) @@ e.at])
-        | None -> vs', [Trapping "data segment dropped" @@ e.at]
-        )
-
-      | MemoryCopy, I32 n :: I32 s :: I32 d :: vs' ->
-        let mem = memory frame.inst (0l @@ e.at) in
-        let dst = I64_convert.extend_i32_u d in
-        let src = I64_convert.extend_i32_u s in
-        (try Memory.copy mem dst src n; vs', []
-        with exn -> vs', [Trapping (memory_error e.at exn) @@ e.at])
-
-      | MemoryFill, I32 n :: I32 b :: I32 i :: vs' ->
-        let mem = memory frame.inst (0l @@ e.at) in
-        let addr = I64_convert.extend_i32_u i in
-        (try Memory.fill mem addr (Int32.to_int b) n; vs', []
-        with exn -> vs', [Trapping (memory_error e.at exn) @@ e.at])
-
-      | TableInit x, I32 n :: I32 s :: I32 d :: vs' ->
-        let tab = table frame.inst (0l @@ e.at) in
-        (match !(elem frame.inst x) with
-        | Some es ->
-          (try Table.init tab es d s n; vs', []
-          with exn -> vs', [Trapping (table_error e.at exn) @@ e.at])
-        | None -> vs', [Trapping "element segment dropped" @@ e.at]
-        )
-
-      | TableCopy, I32 n :: I32 s :: I32 d :: vs' ->
-        let tab = table frame.inst (0l @@ e.at) in
-        (try Table.copy tab d s n; vs', []
-        with exn -> vs', [Trapping (table_error e.at exn) @@ e.at])
-
-      | DataDrop x, vs ->
-        let seg = data frame.inst x in
-        (match !seg with
-        | Some _ -> seg := None; vs, []
-        | None -> vs, [Trapping "data segment dropped" @@ e.at]
-        )
-
-      | ElemDrop x, vs ->
-        let seg = elem frame.inst x in
-        (match !seg with
-        | Some _ -> seg := None; vs, []
-        | None -> vs, [Trapping "element segment dropped" @@ e.at]
-        )
-
       | _ ->
         let s1 = string_of_values (List.rev vs) in
         let s2 = string_of_value_types (List.map type_of (List.rev vs)) in
@@ -442,8 +442,8 @@ let create_export (inst : module_inst) (ex : export) : export_inst =
 let elem_list inst init =
   let to_elem el =
     match el.it with
-    | Null -> Table.Uninitialized
-    | Func x -> FuncElem (func inst x)
+    | RefNull -> Table.Uninitialized
+    | RefFunc x -> FuncElem (func inst x)
   in List.map to_elem init
 
 let create_elem (inst : module_inst) (seg : table_segment) : elem_inst =
diff --git a/interpreter/syntax/ast.ml b/interpreter/syntax/ast.ml
index 3bcbc3a53b..98f1044943 100644
--- a/interpreter/syntax/ast.ml
+++ b/interpreter/syntax/ast.ml
@@ -87,23 +87,23 @@ and instr' =
   | LocalTee of var                   (* write local variable and keep value *)
   | GlobalGet of var                  (* read global variable *)
   | GlobalSet of var                  (* write global variable *)
+  | TableCopy                         (* copy elements between table regions *)
+  | TableInit of var                  (* initialize table from segment *)
+  | ElemDrop of var                   (* drop passive element segment *)
   | Load of loadop                    (* read memory at address *)
   | Store of storeop                  (* write memory at address *)
   | MemorySize                        (* size of linear memory *)
   | MemoryGrow                        (* grow linear memory *)
+  | MemoryFill                        (* fill memory region with value *)
+  | MemoryCopy                        (* copy memory regions *)
+  | MemoryInit of var                 (* initialize memory from segment *)
+  | DataDrop of var                   (* drop passive data segment *)
   | Const of literal                  (* constant *)
   | Test of testop                    (* numeric test *)
   | Compare of relop                  (* numeric comparison *)
   | Unary of unop                     (* unary numeric operator *)
   | Binary of binop                   (* binary numeric operator *)
   | Convert of cvtop                  (* conversion *)
-  | MemoryInit of var                 (* initialize memory from segment *)
-  | MemoryCopy                        (* copy memory regions *)
-  | MemoryFill                        (* fill memory region with value *)
-  | TableInit of var                  (* initialize table from segment *)
-  | TableCopy                         (* copy elements between table regions *)
-  | DataDrop of var                   (* drop passive data segment *)
-  | ElemDrop of var                   (* drop passive element segment *)
 
 
 (* Globals & Functions *)
@@ -147,8 +147,8 @@ and ('data, 'ty) segment' =
 
 type elem = elem' Source.phrase
 and elem' =
-  | Null
-  | Func of var
+  | RefNull
+  | RefFunc of var
 
 type table_segment = (elem list, elem_type) segment
 type memory_segment = (string, unit) segment
diff --git a/interpreter/syntax/free.ml b/interpreter/syntax/free.ml
index 46727fc634..a57a56719e 100644
--- a/interpreter/syntax/free.ml
+++ b/interpreter/syntax/free.ml
@@ -92,8 +92,8 @@ let memory (m : memory) = empty
 
 let elem (e : elem) =
   match e.it with
-  | Null -> empty
-  | Func x -> funcs (var x)
+  | RefNull -> empty
+  | RefFunc x -> funcs (var x)
 
 let table_segment (s : table_segment) =
   match s.it with
diff --git a/interpreter/syntax/operators.ml b/interpreter/syntax/operators.ml
index e06fb73bbb..b925fa4a9e 100644
--- a/interpreter/syntax/operators.ml
+++ b/interpreter/syntax/operators.ml
@@ -9,6 +9,8 @@ let i32_const n = Const (I32 n.it @@ n.at)
 let i64_const n = Const (I64 n.it @@ n.at)
 let f32_const n = Const (F32 n.it @@ n.at)
 let f64_const n = Const (F64 n.it @@ n.at)
+let ref_null = RefNull
+let ref_func x = RefFunc x
 
 let unreachable = Unreachable
 let nop = Nop
@@ -31,6 +33,10 @@ let local_tee x = LocalTee x
 let global_get x = GlobalGet x
 let global_set x = GlobalSet x
 
+let table_copy = TableCopy
+let table_init x = TableInit x
+let elem_drop x = ElemDrop x
+
 let i32_load align offset = Load {ty = I32Type; align; offset; sz = None}
 let i64_load align offset = Load {ty = I64Type; align; offset; sz = None}
 let f32_load align offset = Load {ty = F32Type; align; offset; sz = None}
@@ -71,6 +77,13 @@ let i64_store16 align offset =
 let i64_store32 align offset =
   Store {ty = I64Type; align; offset; sz = Some Pack32}
 
+let memory_size = MemorySize
+let memory_grow = MemoryGrow
+let memory_fill = MemoryFill
+let memory_copy = MemoryCopy
+let memory_init x = MemoryInit x
+let data_drop x = DataDrop x
+
 let i32_clz = Unary (I32 I32Op.Clz)
 let i32_ctz = Unary (I32 I32Op.Ctz)
 let i32_popcnt = Unary (I32 I32Op.Popcnt)
@@ -198,13 +211,3 @@ let i32_reinterpret_f32 = Convert (I32 I32Op.ReinterpretFloat)
 let i64_reinterpret_f64 = Convert (I64 I64Op.ReinterpretFloat)
 let f32_reinterpret_i32 = Convert (F32 F32Op.ReinterpretInt)
 let f64_reinterpret_i64 = Convert (F64 F64Op.ReinterpretInt)
-
-let memory_size = MemorySize
-let memory_grow = MemoryGrow
-let memory_init x = MemoryInit x
-let memory_copy = MemoryCopy
-let memory_fill = MemoryFill
-let table_init x = TableInit x
-let table_copy = TableCopy
-let data_drop x = DataDrop x
-let elem_drop x = ElemDrop x
diff --git a/interpreter/text/arrange.ml b/interpreter/text/arrange.ml
index 42014540d2..c165adaa34 100644
--- a/interpreter/text/arrange.ml
+++ b/interpreter/text/arrange.ml
@@ -242,23 +242,23 @@ let rec instr e =
     | LocalTee x -> "local.tee " ^ var x, []
     | GlobalGet x -> "global.get " ^ var x, []
     | GlobalSet x -> "global.set " ^ var x, []
+    | TableCopy -> "table.copy", []
+    | TableInit x -> "table.init " ^ var x, []
+    | ElemDrop x -> "elem.drop " ^ var x, []
     | Load op -> loadop op, []
     | Store op -> storeop op, []
     | MemorySize -> "memory.size", []
     | MemoryGrow -> "memory.grow", []
+    | MemoryFill -> "memory.fill", []
+    | MemoryCopy -> "memory.copy", []
+    | MemoryInit x -> "memory.init " ^ var x, []
+    | DataDrop x -> "data.drop " ^ var x, []
     | Const lit -> constop lit ^ " " ^ value lit, []
     | Test op -> testop op, []
     | Compare op -> relop op, []
     | Unary op -> unop op, []
     | Binary op -> binop op, []
     | Convert op -> cvtop op, []
-    | MemoryInit x -> "memory.init " ^ var x, []
-    | DataDrop x -> "data.drop " ^ var x, []
-    | MemoryCopy -> "memory.copy", []
-    | MemoryFill -> "memory.fill", []
-    | TableInit x -> "table.init " ^ var x, []
-    | ElemDrop x -> "elem.drop " ^ var x, []
-    | TableCopy -> "table.copy", []
   in Node (head, inner)
 
 let const c =
@@ -304,13 +304,13 @@ let segment head active passive seg =
 
 let active_elem el =
   match el.it with
-  | Null -> assert false
-  | Func x -> atom var x
+  | RefNull -> assert false
+  | RefFunc x -> atom var x
 
 let passive_elem el =
   match el.it with
-  | Null -> Node ("ref.null", [])
-  | Func x -> Node ("ref.func", [atom var x])
+  | RefNull -> Node ("ref.null", [])
+  | RefFunc x -> Node ("ref.func", [atom var x])
 
 let elems seg =
   let active init = list active_elem init in
diff --git a/interpreter/text/lexer.mll b/interpreter/text/lexer.mll
index d29f11bb6e..75fa292faa 100644
--- a/interpreter/text/lexer.mll
+++ b/interpreter/text/lexer.mll
@@ -160,7 +160,10 @@ rule token = parse
   | '"'character*'\\'_
     { error_nest (Lexing.lexeme_end_p lexbuf) lexbuf "illegal escape" }
 
+  | "funcref" { FUNCREF }
   | (nxx as t) { VALUE_TYPE (value_type t) }
+  | "mut" { MUT }
+
   | (nxx as t)".const"
     { let open Source in
       CONST (numop t
@@ -173,8 +176,8 @@ rule token = parse
         (fun s -> let n = F64.of_string s.it in
           f64_const (n @@ s.at), Values.F64 n))
     }
-  | "funcref" { FUNCREF }
-  | "mut" { MUT }
+  | "ref.null" { REF_NULL }
+  | "ref.func" { REF_FUNC }
 
   | "nop" { NOP }
   | "unreachable" { UNREACHABLE }
@@ -199,6 +202,17 @@ rule token = parse
   | "global.get" { GLOBAL_GET }
   | "global.set" { GLOBAL_SET }
 
+  | "table.copy" { TABLE_COPY }
+  | "table.init" { TABLE_INIT }
+  | "elem.drop" { ELEM_DROP }
+
+  | "memory.size" { MEMORY_SIZE }
+  | "memory.grow" { MEMORY_GROW }
+  | "memory.fill" { MEMORY_FILL }
+  | "memory.copy" { MEMORY_COPY }
+  | "memory.init" { MEMORY_INIT }
+  | "data.drop" { DATA_DROP }
+
   | (nxx as t)".load"
     { LOAD (fun a o ->
         numop t (i32_load (opt a 2)) (i64_load (opt a 3))
@@ -314,22 +328,6 @@ rule token = parse
   | "i32.reinterpret_f32" { CONVERT i32_reinterpret_f32 }
   | "i64.reinterpret_f64" { CONVERT i64_reinterpret_f64 }
 
-  | "memory.size" { MEMORY_SIZE }
-  | "memory.grow" { MEMORY_GROW }
-
-  | "memory.init" { MEMORY_INIT }
-  | "data.drop" { DATA_DROP }
-  | "memory.copy" { MEMORY_COPY }
-  | "memory.fill" { MEMORY_FILL }
-  | "table.init" { TABLE_INIT }
-  | "elem.drop" { ELEM_DROP }
-  | "table.copy" { TABLE_COPY }
-
-  | "ref.null" { REF_NULL }
-  | "ref.func" { REF_FUNC }
-
-  | "passive" { PASSIVE }
-
   | "type" { TYPE }
   | "func" { FUNC }
   | "start" { START }
@@ -341,6 +339,7 @@ rule token = parse
   | "memory" { MEMORY }
   | "elem" { ELEM }
   | "data" { DATA }
+  | "passive" { PASSIVE }
   | "offset" { OFFSET }
   | "import" { IMPORT }
   | "export" { EXPORT }
diff --git a/interpreter/text/parser.mly b/interpreter/text/parser.mly
index ffb90b2808..6066c6ffa3 100644
--- a/interpreter/text/parser.mly
+++ b/interpreter/text/parser.mly
@@ -154,19 +154,20 @@ let inline_type_explicit (c : context) x ft at =
 
 %}
 
-%token NAT INT FLOAT STRING VAR VALUE_TYPE FUNCREF MUT LPAR RPAR
-%token NOP DROP BLOCK END IF THEN ELSE SELECT LOOP BR BR_IF BR_TABLE
+%token LPAR RPAR
+%token NAT INT FLOAT STRING VAR
+%token FUNCREF VALUE_TYPE MUT
+%token UNREACHABLE NOP DROP SELECT
+%token BLOCK END IF THEN ELSE LOOP BR BR_IF BR_TABLE
 %token CALL CALL_INDIRECT RETURN
 %token LOCAL_GET LOCAL_SET LOCAL_TEE GLOBAL_GET GLOBAL_SET
+%token TABLE_COPY TABLE_INIT ELEM_DROP
+%token MEMORY_SIZE MEMORY_GROW MEMORY_FILL MEMORY_COPY MEMORY_INIT DATA_DROP
 %token LOAD STORE OFFSET_EQ_NAT ALIGN_EQ_NAT
 %token CONST UNARY BINARY TEST COMPARE CONVERT
-%token UNREACHABLE MEMORY_SIZE MEMORY_GROW
-%token MEMORY_INIT DATA_DROP MEMORY_COPY MEMORY_FILL
-%token TABLE_INIT ELEM_DROP TABLE_COPY
 %token REF_NULL REF_FUNC
 %token FUNC START TYPE PARAM RESULT LOCAL GLOBAL
-%token TABLE ELEM MEMORY DATA OFFSET IMPORT EXPORT TABLE
-%token PASSIVE
+%token TABLE ELEM MEMORY DATA PASSIVE OFFSET IMPORT EXPORT TABLE
 %token MODULE BIN QUOTE
 %token SCRIPT REGISTER INVOKE GET
 %token ASSERT_MALFORMED ASSERT_INVALID ASSERT_SOFT_INVALID ASSERT_UNLINKABLE
@@ -328,23 +329,23 @@ plain_instr :
   | LOCAL_TEE var { fun c -> local_tee ($2 c local) }
   | GLOBAL_GET var { fun c -> global_get ($2 c global) }
   | GLOBAL_SET var { fun c -> global_set ($2 c global) }
+  | TABLE_COPY { fun c -> table_copy }
+  | TABLE_INIT var { fun c -> table_init ($2 c elem) }
+  | ELEM_DROP var { fun c -> elem_drop ($2 c elem) }
   | LOAD offset_opt align_opt { fun c -> $1 $3 $2 }
   | STORE offset_opt align_opt { fun c -> $1 $3 $2 }
   | MEMORY_SIZE { fun c -> memory_size }
   | MEMORY_GROW { fun c -> memory_grow }
+  | MEMORY_FILL { fun c -> memory_fill }
+  | MEMORY_COPY { fun c -> memory_copy }
+  | MEMORY_INIT var { fun c -> memory_init ($2 c data) }
+  | DATA_DROP var { fun c -> data_drop ($2 c data) }
   | CONST literal { fun c -> fst (literal $1 $2) }
   | TEST { fun c -> $1 }
   | COMPARE { fun c -> $1 }
   | UNARY { fun c -> $1 }
   | BINARY { fun c -> $1 }
   | CONVERT { fun c -> $1 }
-  | MEMORY_INIT var { fun c -> memory_init ($2 c data) }
-  | DATA_DROP var { fun c -> data_drop ($2 c data) }
-  | MEMORY_COPY { fun c -> memory_copy }
-  | MEMORY_FILL { fun c -> memory_fill }
-  | TABLE_INIT var { fun c -> table_init ($2 c elem) }
-  | ELEM_DROP var { fun c -> elem_drop ($2 c elem) }
-  | TABLE_COPY { fun c -> table_copy }
 
 
 call_instr :
@@ -570,9 +571,9 @@ offset :
   | expr { let at = at () in fun c -> $1 c @@ at }  /* Sugar */
 
 elemref :
-  | LPAR REF_NULL RPAR { let at = at () in fun c -> Null @@ at }
-  | LPAR REF_FUNC var RPAR { let at = at () in fun c -> Func ($3 c func) @@ at }
-  | var { let at = at () in fun c -> Func ($1 c func) @@ at }
+  | LPAR REF_NULL RPAR { let at = at () in fun c -> ref_null @@ at }
+  | LPAR REF_FUNC var RPAR { let at = at () in fun c -> ref_func ($3 c func) @@ at }
+  | var { let at = at () in fun c -> ref_func ($1 c func) @@ at }
 
 passive_elemref_list :
   | /* empty */ { fun c -> [] }
@@ -580,7 +581,7 @@ passive_elemref_list :
 
 active_elemref_list :
   | var_list
-    { let f = function {at; _} as x -> Func x @@ at in
+    { let f = function {at; _} as x -> ref_func x @@ at in
       fun c lookup -> List.map f ($1 c lookup) }
 
 elem :
diff --git a/interpreter/valid/valid.ml b/interpreter/valid/valid.ml
index 451aeeecb9..584fd30c8b 100644
--- a/interpreter/valid/valid.ml
+++ b/interpreter/valid/valid.ml
@@ -233,8 +233,6 @@ let rec check_instr (c : context) (e : instr) (s : infer_stack_type) : op_type =
     let FuncType (ins, out) = type_ c x in
     (ins @ [I32Type]) --> out
 
-
-
   | LocalGet x ->
     [] --> [local c x]
 
@@ -253,6 +251,20 @@ let rec check_instr (c : context) (e : instr) (s : infer_stack_type) : op_type =
     require (mut = Mutable) x.at "global is immutable";
     [t] --> []
 
+  | TableCopy ->
+    ignore (table c (0l @@ e.at));
+    [I32Type; I32Type; I32Type] --> []
+
+  | TableInit x ->
+    ignore (table c (0l @@ e.at));
+    ignore (elem c x);
+    [I32Type; I32Type; I32Type] --> []
+
+  | ElemDrop x ->
+    ignore (table c (0l @@ e.at));
+    ignore (elem c x);
+    [] --> []
+
   | Load memop ->
     check_memop c memop (Lib.Option.map fst) e.at;
     [I32Type] --> [memop.ty]
@@ -269,6 +281,24 @@ let rec check_instr (c : context) (e : instr) (s : infer_stack_type) : op_type =
     ignore (memory c (0l @@ e.at));
     [I32Type] --> [I32Type]
 
+  | MemoryFill ->
+    ignore (memory c (0l @@ e.at));
+    [I32Type; I32Type; I32Type] --> []
+
+  | MemoryCopy ->
+    ignore (memory c (0l @@ e.at));
+    [I32Type; I32Type; I32Type] --> []
+
+  | MemoryInit x ->
+    ignore (memory c (0l @@ e.at));
+    ignore (data c x);
+    [I32Type; I32Type; I32Type] --> []
+
+  | DataDrop x ->
+    ignore (memory c (0l @@ e.at));
+    ignore (data c x);
+    [] --> []
+
   | Const v ->
     let t = type_value v.it in
     [] --> [t]
@@ -293,38 +323,6 @@ let rec check_instr (c : context) (e : instr) (s : infer_stack_type) : op_type =
     let t1, t2 = type_cvtop e.at cvtop in
     [t1] --> [t2]
 
-  | MemoryInit x ->
-    ignore (memory c (0l @@ e.at));
-    ignore (data c x);
-    [I32Type; I32Type; I32Type] --> []
-
-  | MemoryCopy ->
-    ignore (memory c (0l @@ e.at));
-    [I32Type; I32Type; I32Type] --> []
-
-  | MemoryFill ->
-    ignore (memory c (0l @@ e.at));
-    [I32Type; I32Type; I32Type] --> []
-
-  | TableInit x ->
-    ignore (table c (0l @@ e.at));
-    ignore (elem c x);
-    [I32Type; I32Type; I32Type] --> []
-
-  | TableCopy ->
-    ignore (table c (0l @@ e.at));
-    [I32Type; I32Type; I32Type] --> []
-
-  | DataDrop x ->
-    ignore (memory c (0l @@ e.at));
-    ignore (data c x);
-    [] --> []
-
-  | ElemDrop x ->
-    ignore (table c (0l @@ e.at));
-    ignore (elem c x);
-    [] --> []
-
 and check_seq (c : context) (es : instr list) : infer_stack_type =
   match es with
   | [] ->
@@ -426,8 +424,8 @@ let check_memory (c : context) (mem : memory) =
 
 let check_elemref (c : context) (el : elem) =
   match el.it with
-  | Null -> ()
-  | Func x -> ignore (func c x)
+  | RefNull -> ()
+  | RefFunc x -> ignore (func c x)
 
 let check_elem (c : context) (seg : table_segment) =
   match seg.it with

From c3d5cbc1f7c6b166b7a312adc4efdb7e34746b3d Mon Sep 17 00:00:00 2001
From: Andreas Rossberg 
Date: Wed, 3 Apr 2019 11:15:54 +0200
Subject: [PATCH 074/199] [spec/interpreter/test] Add table bulk instructions
 missing from bulk op proposal (#35)

Adds table.size, table.grow, table.fill to overview, spec, interpreter, and tests, as decided at recent CG meeting. Also adds a few more tests for table.get and table.set.

Also, change interpreter's segment encoding to match bulk ops proposal, addressing #18. (Not updated in spec yet, since corresponding spec text is still missing from bulk ops proposal.)
---
 document/core/appendix/embedding.rst  |  16 +--
 document/core/binary/instructions.rst |  13 ++-
 document/core/exec/instructions.rst   | 156 +++++++++++++++++++++++++
 document/core/exec/modules.rst        |  12 +-
 document/core/syntax/instructions.rst |  16 ++-
 document/core/text/instructions.rst   |   8 +-
 document/core/util/macros.def         |   3 +
 document/core/valid/instructions.rst  |  55 +++++++++
 document/js-api/index.bs              |  10 +-
 interpreter/README.md                 |   3 +
 interpreter/binary/decode.ml          |  20 +++-
 interpreter/binary/encode.ml          |  11 +-
 interpreter/exec/eval.ml              |  25 +++-
 interpreter/host/spectest.ml          |   3 +-
 interpreter/runtime/table.ml          |  15 +--
 interpreter/runtime/table.mli         |   6 +-
 interpreter/syntax/ast.ml             |   3 +
 interpreter/syntax/operators.ml       |   6 +-
 interpreter/text/arrange.ml           |   3 +
 interpreter/text/lexer.mll            |   4 +
 interpreter/text/parser.mly           |  13 ++-
 interpreter/valid/valid.ml            |  18 ++-
 proposals/reference-types/Overview.md |  59 ++++++++--
 test/core/memory_grow.wast            |  46 ++++++--
 test/core/table_fill.wast             | 153 ++++++++++++++++++++++++
 test/core/table_get.wast              |  52 +++++++++
 test/core/table_grow.wast             | 160 ++++++++++++++++++++++++++
 test/core/table_set.wast              |  70 +++++++++++
 test/core/table_size.wast             |  86 ++++++++++++++
 29 files changed, 975 insertions(+), 70 deletions(-)
 create mode 100644 test/core/table_fill.wast
 create mode 100644 test/core/table_grow.wast
 create mode 100644 test/core/table_size.wast

diff --git a/document/core/appendix/embedding.rst b/document/core/appendix/embedding.rst
index 48b601b2a0..f3fa84a36b 100644
--- a/document/core/appendix/embedding.rst
+++ b/document/core/appendix/embedding.rst
@@ -294,8 +294,8 @@ Tables
 
 .. _embed-alloc-table:
 
-:math:`\F{alloc\_table}(\store, \tabletype) : (\store, \tableaddr)`
-...................................................................
+:math:`\F{alloc\_table}(\store, \tabletype) : (\store, \tableaddr, \val)`
+.........................................................................
 
 1. Let :math:`\tableaddr` be the result of :ref:`allocating a table ` in :math:`\store` with :ref:`table type ` :math:`\tabletype`.
 
@@ -303,7 +303,7 @@ Tables
 
 .. math::
    \begin{array}{lclll}
-   \F{alloc\_table}(S, \X{tt}) &=& (S', \X{a}) && (\iff \alloctable(S, \X{tt}) = S', \X{a}) \\
+   \F{alloc\_table}(S, \X{tt}, v) &=& (S', \X{a}) && (\iff \alloctable(S, \X{tt}, v) = S', \X{a}) \\
    \end{array}
 
 
@@ -390,8 +390,8 @@ Tables
 
 .. _embed-grow-table:
 
-:math:`\F{grow\_table}(\store, \tableaddr, n) : \store ~|~ \error`
-..................................................................
+:math:`\F{grow\_table}(\store, \tableaddr, n, \val) : \store ~|~ \error`
+........................................................................
 
 1. Assert: :math:`\store.\STABLES[\tableaddr]` exists.
 
@@ -406,9 +406,9 @@ Tables
 .. math::
    ~ \\
    \begin{array}{lclll}
-   \F{grow\_table}(S, a, n) &=& S' &&
-     (\iff S' = S \with \STABLES[a] = \growtable(S.\STABLES[a], n)) \\
-   \F{grow\_table}(S, a, n) &=& \ERROR && (\otherwise) \\
+   \F{grow\_table}(S, a, n, v) &=& S' &&
+     (\iff S' = S \with \STABLES[a] = \growtable(S.\STABLES[a], n, v)) \\
+   \F{grow\_table}(S, a, n, v) &=& \ERROR && (\otherwise) \\
    \end{array}
 
 
diff --git a/document/core/binary/instructions.rst b/document/core/binary/instructions.rst
index 7b41829ce7..e1ad15ce04 100644
--- a/document/core/binary/instructions.rst
+++ b/document/core/binary/instructions.rst
@@ -138,21 +138,24 @@ Variable Instructions
 Table Instructions
 ~~~~~~~~~~~~~~~~~~
 
-:ref:`Table instructions ` are represented by single byte codes.
+:ref:`Table instructions ` are represented by either single byte or two byte codes.
 
 .. _binary-table.get:
 .. _binary-table.set:
+.. _binary-table.size:
+.. _binary-table.grow:
+.. _binary-table.fill:
 
 .. math::
    \begin{array}{llclll}
    \production{instruction} & \Binstr &::=& \dots \\ &&|&
      \hex{25}~~x{:}\Btableidx &\Rightarrow& \TABLEGET~x \\ &&|&
-     \hex{26}~~x{:}\Btableidx &\Rightarrow& \TABLESET~x \\
+     \hex{26}~~x{:}\Btableidx &\Rightarrow& \TABLESET~x \\ &&|&
+     \hex{FC}~\hex{0F}~~x{:}\Btableidx &\Rightarrow& \TABLEGROW~x \\ &&|&
+     \hex{FC}~\hex{10}~~x{:}\Btableidx &\Rightarrow& \TABLESIZE~x \\ &&|&
+     \hex{FC}~\hex{11}~~x{:}\Btableidx &\Rightarrow& \TABLEFILL~x \\
    \end{array}
 
-.. note::
-   These opcode assignments are preliminary.
-
 
 .. index:: memory instruction, memory index
    pair: binary format; instruction
diff --git a/document/core/exec/instructions.rst b/document/core/exec/instructions.rst
index 2673db49b8..91452e8c2c 100644
--- a/document/core/exec/instructions.rst
+++ b/document/core/exec/instructions.rst
@@ -522,6 +522,162 @@ Table Instructions
    \end{array}
 
 
+.. _exec-table.size:
+
+:math:`\TABLESIZE~x`
+....................
+
+1. Let :math:`F` be the :ref:`current ` :ref:`frame `.
+
+2. Assert: due to :ref:`validation `, :math:`F.\AMODULE.\MITABLES[x]` exists.
+
+3. Let :math:`a` be the :ref:`table address ` :math:`F.\AMODULE.\MITABLES[x]`.
+
+4. Assert: due to :ref:`validation `, :math:`S.\STABLES[a]` exists.
+
+5. Let :math:`\X{tab}` be the :ref:`table instance ` :math:`S.\STABLES[a]`.
+
+6. Let :math:`\X{sz}` be the length of :math:`\X{tab}.\TIELEM`.
+
+7. Push the value :math:`\I32.\CONST~\X{sz}` to the stack.
+
+.. math::
+   \begin{array}{l}
+   \begin{array}{lcl@{\qquad}l}
+   S; F; \TABLESIZE~x &\stepto& S; F; (\I32.\CONST~\X{sz})
+   \end{array}
+   \\ \qquad
+     (\iff |S.\STABLES[F.\AMODULE.\MITABLES[x]].\TIELEM| = \X{sz}) \\
+   \end{array}
+
+
+.. _exec-table.grow:
+
+:math:`\TABLEGROW~x`
+....................
+
+1. Let :math:`F` be the :ref:`current ` :ref:`frame `.
+
+2. Assert: due to :ref:`validation `, :math:`F.\AMODULE.\MITABLES[x]` exists.
+
+3. Let :math:`a` be the :ref:`table address ` :math:`F.\AMODULE.\MITABLES[x]`.
+
+4. Assert: due to :ref:`validation `, :math:`S.\STABLES[a]` exists.
+
+5. Let :math:`\X{tab}` be the :ref:`table instance ` :math:`S.\STABLES[a]`.
+
+6. Let :math:`\X{sz}` be the length of :math:`S.\STABLES[a]`.
+
+7. Assert: due to :ref:`validation `, a value of :ref:`value type ` |I32| is on the top of the stack.
+
+8. Pop the value :math:`\I32.\CONST~n` from the stack.
+
+9. Assert: due to :ref:`validation `, a :ref:`reference value ` is on the top of the stack.
+
+10. Pop the value :math:`\val` from the stack.
+
+11. Either, try :ref:`growing ` :math:`\X{table}` by :math:`n` entries with initialization value :math:`\val`:
+
+   a. If it succeeds, push the value :math:`\I32.\CONST~\X{sz}` to the stack.
+
+   b. Else, push the value :math:`\I32.\CONST~(-1)` to the stack.
+
+12. Or, push the value :math:`\I32.\CONST~(-1)` to the stack.
+
+.. math::
+   ~\\[-1ex]
+   \begin{array}{l}
+   \begin{array}{lcl@{\qquad}l}
+   S; F; \val~(\I32.\CONST~n)~\TABLEGROW~x &\stepto& S'; F; (\I32.\CONST~\X{sz})
+   \end{array}
+   \\ \qquad
+     \begin{array}[t]{@{}r@{~}l@{}}
+     (\iff & F.\AMODULE.\MITABLES[x] = a \\
+     \wedge & \X{sz} = |S.\STABLES[a].\TIELEM| \\
+     \wedge & S' = S \with \STABLES[a] = \growtable(S.\STABLES[a], n, \val)) \\
+     \end{array}
+   \\[1ex]
+   \begin{array}{lcl@{\qquad}l}
+   S; F; (\I32.\CONST~n)~\TABLEGROW~x &\stepto& S; F; (\I32.\CONST~{-1})
+   \end{array}
+   \end{array}
+
+.. note::
+   The |TABLEGROW| instruction is non-deterministic.
+   It may either succeed, returning the old table size :math:`\X{sz}`,
+   or fail, returning :math:`{-1}`.
+   Failure *must* occur if the referenced table instance has a maximum size defined that would be exceeded.
+   However, failure *can* occur in other cases as well.
+   In practice, the choice depends on the :ref:`resources ` available to the :ref:`embedder `.
+
+
+.. _exec-table.fill:
+
+:math:`\TABLEFILL~x`
+....................
+
+1. Let :math:`F` be the :ref:`current ` :ref:`frame `.
+
+2. Assert: due to :ref:`validation `, :math:`F.\AMODULE.\MITABLES[x]` exists.
+
+3. Let :math:`a` be the :ref:`table address ` :math:`F.\AMODULE.\MITABLES[x]`.
+
+4. Assert: due to :ref:`validation `, :math:`S.\STABLES[a]` exists.
+
+5. Let :math:`\X{tab}` be the :ref:`table instance ` :math:`S.\STABLES[a]`.
+
+6. Assert: due to :ref:`validation `, a value of :ref:`value type ` |I32| is on the top of the stack.
+
+7. Pop the value :math:`\I32.\CONST~n` from the stack.
+
+8. Assert: due to :ref:`validation `, a :ref:`reference value ` is on the top of the stack.
+
+9. Pop the value :math:`\val` from the stack.
+
+10. Assert: due to :ref:`validation `, a value of :ref:`value type ` |I32| is on the top of the stack.
+
+11. Pop the value :math:`\I32.\CONST~i` from the stack.
+
+12. If :math:`n` is :math:`0`, then:
+
+    a. If :math:`i` is larger than the length of :math:`\X{tab}.\TIELEM`, then:
+
+       i. Trap.
+
+12. Else:
+
+    a. Push the value :math:`\I32.CONST~i` to the stack.
+
+    b. Push the value :math:`\val` to the stack.
+
+    c. Execute the instruction :math:`\TABLESET~x`.
+
+    d. Push the value :math:`\I32.CONST~(i+1)` to the stack.
+
+    e. Push the value :math:`\val` to the stack.
+
+    f. Push the value :math:`\I32.CONST~(n-1)` to the stack.
+
+    c. Execute the instruction :math:`\TABLEFILL~x`.
+
+.. math::
+   \begin{array}{l}
+   \begin{array}{lcl@{\qquad}l}
+   S; F; (\I32.\CONST~i)~\val~(\I32.\CONST~(n+1))~(\TABLEFILL~x) &\stepto& S'; F; (\I32.\CONST~i)~\val~(\TABLESET~x)~(\I32.\CONST~(i+1))~\val~(\I32.\CONST~n)~(\TABLEFILL~x)
+   \end{array} \\
+   \begin{array}{lcl@{\qquad}l}
+   S; F; (\I32.\CONST~i)~\val~(\I32.\CONST~0)~(\TABLEFILL~x) &\stepto& S'; F; \epsilon
+   \end{array}
+   \\ \qquad
+     (\iff i \leq |\STABLES[F.\AMODULE.\MITABLES[x]]|) \\
+   \begin{array}{lcl@{\qquad}l}
+   S; F; (\I32.\CONST~i)~\val~(\I32.\CONST~0)~(\TABLEFILL~x) &\stepto& S; F; \TRAP
+   \end{array}
+   \\ \qquad
+     (\otherwise) \\
+   \end{array}
+
+
 .. index:: memory instruction, memory index, store, frame, address, memory address, memory instance, value, integer, limits, value type, bit width
    pair: execution; instruction
    single: abstract syntax; instruction
diff --git a/document/core/exec/modules.rst b/document/core/exec/modules.rst
index 3078d9441c..4aad62cbdf 100644
--- a/document/core/exec/modules.rst
+++ b/document/core/exec/modules.rst
@@ -298,7 +298,7 @@ New instances of :ref:`functions `, :ref:`tables `
 ................................
 
-1. Let :math:`\tabletype` be the :ref:`table type ` to allocate.
+1. Let :math:`\tabletype` be the :ref:`table type ` to allocate and :math:`\val` the initialization value.
 
 2. Let :math:`(\{\LMIN~n, \LMAX~m^?\}~\reftype)` be the structure of :ref:`table type ` :math:`\tabletype`.
 
@@ -312,11 +312,11 @@ New instances of :ref:`functions `, :ref:`tables `, :ref:`tables `
 ........................................
 
-1. Let :math:`\tableinst` be the :ref:`table instance ` to grow and :math:`n` the number of elements by which to grow it.
+1. Let :math:`\tableinst` be the :ref:`table instance ` to grow, :math:`n` the number of elements by which to grow it, and :math:`\val` the initialization value.
 
 2. Let :math:`\X{len}` be :math:`n` added to the length of :math:`\tableinst.\TIELEM`.
 
@@ -397,7 +397,7 @@ Growing :ref:`tables `
 
 .. math::
    \begin{array}{rllll}
-   \growtable(\tableinst, n) &=& \tableinst \with \TIELEM = \tableinst.\TIELEM~\REFNULL^n \\
+   \growtable(\tableinst, n, \val) &=& \tableinst \with \TIELEM = \tableinst.\TIELEM~\val^n \\
      && (
        \begin{array}[t]{@{}r@{~}l@{}}
        \iff & \X{len} = n + |\tableinst.\TIELEM| \\
@@ -519,7 +519,7 @@ where:
      \MIEXPORTS~\exportinst^\ast ~\}
      \end{array} \\[1ex]
    S_1, \funcaddr^\ast &=& \allocfunc^\ast(S, \module.\MFUNCS, \moduleinst) \\
-   S_2, \tableaddr^\ast &=& \alloctable^\ast(S_1, (\table.\TTYPE)^\ast)
+   S_2, \tableaddr^\ast &=& \alloctable^\ast(S_1, (\table.\TTYPE)^\ast, \REFNULL)
      \qquad\qquad\qquad~ (\where \table^\ast = \module.\MTABLES) \\
    S_3, \memaddr^\ast &=& \allocmem^\ast(S_2, (\mem.\MTYPE)^\ast)
      \qquad\qquad\qquad~ (\where \mem^\ast = \module.\MMEMS) \\
diff --git a/document/core/syntax/instructions.rst b/document/core/syntax/instructions.rst
index 2fa21f1c39..c4806d5c8e 100644
--- a/document/core/syntax/instructions.rst
+++ b/document/core/syntax/instructions.rst
@@ -241,6 +241,9 @@ The |LOCALTEE| instruction is like |LOCALSET| but also returns its argument.
    pair: abstract syntax; instruction
 .. _syntax-table.get:
 .. _syntax-table.set:
+.. _syntax-table.size:
+.. _syntax-table.grow:
+.. _syntax-table.fill:
 .. _syntax-instr-table:
 
 Table Instructions
@@ -253,10 +256,19 @@ Instructions in this group are concerned with accessing :ref:`tables ` |CALLINDIRECT|.
 
diff --git a/document/core/text/instructions.rst b/document/core/text/instructions.rst
index 002866e190..f42cc0f6b2 100644
--- a/document/core/text/instructions.rst
+++ b/document/core/text/instructions.rst
@@ -200,12 +200,18 @@ Table Instructions
 
 .. _text-table.get:
 .. _text-table.set:
+.. _text-table.size:
+.. _text-table.grow:
+.. _text-table.fill:
 
 .. math::
    \begin{array}{llclll}
    \production{instruction} & \Tplaininstr_I &::=& \dots \\ &&|&
      \text{table.get}~~x{:}\Ttableidx_I &\Rightarrow& \TABLEGET~x \\ &&|&
-     \text{table.set}~~x{:}\Ttableidx_I &\Rightarrow& \TABLESET~x \\
+     \text{table.set}~~x{:}\Ttableidx_I &\Rightarrow& \TABLESET~x \\ &&|&
+     \text{table.size}~~x{:}\Ttableidx_I &\Rightarrow& \TABLESIZE~x \\ &&|&
+     \text{table.grow}~~x{:}\Ttableidx_I &\Rightarrow& \TABLEGROW~x \\ &&|&
+     \text{table.fill}~~x{:}\Ttableidx_I &\Rightarrow& \TABLEFILL~x \\
    \end{array}
 
 
diff --git a/document/core/util/macros.def b/document/core/util/macros.def
index 3fe9dfd722..54be7bdabd 100644
--- a/document/core/util/macros.def
+++ b/document/core/util/macros.def
@@ -328,6 +328,9 @@
 
 .. |TABLEGET| mathdef:: \xref{syntax/instructions}{syntax-instr-table}{\K{table.get}}
 .. |TABLESET| mathdef:: \xref{syntax/instructions}{syntax-instr-table}{\K{table.set}}
+.. |TABLESIZE| mathdef:: \xref{syntax/instructions}{syntax-instr-table}{\K{table.size}}
+.. |TABLEGROW| mathdef:: \xref{syntax/instructions}{syntax-instr-table}{\K{table.grow}}
+.. |TABLEFILL| mathdef:: \xref{syntax/instructions}{syntax-instr-table}{\K{table.fill}}
 
 .. |LOAD| mathdef:: \xref{syntax/instructions}{syntax-instr-memory}{\K{load}}
 .. |STORE| mathdef:: \xref{syntax/instructions}{syntax-instr-memory}{\K{store}}
diff --git a/document/core/valid/instructions.rst b/document/core/valid/instructions.rst
index 7241562330..16a432c1fc 100644
--- a/document/core/valid/instructions.rst
+++ b/document/core/valid/instructions.rst
@@ -398,6 +398,61 @@ Table Instructions
    }
 
 
+.. _valid-table.size:
+
+:math:`\TABLESIZE~x`
+....................
+
+* The table :math:`C.\CTABLES[x]` must be defined in the context.
+
+* Then the instruction is valid with type :math:`[] \to [\I32]`.
+
+.. math::
+   \frac{
+     C.\CTABLES[x] = t
+   }{
+     C \vdashinstr \TABLESIZE~x : [] \to [\I32]
+   }
+
+
+.. _valid-table.grow:
+
+:math:`\TABLEGROW~x`
+....................
+
+* The table :math:`C.\CTABLES[x]` must be defined in the context.
+
+* Let :math:`\limits~t` be the :ref:`table type ` :math:`C.\CTABLES[x]`.
+
+* Then the instruction is valid with type :math:`[t~\I32] \to [\I32]`.
+
+.. math::
+   \frac{
+     C.\CTABLES[x] = t
+   }{
+     C \vdashinstr \TABLEGROW~x : [t~\I32] \to [\I32]
+   }
+
+
+.. _valid-table.fill:
+
+:math:`\TABLEFILL~x`
+....................
+
+* The table :math:`C.\CTABLES[x]` must be defined in the context.
+
+* Let :math:`\limits~t` be the :ref:`table type ` :math:`C.\CTABLES[x]`.
+
+* Then the instruction is valid with type :math:`[\I32~t~\I32] \to []`.
+
+.. math::
+   \frac{
+     C.\CTABLES[x] = t
+   }{
+     C \vdashinstr \TABLEFILL~x : [\I32~t~\I32] \to []
+   }
+
+
 .. index:: memory instruction, memory index, context
    pair: validation; instruction
    single: abstract syntax; instruction
diff --git a/document/js-api/index.bs b/document/js-api/index.bs
index c2eb6ec50f..754634977b 100644
--- a/document/js-api/index.bs
+++ b/document/js-api/index.bs
@@ -716,7 +716,7 @@ which can be simultaneously referenced by multiple {{Instance}} objects. Each
     1. If |maximum| is not empty and |maximum| < |initial|, throw a {{RangeError}} exception.
     1. Let |type| be the [=table type=] {[=table type|𝗆𝗂𝗇=] n, [=table type|𝗆𝖺𝗑=] |maximum|} [=table type|funcref=].
     1. Let |store| be the [=surrounding agent=]'s [=associated store=].
-    1. Let (|store|, |tableaddr|) be [=alloc_table=](|store|, |type|). 
+    1. Let (|store|, |tableaddr|) be [=alloc_table=](|store|, |type|, [=ref.null=]). 
     1. Set the [=surrounding agent=]'s [=associated store=] to |store|.
     1. [=Create a table object=] from the table address |tableaddr| and return the result.
 
@@ -726,7 +726,7 @@ which can be simultaneously referenced by multiple {{Instance}} objects. Each
     1. Let |tableaddr| be the Table instance's \[[Table]] internal slot.
     1. Let |initialSize| be the length of the Table instance's \[[Values]] internal slot.
     1. Let |store| be the [=surrounding agent=]'s [=associated store=].
-    1. Let |result| be [=grow_table=](|store|, |tableaddr|, |delta|).
+    1. Let |result| be [=grow_table=](|store|, |tableaddr|, |delta|, [=ref.null=]).
     1. If |result| is [=error=], throw a {{RangeError}} exception.
 
         Note: The above exception may happen due to either insufficient memory or an invalid size parameter.
@@ -752,12 +752,12 @@ which can be simultaneously referenced by multiple {{Instance}} objects. Each
     The set(|index|, |value|) method, when invoked, performs the following steps:
     1. Let |tableaddr| be the Table instance's \[[Table]] internal slot.
     1. Let |values| be the Table instance's \[[Values]] internal slot.
-    1. If |value| is null, let |funcaddr| be an empty [=function element=].
+    1. If |value| is null, let |ref| be [=ref.null=].
     1. Otherwise,
         1. If |value| does not have a \[[FunctionAddress]] internal slot, throw a {{TypeError}} exception.
-        1. Let |funcaddr| be |value|.\[[FunctionAddress]].
+        1. Let |ref| be [=ref.func=] |value|.\[[FunctionAddress]].
     1. Let |store| be the [=surrounding agent=]'s [=associated store=].
-    1. Let |store| be [=write_table=](|store|, |tableaddr|, |index|, |funcaddr|).
+    1. Let |store| be [=write_table=](|store|, |tableaddr|, |index|, |ref|).
     1. If |store| is [=error=], throw a {{RangeError}} exception.
     1. Set the [=surrounding agent=]'s [=associated store=] to |store|.
     1. Set |values|[|index|] to |value|.
diff --git a/interpreter/README.md b/interpreter/README.md
index 0ef90f1627..75512b5508 100644
--- a/interpreter/README.md
+++ b/interpreter/README.md
@@ -226,6 +226,9 @@ op:
   global.set 
   table.get 
   table.set 
+  table.size 
+  table.grow 
+  table.fill 
   .load((8|16|32)_)? ? ?
   .store(8|16|32)? ? ?
   memory.size
diff --git a/interpreter/binary/decode.ml b/interpreter/binary/decode.ml
index e6bb53eba4..08e41d36c7 100644
--- a/interpreter/binary/decode.ml
+++ b/interpreter/binary/decode.ml
@@ -47,6 +47,8 @@ let skip n = guard (skip n)
 
 let expect b s msg = require (guard get s = b) s (pos s - 1) msg
 let illegal s pos b = error s pos ("illegal opcode " ^ string_of_byte b)
+let illegal2 s pos b1 b2 =
+  error s pos ("illegal opcode " ^ string_of_byte b1 ^ " " ^ string_of_byte b2)
 
 let at f s =
   let left = pos s in
@@ -448,6 +450,15 @@ let rec instr s =
   | 0xd1 -> ref_is_null
   | 0xd2 -> ref_func (at var s)
 
+  | 0xfc as b1 ->
+    (match op s with
+    | 0x0f -> table_grow (at var s)
+    | 0x10 -> table_size (at var s)
+    | 0x11 -> table_fill (at var s)
+
+    | b2 -> illegal2 s pos b1 b2
+    )
+
   | b -> illegal s pos b
 
 and instr_block s = List.rev (instr_block' s [])
@@ -610,7 +621,14 @@ let code_section s =
 (* Element section *)
 
 let segment dat s =
-  let index = at var s in
+  let pos = pos s in
+  let x = at vu32 s in
+  let index =
+    match x.Source.it with
+    | 0l -> x
+    | 2l -> at var s
+    | _ -> error s pos "invalid segment kind"
+  in
   let offset = const s in
   let init = dat s in
   {index; offset; init}
diff --git a/interpreter/binary/encode.ml b/interpreter/binary/encode.ml
index e4d25b2658..7519bc2e23 100644
--- a/interpreter/binary/encode.ml
+++ b/interpreter/binary/encode.ml
@@ -173,8 +173,12 @@ let encode m =
       | LocalTee x -> op 0x22; var x
       | GlobalGet x -> op 0x23; var x
       | GlobalSet x -> op 0x24; var x
+
       | TableGet x -> op 0x25; var x
       | TableSet x -> op 0x26; var x
+      | TableSize x -> op 0xfc; op 0x10; var x
+      | TableGrow x -> op 0xfc; op 0x0f; var x
+      | TableFill x -> op 0xfc; op 0x11; var x
 
       | Load ({ty = I32Type; sz = None; _} as mo) -> op 0x28; memop mo
       | Load ({ty = I64Type; sz = None; _} as mo) -> op 0x29; memop mo
@@ -485,7 +489,12 @@ let encode m =
     (* Element section *)
     let segment dat seg =
       let {index; offset; init} = seg.it in
-      var index; const offset; dat init
+      if index.it = 0l then
+        u8 0x00
+      else begin
+        u8 0x02; var index
+      end;
+      const offset; dat init
 
     let table_segment seg =
       segment (vec var) seg
diff --git a/interpreter/exec/eval.ml b/interpreter/exec/eval.ml
index 46c3b0d026..84eb2f4eb3 100644
--- a/interpreter/exec/eval.ml
+++ b/interpreter/exec/eval.ml
@@ -205,6 +205,29 @@ let rec step (c : config) : config =
         (try Table.store (table frame.inst x) i r; vs', []
         with exn -> vs', [Trapping (table_error e.at exn) @@ e.at])
 
+      | TableSize x, vs ->
+        Num (I32 (Table.size (table frame.inst x))) :: vs, []
+
+      | TableGrow x, Num (I32 delta) :: Ref r :: vs' ->
+        let tab = table frame.inst x in
+        let old_size = Table.size tab in
+        let result =
+          try Table.grow tab delta r; old_size
+          with Table.SizeOverflow | Table.SizeLimit | Table.OutOfMemory -> -1l
+        in Num (I32 result) :: vs', []
+
+      | TableFill x, Num (I32 0l) :: Ref r :: Num (I32 i) :: vs' ->
+        if I32.gt_u i (Table.size (table frame.inst x)) then
+          vs', [Trapping (table_error e.at Table.Bounds) @@ e.at]
+        else
+          vs', []
+
+      | TableFill x, Num (I32 n) :: Ref r :: Num (I32 i) :: vs' ->
+        assert (I32.lt_u i 0xffff_ffffl);
+        Ref r :: Num (I32 i) ::
+          Num (I32 (I32.sub n 1l)) :: Ref r :: Num (I32 (I32.add i 1l)) :: vs',
+          [Plain (TableSet x) @@ e.at; Plain (TableFill x) @@ e.at]
+
       | Load {offset; ty; sz; _}, Num (I32 i) :: vs' ->
         let mem = memory frame.inst (0l @@ e.at) in
         let addr = I64_convert.extend_i32_u i in
@@ -388,7 +411,7 @@ let create_func (inst : module_inst) (f : func) : func_inst =
 
 let create_table (inst : module_inst) (tab : table) : table_inst =
   let {ttype} = tab.it in
-  Table.alloc ttype
+  Table.alloc ttype NullRef
 
 let create_memory (inst : module_inst) (mem : memory) : memory_inst =
   let {mtype} = mem.it in
diff --git a/interpreter/host/spectest.ml b/interpreter/host/spectest.ml
index 6946f3cf8c..c343e1bb75 100644
--- a/interpreter/host/spectest.ml
+++ b/interpreter/host/spectest.ml
@@ -17,7 +17,8 @@ let global (GlobalType (t, _) as gt) =
     | RefType _ -> Ref NullRef
   in Global.alloc gt v
 
-let table = Table.alloc (TableType ({min = 10l; max = Some 20l}, FuncRefType))
+let table =
+  Table.alloc (TableType ({min = 10l; max = Some 20l}, FuncRefType)) NullRef
 let memory = Memory.alloc (MemoryType {min = 1l; max = Some 2l})
 let func f t = Func.alloc_host t (f t)
 
diff --git a/interpreter/runtime/table.ml b/interpreter/runtime/table.ml
index 9958b7f76f..9a5c173eab 100644
--- a/interpreter/runtime/table.ml
+++ b/interpreter/runtime/table.ml
@@ -13,18 +13,19 @@ exception Type
 exception Bounds
 exception SizeOverflow
 exception SizeLimit
+exception OutOfMemory
 
 let within_limits size = function
   | None -> true
   | Some max -> I32.le_u size max
 
-let create size =
-  try Lib.Array32.make size NullRef
-  with Invalid_argument _ -> raise Out_of_memory
+let create size r =
+  try Lib.Array32.make size r
+  with Out_of_memory | Invalid_argument _ -> raise OutOfMemory
 
-let alloc (TableType ({min; max}, elem_type)) =
+let alloc (TableType ({min; max}, elem_type)) r =
   assert (within_limits min max);
-  {content = create min; max; elem_type}
+  {content = create min r; max; elem_type}
 
 let size tab =
   Lib.Array32.length tab.content
@@ -32,12 +33,12 @@ let size tab =
 let type_of tab =
   TableType ({min = size tab; max = tab.max}, tab.elem_type)
 
-let grow tab delta =
+let grow tab delta r =
   let old_size = size tab in
   let new_size = Int32.add old_size delta in
   if I32.gt_u old_size new_size then raise SizeOverflow else
   if not (within_limits new_size tab.max) then raise SizeLimit else
-  let after = create new_size in
+  let after = create new_size r in
   Array.blit tab.content 0 after 0 (Array.length tab.content);
   tab.content <- after
 
diff --git a/interpreter/runtime/table.mli b/interpreter/runtime/table.mli
index ae5fe69105..b07b398012 100644
--- a/interpreter/runtime/table.mli
+++ b/interpreter/runtime/table.mli
@@ -11,11 +11,13 @@ exception Type
 exception Bounds
 exception SizeOverflow
 exception SizeLimit
+exception OutOfMemory
 
-val alloc : table_type -> table
+val alloc : table_type -> ref_ -> table (* raises OutOfMemory *)
 val type_of : table -> table_type
 val size : table -> size
-val grow : table -> size -> unit (* raises SizeOverflow, SizeLimit *)
+val grow : table -> size -> ref_ -> unit
+  (* raises SizeOverflow, SizeLimit, OutOfMemory *)
 
 val load : table -> index -> ref_ (* raises Bounds *)
 val store : table -> index -> ref_ -> unit (* raises Type, Bounds *)
diff --git a/interpreter/syntax/ast.ml b/interpreter/syntax/ast.ml
index da0563cde6..0f57ba31f0 100644
--- a/interpreter/syntax/ast.ml
+++ b/interpreter/syntax/ast.ml
@@ -89,6 +89,9 @@ and instr' =
   | GlobalSet of var                  (* write global variable *)
   | TableGet of var                   (* read table element *)
   | TableSet of var                   (* write table element *)
+  | TableSize of var                  (* size of table *)
+  | TableGrow of var                  (* grow table *)
+  | TableFill of var                  (* fill table with unique value *)
   | Load of loadop                    (* read memory at address *)
   | Store of storeop                  (* write memory at address *)
   | MemorySize                        (* size of linear memory *)
diff --git a/interpreter/syntax/operators.ml b/interpreter/syntax/operators.ml
index c77d1e4297..3fb6a4b415 100644
--- a/interpreter/syntax/operators.ml
+++ b/interpreter/syntax/operators.ml
@@ -10,8 +10,8 @@ let i64_const n = Const (I64 n.it @@ n.at)
 let f32_const n = Const (F32 n.it @@ n.at)
 let f64_const n = Const (F64 n.it @@ n.at)
 let ref_null = RefNull
-let ref_is_null = RefIsNull
 let ref_func x = RefFunc x
+let ref_is_null = RefIsNull
 
 let unreachable = Unreachable
 let nop = Nop
@@ -33,8 +33,12 @@ let local_set x = LocalSet x
 let local_tee x = LocalTee x
 let global_get x = GlobalGet x
 let global_set x = GlobalSet x
+
 let table_get x = TableGet x
 let table_set x = TableSet x
+let table_size x = TableSize x
+let table_grow x = TableGrow x
+let table_fill x = TableFill x
 
 let i32_load align offset = Load {ty = I32Type; align; offset; sz = None}
 let i64_load align offset = Load {ty = I64Type; align; offset; sz = None}
diff --git a/interpreter/text/arrange.ml b/interpreter/text/arrange.ml
index 2d97083aef..e2b7adaedf 100644
--- a/interpreter/text/arrange.ml
+++ b/interpreter/text/arrange.ml
@@ -245,6 +245,9 @@ let rec instr e =
     | GlobalSet x -> "global.set " ^ var x, []
     | TableGet x -> "table.get " ^ var x, []
     | TableSet x -> "table.set " ^ var x, []
+    | TableSize x -> "table.size " ^ var x, []
+    | TableGrow x -> "table.grow " ^ var x, []
+    | TableFill x -> "table.fill " ^ var x, []
     | Load op -> loadop op, []
     | Store op -> storeop op, []
     | MemorySize -> "memory.size", []
diff --git a/interpreter/text/lexer.mll b/interpreter/text/lexer.mll
index b9f253b58a..3b7ec2caa7 100644
--- a/interpreter/text/lexer.mll
+++ b/interpreter/text/lexer.mll
@@ -204,8 +204,12 @@ rule token = parse
   | "local.tee" { LOCAL_TEE }
   | "global.get" { GLOBAL_GET }
   | "global.set" { GLOBAL_SET }
+
   | "table.get" { TABLE_GET }
   | "table.set" { TABLE_SET }
+  | "table.size" { TABLE_SIZE }
+  | "table.grow" { TABLE_GROW }
+  | "table.fill" { TABLE_FILL }
 
   | (nxx as t)".load"
     { LOAD (fun a o ->
diff --git a/interpreter/text/parser.mly b/interpreter/text/parser.mly
index df2c3f85f2..576e0dd1db 100644
--- a/interpreter/text/parser.mly
+++ b/interpreter/text/parser.mly
@@ -148,13 +148,15 @@ let inline_type_explicit (c : context) x ft at =
 %token LPAR RPAR
 %token NAT INT FLOAT STRING VAR
 %token ANYREF FUNCREF NUM_TYPE MUT
-%token NOP DROP BLOCK END IF THEN ELSE SELECT LOOP BR BR_IF BR_TABLE
+%token UNREACHABLE NOP DROP SELECT
+%token BLOCK END IF THEN ELSE LOOP BR BR_IF BR_TABLE
 %token CALL CALL_INDIRECT RETURN
-%token LOCAL_GET LOCAL_SET LOCAL_TEE GLOBAL_GET GLOBAL_SET TABLE_GET TABLE_SET
+%token LOCAL_GET LOCAL_SET LOCAL_TEE GLOBAL_GET GLOBAL_SET
+%token TABLE_GET TABLE_SET TABLE_SIZE TABLE_GROW TABLE_FILL
+%token MEMORY_SIZE MEMORY_GROW
 %token LOAD STORE OFFSET_EQ_NAT ALIGN_EQ_NAT
-%token REF_NULL REF_FUNC REF_HOST REF_IS_NULL
 %token CONST UNARY BINARY TEST COMPARE CONVERT
-%token UNREACHABLE MEMORY_SIZE MEMORY_GROW
+%token REF_NULL REF_FUNC REF_HOST REF_IS_NULL
 %token FUNC START TYPE PARAM RESULT LOCAL GLOBAL
 %token TABLE ELEM MEMORY DATA OFFSET IMPORT EXPORT TABLE
 %token MODULE BIN QUOTE
@@ -326,6 +328,9 @@ plain_instr :
   | GLOBAL_SET var { fun c -> global_set ($2 c global) }
   | TABLE_GET var { fun c -> table_get ($2 c table) }
   | TABLE_SET var { fun c -> table_set ($2 c table) }
+  | TABLE_SIZE var { fun c -> table_size ($2 c table) }
+  | TABLE_GROW var { fun c -> table_grow ($2 c table) }
+  | TABLE_FILL var { fun c -> table_fill ($2 c table) }
   | LOAD offset_opt align_opt { fun c -> $1 $3 $2 }
   | STORE offset_opt align_opt { fun c -> $1 $3 $2 }
   | MEMORY_SIZE { fun c -> memory_size }
diff --git a/interpreter/valid/valid.ml b/interpreter/valid/valid.ml
index 22dcc63f7d..5946f68988 100644
--- a/interpreter/valid/valid.ml
+++ b/interpreter/valid/valid.ml
@@ -270,7 +270,7 @@ let rec check_instr (c : context) (e : instr) (s : infer_stack_type) : op_type =
     [local c x] --> [local c x]
 
   | GlobalGet x ->
-    let GlobalType (t, mut) = global c x in
+    let GlobalType (t, _mut) = global c x in
     [] --> [t]
 
   | GlobalSet x ->
@@ -279,13 +279,25 @@ let rec check_instr (c : context) (e : instr) (s : infer_stack_type) : op_type =
     [t] --> []
 
   | TableGet x ->
-    let TableType (lim, t) = table c x in
+    let TableType (_lim, t) = table c x in
     [NumType I32Type] --> [RefType t]
 
   | TableSet x ->
-    let TableType (lim, t) = table c x in
+    let TableType (_lim, t) = table c x in
     [NumType I32Type; RefType t] --> []
 
+  | TableSize x ->
+    let _tt = table c x in
+    [] --> [NumType I32Type]
+
+  | TableGrow x ->
+    let TableType (_lim, t) = table c x in
+    [RefType t; NumType I32Type] --> [NumType I32Type]
+
+  | TableFill x ->
+    let TableType (_lim, t) = table c x in
+    [NumType I32Type; RefType t; NumType I32Type] --> []
+
   | Load memop ->
     check_memop c memop (Lib.Option.map fst) e.at;
     [NumType I32Type] --> [NumType memop.ty]
diff --git a/proposals/reference-types/Overview.md b/proposals/reference-types/Overview.md
index a12571608b..44b94ae603 100644
--- a/proposals/reference-types/Overview.md
+++ b/proposals/reference-types/Overview.md
@@ -14,6 +14,7 @@ Motivation:
   - allow representing data structures containing references
 by repurposing tables as a general memory for opaque data types
   - allow manipulating function tables from within Wasm.
+  - add instructions missing from [bulk operations proposal](https://github.com/WebAssembly/bulk-memory-operations/blob/master/proposals/bulk-memory-operations/Overview.md)
 
 * Set the stage for later additions:
 
@@ -31,6 +32,8 @@ Summary:
 
 * Introduce instructions to get and set table slots.
 
+* Add missing table size, grow, fill instructions.
+
 * Allow multiple tables.
 
 Notes:
@@ -59,9 +62,9 @@ Typing extensions:
 
 * Introduce a simple subtype relation between reference types.
   - reflexive transitive closure of the following rules
-  - `t < anyref` for all reftypes `t`
-  - `nullref < anyref` and `nullref < funcref`
-  - Note: No rule `nullref < t` for all reftypes `t` -- while that is derivable from the above given the current set of types it might not hold for future reference types which don't allow null.
+  - `t <: anyref` for all reftypes `t`
+  - `nullref <: anyref` and `nullref <: funcref`
+  - Note: No rule `nullref <: t` for all reftypes `t` -- while that is derivable from the above given the current set of types it might not hold for future reference types which don't allow null.
 
 
 New/extended instructions:
@@ -74,17 +77,51 @@ New/extended instructions:
   - `ref.is_null : [anyref] -> [i32]`
 
 * The new instruction `ref.func` creates a reference to a given function.
-  - `ref.func $x : [] -> [funcref]` iff `$x` is a function
+  - `ref.func $x : [] -> [funcref]`
+    - iff `$x : func $t`
+  - allowed in constant expressions
+  - Note: the result type of this instruction may be refined by future proposals (e.g., to `[(ref $t)]`)
 
 * The new instructions `table.get` and `table.set` access tables.
-  - `table.get $x : [i32] -> [t]` iff `t` is the element type of table `$x`
-  - `table.set $x : [i32 t] -> []` iff `t` is the element type of table `$x`
-  - `table.fill $x : [i32 i32 t] -> []` iff `t` is the element type of table `$x`
+  - `table.get $x : [i32] -> [t]`
+    - iff `$x : table t`
+  - `table.set $x : [i32 t] -> []`
+    - iff `$x : table t`
+
+* The new instructions `table.size`and `table.grow` manipulate the size of a table.
+  - `table.size $x : [] -> [i32]`
+    - iff `$x : table t`
+  - `table.grow $x : [t i32] -> [i32]`
+    - iff `$x : table t`
+  - the first operand of `table.grow` is an initialisation value (for compatibility with future extensions to the type system, such as non-nullable references)
+
+* The new instruction `table.fill` fills a range in a table with a value.
+  - `table.fill $x : [i32 t i32] -> []`
+    - iff `$x : table t`
+  - the first operand is the start index of the range, the third operand its length (analoguous to `memory.fill`)
+  - traps when range+length > size of the table, but only after filling range up to size (analoguous to `memory.fill`)
+
+* The `table.init` instruction takes an additional table index as immediate.
+  - `table.init $x $y : [i32 i32 i32] -> []`
+    - iff `$x : table t`
+    - and `$y : elem t'`
+    - and `t' <: t`
+
+* The `table.copy` instruction takes two additional table indices as immediate.
+  - `table.copy $x $y : [i32 i32 i32] -> []`
+    - iff `$x : table t`
+    - and `$y : table t'`
+    - and `t' <: t`
+
+* The `call_indirect` instruction takes a table index as immediate.
+  - `call_indirect (type $t) $x : [t1* i32] -> [t2*]`
+    - iff `$t = [t1*] -> [t2*]`
+    - and `$x : table t'`
+    - and `t' <: funcref`
 
-* The `call_indirect` instruction takes a table index as immediate that identifies the table it calls through.
-  - `call_indirect (type $t) $x : [t1* i32] -> [t2*]` iff `$t` denotes the function type `[t1*] -> [t2*]` and the element type of table `$x` is a subtype of `funcref`.
-  - In the binary format, space for the index is already reserved.
-  - For backwards compatibility, the index may be omitted in the text format, in which case it defaults to 0.
+Note:
+- In the binary format, space for the additional table indices is already reserved.
+- For backwards compatibility, all table indices may be omitted in the text format, in which case they default to 0 (for `table.copy`, both indices must be either present or absent).
 
 
 Table extensions:
diff --git a/test/core/memory_grow.wast b/test/core/memory_grow.wast
index 8a87c77c64..aa56297d25 100644
--- a/test/core/memory_grow.wast
+++ b/test/core/memory_grow.wast
@@ -312,8 +312,8 @@
 (assert_invalid
   (module
     (memory 0)
-    (func $type-size-empty
-      (memory.grow) (drop)
+    (func $type-size-empty-vs-i32 (result i32)
+      (memory.grow)
     )
   )
   "type mismatch"
@@ -321,9 +321,9 @@
 (assert_invalid
   (module
     (memory 0)
-    (func $type-size-empty-in-block
+    (func $type-size-empty-vs-i32-in-block (result i32)
       (i32.const 0)
-      (block (memory.grow) (drop))
+      (block (result i32) (memory.grow))
     )
   )
   "type mismatch"
@@ -331,9 +331,9 @@
 (assert_invalid
   (module
     (memory 0)
-    (func $type-size-empty-in-loop
+    (func $type-size-empty-vs-i32-in-loop (result i32)
       (i32.const 0)
-      (loop (memory.grow) (drop))
+      (loop (result i32) (memory.grow))
     )
   )
   "type mismatch"
@@ -341,15 +341,39 @@
 (assert_invalid
   (module
     (memory 0)
-    (func $type-size-empty-in-then
+    (func $type-size-empty-vs-i32-in-then (result i32)
       (i32.const 0) (i32.const 0)
-      (if (then (memory.grow) (drop)))
+      (if (result i32) (then (memory.grow)))
     )
   )
   "type mismatch"
 )
 
+(assert_invalid
+  (module
+    (memory 1)
+    (func $type-size-f32-vs-i32 (result i32)
+      (memory.grow (f32.const 0))
+    )
+  )
+  "type mismatch"
+)
 
-;; Type check
-
-(assert_invalid (module (memory 1) (func (result i32) (memory.grow (f32.const 0)))) "type mismatch")
+(assert_invalid
+  (module
+    (memory 1)
+    (func $type-result-i32-vs-empty
+      (memory.grow (i32.const 0))
+    )
+  )
+  "type mismatch"
+)
+(assert_invalid
+  (module
+    (memory 1)
+    (func $type-result-i32-vs-f32 (result f32)
+      (memory.grow (i32.const 0))
+    )
+  )
+  "type mismatch"
+)
diff --git a/test/core/table_fill.wast b/test/core/table_fill.wast
new file mode 100644
index 0000000000..8ec66b69c2
--- /dev/null
+++ b/test/core/table_fill.wast
@@ -0,0 +1,153 @@
+(module
+  (table $t 10 anyref)
+
+  (func (export "fill") (param $i i32) (param $r anyref) (param $n i32)
+    (table.fill $t (local.get $i) (local.get $r) (local.get $n))
+  )
+
+  (func (export "get") (param $i i32) (result anyref)
+    (table.get $t (local.get $i))
+  )
+)
+
+(assert_return (invoke "get" (i32.const 1)) (ref.null))
+(assert_return (invoke "get" (i32.const 2)) (ref.null))
+(assert_return (invoke "get" (i32.const 3)) (ref.null))
+(assert_return (invoke "get" (i32.const 4)) (ref.null))
+(assert_return (invoke "get" (i32.const 5)) (ref.null))
+
+(assert_return (invoke "fill" (i32.const 2) (ref.host 1) (i32.const 3)))
+(assert_return (invoke "get" (i32.const 1)) (ref.null))
+(assert_return (invoke "get" (i32.const 2)) (ref.host 1))
+(assert_return (invoke "get" (i32.const 3)) (ref.host 1))
+(assert_return (invoke "get" (i32.const 4)) (ref.host 1))
+(assert_return (invoke "get" (i32.const 5)) (ref.null))
+
+(assert_return (invoke "fill" (i32.const 4) (ref.host 2) (i32.const 2)))
+(assert_return (invoke "get" (i32.const 3)) (ref.host 1))
+(assert_return (invoke "get" (i32.const 4)) (ref.host 2))
+(assert_return (invoke "get" (i32.const 5)) (ref.host 2))
+(assert_return (invoke "get" (i32.const 6)) (ref.null))
+
+(assert_return (invoke "fill" (i32.const 4) (ref.host 3) (i32.const 0)))
+(assert_return (invoke "get" (i32.const 3)) (ref.host 1))
+(assert_return (invoke "get" (i32.const 4)) (ref.host 2))
+(assert_return (invoke "get" (i32.const 5)) (ref.host 2))
+
+(assert_return (invoke "fill" (i32.const 8) (ref.host 4) (i32.const 2)))
+(assert_return (invoke "get" (i32.const 7)) (ref.null))
+(assert_return (invoke "get" (i32.const 8)) (ref.host 4))
+(assert_return (invoke "get" (i32.const 9)) (ref.host 4))
+
+(assert_return (invoke "fill" (i32.const 9) (ref.null) (i32.const 1)))
+(assert_return (invoke "get" (i32.const 8)) (ref.host 4))
+(assert_return (invoke "get" (i32.const 9)) (ref.null))
+
+(assert_return (invoke "fill" (i32.const 10) (ref.host 5) (i32.const 0)))
+(assert_return (invoke "get" (i32.const 9)) (ref.null))
+
+(assert_trap
+  (invoke "fill" (i32.const 8) (ref.host 6) (i32.const 3))
+  "out of bounds"
+)
+(assert_return (invoke "get" (i32.const 7)) (ref.null))
+(assert_return (invoke "get" (i32.const 8)) (ref.host 6))
+(assert_return (invoke "get" (i32.const 9)) (ref.host 6))
+
+(assert_trap
+  (invoke "fill" (i32.const 11) (ref.null) (i32.const 0))
+  "out of bounds"
+)
+
+(assert_trap
+  (invoke "fill" (i32.const 11) (ref.null) (i32.const 10))
+  "out of bounds"
+)
+
+
+;; Type errors
+
+(assert_invalid
+  (module
+    (table $t 10 anyref)
+    (func $type-index-value-length-empty-vs-i32-i32
+      (table.fill $t)
+    )
+  )
+  "type mismatch"
+)
+(assert_invalid
+  (module
+    (table $t 10 anyref)
+    (func $type-index-empty-vs-i32
+      (table.fill $t (ref.null) (i32.const 1))
+    )
+  )
+  "type mismatch"
+)
+(assert_invalid
+  (module
+    (table $t 10 anyref)
+    (func $type-value-empty-vs
+      (table.fill $t (i32.const 1) (i32.const 1))
+    )
+  )
+  "type mismatch"
+)
+(assert_invalid
+  (module
+    (table $t 10 anyref)
+    (func $type-length-empty-vs-i32
+      (table.fill $t (i32.const 1) (ref.null))
+    )
+  )
+  "type mismatch"
+)
+(assert_invalid
+  (module
+    (table $t 0 anyref)
+    (func $type-index-f32-vs-i32
+      (table.fill $t (f32.const 1) (ref.null) (i32.const 1))
+    )
+  )
+  "type mismatch"
+)
+(assert_invalid
+  (module
+    (table $t 0 funcref)
+    (func $type-value-vs-funcref (param $r anyref)
+      (table.fill $t (i32.const 1) (local.get $r) (i32.const 1))
+    )
+  )
+  "type mismatch"
+)
+(assert_invalid
+  (module
+    (table $t 0 anyref)
+    (func $type-length-f32-vs-i32
+      (table.fill $t (i32.const 1) (ref.null) (f32.const 1))
+    )
+  )
+  "type mismatch"
+)
+
+(assert_invalid
+  (module
+    (table $t1 1 anyref)
+    (table $t2 1 funcref)
+    (func $type-value-anyref-vs-funcref-multi (param $r anyref)
+      (table.fill $t2 (i32.const 0) (local.get $r) (i32.const 1))
+    )
+  )
+  "type mismatch"
+)
+
+(assert_invalid
+  (module
+    (table $t 1 anyref)
+    (func $type-result-empty-vs-num (result i32)
+      (table.fill $t (i32.const 0) (ref.null) (i32.const 1))
+    )
+  )
+  "type mismatch"
+)
diff --git a/test/core/table_get.wast b/test/core/table_get.wast
index bd0c30c9fb..02855a8311 100644
--- a/test/core/table_get.wast
+++ b/test/core/table_get.wast
@@ -33,3 +33,55 @@
 (assert_trap (invoke "get-funcref" (i32.const 3)) "out of bounds")
 (assert_trap (invoke "get-anyref" (i32.const -1)) "out of bounds")
 (assert_trap (invoke "get-funcref" (i32.const -1)) "out of bounds")
+
+
+;; Type errors
+
+(assert_invalid
+  (module
+    (table $t 10 anyref)
+    (func $type-index-empty-vs-i32 (result anyref)
+      (table.get $t)
+    )
+  )
+  "type mismatch"
+)
+(assert_invalid
+  (module
+    (table $t 10 anyref)
+    (func $type-index-f32-vs-i32 (result anyref)
+      (table.get $t (f32.const 1))
+    )
+  )
+  "type mismatch"
+)
+
+(assert_invalid
+  (module
+    (table $t 10 anyref)
+    (func $type-result-anyref-vs-empty
+      (table.get $t (i32.const 0))
+    )
+  )
+  "type mismatch"
+)
+(assert_invalid
+  (module
+    (table $t 10 anyref)
+    (func $type-result-anyref-vs-funcref (result funcref)
+      (table.get $t (i32.const 1))
+    )
+  )
+  "type mismatch"
+)
+
+(assert_invalid
+  (module
+    (table $t1 1 funcref)
+    (table $t2 1 anyref)
+    (func $type-result-anyref-vs-funcref-multi (result funcref)
+      (table.get $t2 (i32.const 0))
+    )
+  )
+  "type mismatch"
+)
diff --git a/test/core/table_grow.wast b/test/core/table_grow.wast
new file mode 100644
index 0000000000..bd9c395a4e
--- /dev/null
+++ b/test/core/table_grow.wast
@@ -0,0 +1,160 @@
+(module
+  (table $t 0 anyref)
+
+  (func (export "get") (param $i i32) (result anyref) (table.get $t (local.get $i)))
+  (func (export "set") (param $i i32) (param $r anyref) (table.set $t (local.get $i) (local.get $r)))
+
+  (func (export "grow") (param $sz i32) (param $init anyref) (result i32)
+    (table.grow $t (local.get $init) (local.get $sz))
+  )
+  (func (export "size") (result i32) (table.size $t))
+)
+
+(assert_return (invoke "size") (i32.const 0))
+(assert_trap (invoke "set" (i32.const 0) (ref.host 2)) "out of bounds table access")
+(assert_trap (invoke "get" (i32.const 0)) "out of bounds table access")
+
+(assert_return (invoke "grow" (i32.const 1) (ref.null)) (i32.const 0))
+(assert_return (invoke "size") (i32.const 1))
+(assert_return (invoke "get" (i32.const 0)) (ref.null))
+(assert_return (invoke "set" (i32.const 0) (ref.host 2)))
+(assert_return (invoke "get" (i32.const 0)) (ref.host 2))
+(assert_trap (invoke "set" (i32.const 1) (ref.host 2)) "out of bounds table access")
+(assert_trap (invoke "get" (i32.const 1)) "out of bounds table access")
+
+(assert_return (invoke "grow" (i32.const 4) (ref.host 3)) (i32.const 1))
+(assert_return (invoke "size") (i32.const 5))
+(assert_return (invoke "get" (i32.const 0)) (ref.host 2))
+(assert_return (invoke "set" (i32.const 0) (ref.host 2)))
+(assert_return (invoke "get" (i32.const 0)) (ref.host 2))
+(assert_return (invoke "get" (i32.const 1)) (ref.host 3))
+(assert_return (invoke "get" (i32.const 4)) (ref.host 3))
+(assert_return (invoke "set" (i32.const 4) (ref.host 4)))
+(assert_return (invoke "get" (i32.const 4)) (ref.host 4))
+(assert_trap (invoke "set" (i32.const 5) (ref.host 2)) "out of bounds table access")
+(assert_trap (invoke "get" (i32.const 5)) "out of bounds table access")
+
+
+(module
+  (table $t 0 anyref)
+  (func (export "grow") (param i32) (result i32)
+    (table.grow $t (ref.null) (local.get 0))
+  )
+)
+
+(assert_return (invoke "grow" (i32.const 0)) (i32.const 0))
+(assert_return (invoke "grow" (i32.const 1)) (i32.const 0))
+(assert_return (invoke "grow" (i32.const 0)) (i32.const 1))
+(assert_return (invoke "grow" (i32.const 2)) (i32.const 1))
+(assert_return (invoke "grow" (i32.const 800)) (i32.const 3))
+
+
+(module
+  (table $t 0 10 anyref)
+  (func (export "grow") (param i32) (result i32)
+    (table.grow $t (ref.null) (local.get 0))
+  )
+)
+
+(assert_return (invoke "grow" (i32.const 0)) (i32.const 0))
+(assert_return (invoke "grow" (i32.const 1)) (i32.const 0))
+(assert_return (invoke "grow" (i32.const 1)) (i32.const 1))
+(assert_return (invoke "grow" (i32.const 2)) (i32.const 2))
+(assert_return (invoke "grow" (i32.const 6)) (i32.const 4))
+(assert_return (invoke "grow" (i32.const 0)) (i32.const 10))
+(assert_return (invoke "grow" (i32.const 1)) (i32.const -1))
+(assert_return (invoke "grow" (i32.const 0x10000)) (i32.const -1))
+
+
+(module
+  (table $t 10 anyref)
+  (func (export "grow") (param i32) (result i32)
+    (table.grow $t (ref.null) (local.get 0))
+  )
+  (func (export "check-table-null") (param i32 i32) (result anyref)
+    (local anyref)
+    (local.set 2 (ref.func 1))
+    (block
+      (loop
+        (local.set 2 (table.get $t (local.get 0)))
+        (br_if 1 (i32.eqz (ref.is_null (local.get 2))))
+        (br_if 1 (i32.ge_u (local.get 0) (local.get 1)))
+        (local.set 0 (i32.add (local.get 0) (i32.const 1)))
+        (br_if 0 (i32.le_u (local.get 0) (local.get 1)))
+      )
+    )
+    (local.get 2)
+  )
+)
+
+(assert_return (invoke "check-table-null" (i32.const 0) (i32.const 9)) (ref.null))
+(assert_return (invoke "grow" (i32.const 10)) (i32.const 10))
+(assert_return (invoke "check-table-null" (i32.const 0) (i32.const 19)) (ref.null))
+
+
+;; Type errors
+
+(assert_invalid
+  (module
+    (table $t 0 anyref)
+    (func $type-init-size-empty-vs-i32-anyref (result i32)
+      (table.grow $t)
+    )
+  )
+  "type mismatch"
+)
+(assert_invalid
+  (module
+    (table $t 0 anyref)
+    (func $type-size-empty-vs-i32 (result i32)
+      (table.grow $t (ref.null))
+    )
+  )
+  "type mismatch"
+)
+(assert_invalid
+  (module
+    (table $t 0 anyref)
+    (func $type-init-empty-vs-anyref (result i32)
+      (table.grow $t (i32.const 1))
+    )
+  )
+  "type mismatch"
+)
+(assert_invalid
+  (module
+    (table $t 0 anyref)
+    (func $type-size-f32-vs-i32 (result i32)
+      (table.grow $t (ref.null) (f32.const 1))
+    )
+  )
+  "type mismatch"
+)
+(assert_invalid
+  (module
+    (table $t 0 funcref)
+    (func $type-init-anyref-vs-funcref (param $r anyref) (result i32)
+      (table.grow $t (local.get $r) (i32.const 1))
+    )
+  )
+  "type mismatch"
+)
+
+(assert_invalid
+  (module
+    (table $t 1 anyref)
+    (func $type-result-i32-vs-empty
+      (table.grow $t (ref.null) (i32.const 0))
+    )
+  )
+  "type mismatch"
+)
+(assert_invalid
+  (module
+    (table $t 1 anyref)
+    (func $type-result-i32-vs-f32 (result f32)
+      (table.grow $t (ref.null) (i32.const 0))
+    )
+  )
+  "type mismatch"
+)
diff --git a/test/core/table_set.wast b/test/core/table_set.wast
index 9cb231b57c..5d2a6a2688 100644
--- a/test/core/table_set.wast
+++ b/test/core/table_set.wast
@@ -46,3 +46,73 @@
 (assert_trap (invoke "set-funcref-from" (i32.const 3) (i32.const 1)) "out of bounds")
 (assert_trap (invoke "set-anyref" (i32.const -1) (ref.host 0)) "out of bounds")
 (assert_trap (invoke "set-funcref-from" (i32.const -1) (i32.const 1)) "out of bounds")
+
+
+;; Type errors
+
+(assert_invalid
+  (module
+    (table $t 10 anyref)
+    (func $type-index-value-empty-vs-i32-anyref 
+      (table.set $t)
+    )
+  )
+  "type mismatch"
+)
+(assert_invalid
+  (module
+    (table $t 10 anyref)
+    (func $type-index-empty-vs-i32
+      (table.set $t (ref.null))
+    )
+  )
+  "type mismatch"
+)
+(assert_invalid
+  (module
+    (table $t 10 anyref)
+    (func $type-value-empty-vs-anyref
+      (table.set $t (i32.const 1))
+    )
+  )
+  "type mismatch"
+)
+(assert_invalid
+  (module
+    (table $t 10 anyref)
+    (func $type-size-f32-vs-i32
+      (table.set $t (f32.const 1) (ref.null))
+    )
+  )
+  "type mismatch"
+)
+(assert_invalid
+  (module
+    (table $t 10 funcref)
+    (func $type-value-anyref-vs-funcref (param $r anyref)
+      (table.set $t (i32.const 1) (local.get $r))
+    )
+  )
+  "type mismatch"
+)
+
+(assert_invalid
+  (module
+    (table $t1 1 anyref)
+    (table $t2 1 funcref)
+    (func $type-value-anyref-vs-funcref-multi (param $r anyref)
+      (table.set $t2 (i32.const 0) (local.get $r))
+    )
+  )
+  "type mismatch"
+)
+
+(assert_invalid
+  (module
+    (table $t 10 anyref)
+    (func $type-result-empty-vs-num (result i32)
+      (table.set $t (i32.const 0) (ref.null))
+    )
+  )
+  "type mismatch"
+)
diff --git a/test/core/table_size.wast b/test/core/table_size.wast
new file mode 100644
index 0000000000..5817104a4c
--- /dev/null
+++ b/test/core/table_size.wast
@@ -0,0 +1,86 @@
+(module
+  (table $t0 0 anyref)
+  (table $t1 1 anyref)
+  (table $t2 0 2 anyref)
+  (table $t3 3 8 anyref)
+
+  (func (export "size-t0") (result i32) (table.size $t0))
+  (func (export "size-t1") (result i32) (table.size $t1))
+  (func (export "size-t2") (result i32) (table.size $t2))
+  (func (export "size-t3") (result i32) (table.size $t3))
+
+  (func (export "grow-t0") (param $sz i32)
+    (drop (table.grow $t0 (ref.null) (local.get $sz)))
+  )
+  (func (export "grow-t1") (param $sz i32)
+    (drop (table.grow $t1 (ref.null) (local.get $sz)))
+  )
+  (func (export "grow-t2") (param $sz i32)
+    (drop (table.grow $t2 (ref.null) (local.get $sz)))
+  )
+  (func (export "grow-t3") (param $sz i32)
+    (drop (table.grow $t3 (ref.null) (local.get $sz)))
+  )
+)
+
+(assert_return (invoke "size-t0") (i32.const 0))
+(assert_return (invoke "grow-t0" (i32.const 1)))
+(assert_return (invoke "size-t0") (i32.const 1))
+(assert_return (invoke "grow-t0" (i32.const 4)))
+(assert_return (invoke "size-t0") (i32.const 5))
+(assert_return (invoke "grow-t0" (i32.const 0)))
+(assert_return (invoke "size-t0") (i32.const 5))
+
+(assert_return (invoke "size-t1") (i32.const 1))
+(assert_return (invoke "grow-t1" (i32.const 1)))
+(assert_return (invoke "size-t1") (i32.const 2))
+(assert_return (invoke "grow-t1" (i32.const 4)))
+(assert_return (invoke "size-t1") (i32.const 6))
+(assert_return (invoke "grow-t1" (i32.const 0)))
+(assert_return (invoke "size-t1") (i32.const 6))
+
+(assert_return (invoke "size-t2") (i32.const 0))
+(assert_return (invoke "grow-t2" (i32.const 3)))
+(assert_return (invoke "size-t2") (i32.const 0))
+(assert_return (invoke "grow-t2" (i32.const 1)))
+(assert_return (invoke "size-t2") (i32.const 1))
+(assert_return (invoke "grow-t2" (i32.const 0)))
+(assert_return (invoke "size-t2") (i32.const 1))
+(assert_return (invoke "grow-t2" (i32.const 4)))
+(assert_return (invoke "size-t2") (i32.const 1))
+(assert_return (invoke "grow-t2" (i32.const 1)))
+(assert_return (invoke "size-t2") (i32.const 2))
+
+(assert_return (invoke "size-t3") (i32.const 3))
+(assert_return (invoke "grow-t3" (i32.const 1)))
+(assert_return (invoke "size-t3") (i32.const 4))
+(assert_return (invoke "grow-t3" (i32.const 3)))
+(assert_return (invoke "size-t3") (i32.const 7))
+(assert_return (invoke "grow-t3" (i32.const 0)))
+(assert_return (invoke "size-t3") (i32.const 7))
+(assert_return (invoke "grow-t3" (i32.const 2)))
+(assert_return (invoke "size-t3") (i32.const 7))
+(assert_return (invoke "grow-t3" (i32.const 1)))
+(assert_return (invoke "size-t3") (i32.const 8))
+
+
+;; Type errors
+
+(assert_invalid
+  (module
+    (table $t 1 anyref)
+    (func $type-result-i32-vs-empty
+      (table.size $t)
+    )
+  )
+  "type mismatch"
+)
+(assert_invalid
+  (module
+    (table $t 1 anyref)
+    (func $type-result-i32-vs-f32 (result f32)
+      (table.size $t)
+    )
+  )
+  "type mismatch"
+)

From 40785fff4d6d18147301638f530b567fec7e43d9 Mon Sep 17 00:00:00 2001
From: Lars T Hansen 
Date: Thu, 4 Apr 2019 07:44:34 +0200
Subject: [PATCH 075/199] Increase the table count limit to 100,000

---
 document/js-api/index.bs  | 2 +-
 test/js-api/limits.any.js | 2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/document/js-api/index.bs b/document/js-api/index.bs
index 754634977b..cb27697345 100644
--- a/document/js-api/index.bs
+++ b/document/js-api/index.bs
@@ -1112,7 +1112,7 @@ In practice, an implementation may run out of resources for valid modules below
 
  • The maximum number of globals defined in a module is 1000000.
  • The maximum number of data segments defined in a module is 100000.
  • -
  • The maximum number of tables, including declared or imported tables, is 1.
  • +
  • The maximum number of tables, including declared or imported tables, is 100000.
  • The maximum size of a table is 10000000.
  • The maximum number of table entries in any table initialization is 10000000.
  • The maximum number of memories, including declared or imported memories, is 1.
  • diff --git a/test/js-api/limits.any.js b/test/js-api/limits.any.js index 7ab983d466..d49a51eb1d 100644 --- a/test/js-api/limits.any.js +++ b/test/js-api/limits.any.js @@ -17,7 +17,7 @@ const kJSEmbeddingMaxFunctionParams = 1000; const kJSEmbeddingMaxFunctionReturns = 1; const kJSEmbeddingMaxTableSize = 10000000; const kJSEmbeddingMaxElementSegments = 10000000; -const kJSEmbeddingMaxTables = 1; +const kJSEmbeddingMaxTables = 100000; const kJSEmbeddingMaxMemories = 1; // This function runs the {gen} function with the values {min}, {limit}, and From fcef8d6dd27b1a384c9e4c1e45bb9cdae5c3d133 Mon Sep 17 00:00:00 2001 From: Ben Smith Date: Fri, 5 Apr 2019 14:52:12 -0700 Subject: [PATCH 076/199] [spec] Use `data.drop` instead of `memory.drop` --- document/core/binary/instructions.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/document/core/binary/instructions.rst b/document/core/binary/instructions.rst index 3321dbf879..b119b2e99f 100644 --- a/document/core/binary/instructions.rst +++ b/document/core/binary/instructions.rst @@ -183,7 +183,7 @@ Each variant of :ref:`memory instruction ` is encoded with \hex{3F}~~\hex{00} &\Rightarrow& \MEMORYSIZE \\ &&|& \hex{40}~~\hex{00} &\Rightarrow& \MEMORYGROW \\ &&|& \hex{FC}~\hex{08}~~\hex{00}~x{:}\Bdataidx &\Rightarrow& \MEMORYINIT~x \\ &&|& - \hex{FC}~\hex{09}~~x{:}\Bdataidx &\Rightarrow& \MEMORYDROP~x \\ &&|& + \hex{FC}~\hex{09}~~x{:}\Bdataidx &\Rightarrow& \DATADROP~x \\ &&|& \hex{FC}~\hex{0A}~~\hex{00}~~\hex{00} &\Rightarrow& \MEMORYCOPY \\ &&|& \hex{FC}~\hex{0B}~~\hex{00} &\Rightarrow& \MEMORYFILL \\ \end{array} From d346a8f29202d4cd8649296acec941e02f00e884 Mon Sep 17 00:00:00 2001 From: Ben Smith Date: Fri, 5 Apr 2019 15:48:51 -0700 Subject: [PATCH 077/199] [spec] Update instruction index (#81) Fixes issue #77. --- document/core/appendix/index-instructions.rst | 399 +++++++++--------- 1 file changed, 203 insertions(+), 196 deletions(-) diff --git a/document/core/appendix/index-instructions.rst b/document/core/appendix/index-instructions.rst index 3e294ba120..42b6770b8b 100644 --- a/document/core/appendix/index-instructions.rst +++ b/document/core/appendix/index-instructions.rst @@ -4,199 +4,206 @@ Index of Instructions --------------------- -====================================== ================ ========================================== ======================================== =============================================================== -Instruction Binary Opcode Type Validation Execution -====================================== ================ ========================================== ======================================== =============================================================== -:math:`\UNREACHABLE` :math:`\hex{00}` :math:`[t_1^\ast] \to [t_2^\ast]` :ref:`validation ` :ref:`execution ` -:math:`\NOP` :math:`\hex{01}` :math:`[] \to []` :ref:`validation ` :ref:`execution ` -:math:`\BLOCK~[t^?]` :math:`\hex{02}` :math:`[] \to [t^\ast]` :ref:`validation ` :ref:`execution ` -:math:`\LOOP~[t^?]` :math:`\hex{03}` :math:`[] \to [t^\ast]` :ref:`validation ` :ref:`execution ` -:math:`\IF~[t^?]` :math:`\hex{04}` :math:`[] \to [t^\ast]` :ref:`validation ` :ref:`execution ` -:math:`\ELSE` :math:`\hex{05}` -(reserved) :math:`\hex{06}` -(reserved) :math:`\hex{07}` -(reserved) :math:`\hex{08}` -(reserved) :math:`\hex{09}` -(reserved) :math:`\hex{0A}` -:math:`\END` :math:`\hex{0B}` -:math:`\BR~l` :math:`\hex{0C}` :math:`[t_1^\ast~t^?] \to [t_2^\ast]` :ref:`validation ` :ref:`execution ` -:math:`\BRIF~l` :math:`\hex{0D}` :math:`[t^?~\I32] \to [t^?]` :ref:`validation ` :ref:`execution ` -:math:`\BRTABLE~l^\ast~l` :math:`\hex{0E}` :math:`[t_1^\ast~t^?~\I32] \to [t_2^\ast]` :ref:`validation ` :ref:`execution ` -:math:`\RETURN` :math:`\hex{0F}` :math:`[t_1^\ast~t^?] \to [t_2^\ast]` :ref:`validation ` :ref:`execution ` -:math:`\CALL~x` :math:`\hex{10}` :math:`[t_1^\ast] \to [t_2^\ast]` :ref:`validation ` :ref:`execution ` -:math:`\CALLINDIRECT~x` :math:`\hex{11}` :math:`[t_1^\ast~\I32] \to [t_2^\ast]` :ref:`validation ` :ref:`execution ` -(reserved) :math:`\hex{12}` -(reserved) :math:`\hex{13}` -(reserved) :math:`\hex{14}` -(reserved) :math:`\hex{15}` -(reserved) :math:`\hex{16}` -(reserved) :math:`\hex{17}` -(reserved) :math:`\hex{18}` -(reserved) :math:`\hex{19}` -:math:`\DROP` :math:`\hex{1A}` :math:`[t] \to []` :ref:`validation ` :ref:`execution ` -:math:`\SELECT` :math:`\hex{1B}` :math:`[t~t~\I32] \to [t]` :ref:`validation ` :ref:`execution ` -(reserved) :math:`\hex{1C}` -(reserved) :math:`\hex{1D}` -(reserved) :math:`\hex{1E}` -(reserved) :math:`\hex{1F}` -:math:`\LOCALGET~x` :math:`\hex{20}` :math:`[] \to [t]` :ref:`validation ` :ref:`execution ` -:math:`\LOCALSET~x` :math:`\hex{21}` :math:`[t] \to []` :ref:`validation ` :ref:`execution ` -:math:`\LOCALTEE~x` :math:`\hex{22}` :math:`[t] \to [t]` :ref:`validation ` :ref:`execution ` -:math:`\GLOBALGET~x` :math:`\hex{23}` :math:`[] \to [t]` :ref:`validation ` :ref:`execution ` -:math:`\GLOBALSET~x` :math:`\hex{24}` :math:`[t] \to []` :ref:`validation ` :ref:`execution ` -(reserved) :math:`\hex{25}` -(reserved) :math:`\hex{26}` -(reserved) :math:`\hex{27}` -:math:`\I32.\LOAD~\memarg` :math:`\hex{28}` :math:`[\I32] \to [\I32]` :ref:`validation ` :ref:`execution ` -:math:`\I64.\LOAD~\memarg` :math:`\hex{29}` :math:`[\I32] \to [\I64]` :ref:`validation ` :ref:`execution ` -:math:`\F32.\LOAD~\memarg` :math:`\hex{2A}` :math:`[\I32] \to [\F32]` :ref:`validation ` :ref:`execution ` -:math:`\F64.\LOAD~\memarg` :math:`\hex{2B}` :math:`[\I32] \to [\F64]` :ref:`validation ` :ref:`execution ` -:math:`\I32.\LOAD\K{8\_s}~\memarg` :math:`\hex{2C}` :math:`[\I32] \to [\I32]` :ref:`validation ` :ref:`execution ` -:math:`\I32.\LOAD\K{8\_u}~\memarg` :math:`\hex{2D}` :math:`[\I32] \to [\I32]` :ref:`validation ` :ref:`execution ` -:math:`\I32.\LOAD\K{16\_s}~\memarg` :math:`\hex{2E}` :math:`[\I32] \to [\I32]` :ref:`validation ` :ref:`execution ` -:math:`\I32.\LOAD\K{16\_u}~\memarg` :math:`\hex{2F}` :math:`[\I32] \to [\I32]` :ref:`validation ` :ref:`execution ` -:math:`\I64.\LOAD\K{8\_s}~\memarg` :math:`\hex{30}` :math:`[\I32] \to [\I64]` :ref:`validation ` :ref:`execution ` -:math:`\I64.\LOAD\K{8\_u}~\memarg` :math:`\hex{31}` :math:`[\I32] \to [\I64]` :ref:`validation ` :ref:`execution ` -:math:`\I64.\LOAD\K{16\_s}~\memarg` :math:`\hex{32}` :math:`[\I32] \to [\I64]` :ref:`validation ` :ref:`execution ` -:math:`\I64.\LOAD\K{16\_u}~\memarg` :math:`\hex{33}` :math:`[\I32] \to [\I64]` :ref:`validation ` :ref:`execution ` -:math:`\I64.\LOAD\K{32\_s}~\memarg` :math:`\hex{34}` :math:`[\I32] \to [\I64]` :ref:`validation ` :ref:`execution ` -:math:`\I64.\LOAD\K{32\_u}~\memarg` :math:`\hex{35}` :math:`[\I32] \to [\I64]` :ref:`validation ` :ref:`execution ` -:math:`\I32.\STORE~\memarg` :math:`\hex{36}` :math:`[\I32~\I32] \to []` :ref:`validation ` :ref:`execution ` -:math:`\I64.\STORE~\memarg` :math:`\hex{37}` :math:`[\I32~\I64] \to []` :ref:`validation ` :ref:`execution ` -:math:`\F32.\STORE~\memarg` :math:`\hex{38}` :math:`[\I32~\F32] \to []` :ref:`validation ` :ref:`execution ` -:math:`\F64.\STORE~\memarg` :math:`\hex{39}` :math:`[\I32~\F64] \to []` :ref:`validation ` :ref:`execution ` -:math:`\I32.\STORE\K{8}~\memarg` :math:`\hex{3A}` :math:`[\I32~\I32] \to []` :ref:`validation ` :ref:`execution ` -:math:`\I32.\STORE\K{16}~\memarg` :math:`\hex{3B}` :math:`[\I32~\I32] \to []` :ref:`validation ` :ref:`execution ` -:math:`\I64.\STORE\K{8}~\memarg` :math:`\hex{3C}` :math:`[\I32~\I64] \to []` :ref:`validation ` :ref:`execution ` -:math:`\I64.\STORE\K{16}~\memarg` :math:`\hex{3D}` :math:`[\I32~\I64] \to []` :ref:`validation ` :ref:`execution ` -:math:`\I64.\STORE\K{32}~\memarg` :math:`\hex{3E}` :math:`[\I32~\I64] \to []` :ref:`validation ` :ref:`execution ` -:math:`\MEMORYSIZE` :math:`\hex{3F}` :math:`[] \to [\I32]` :ref:`validation ` :ref:`execution ` -:math:`\MEMORYGROW` :math:`\hex{40}` :math:`[\I32] \to [\I32]` :ref:`validation ` :ref:`execution ` -:math:`\I32.\CONST~\i32` :math:`\hex{41}` :math:`[] \to [\I32]` :ref:`validation ` :ref:`execution ` -:math:`\I64.\CONST~\i64` :math:`\hex{42}` :math:`[] \to [\I64]` :ref:`validation ` :ref:`execution ` -:math:`\F32.\CONST~\f32` :math:`\hex{43}` :math:`[] \to [\F32]` :ref:`validation ` :ref:`execution ` -:math:`\F64.\CONST~\f64` :math:`\hex{44}` :math:`[] \to [\F64]` :ref:`validation ` :ref:`execution ` -:math:`\I32.\EQZ` :math:`\hex{45}` :math:`[\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I32.\EQ` :math:`\hex{46}` :math:`[\I32~\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I32.\NE` :math:`\hex{47}` :math:`[\I32~\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I32.\LT\K{\_s}` :math:`\hex{48}` :math:`[\I32~\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I32.\LT\K{\_u}` :math:`\hex{49}` :math:`[\I32~\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I32.\GT\K{\_s}` :math:`\hex{4A}` :math:`[\I32~\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I32.\GT\K{\_u}` :math:`\hex{4B}` :math:`[\I32~\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I32.\LE\K{\_s}` :math:`\hex{4C}` :math:`[\I32~\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I32.\LE\K{\_u}` :math:`\hex{4D}` :math:`[\I32~\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I32.\GE\K{\_s}` :math:`\hex{4E}` :math:`[\I32~\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I32.\GE\K{\_u}` :math:`\hex{4F}` :math:`[\I32~\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I64.\EQZ` :math:`\hex{50}` :math:`[\I64] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I64.\EQ` :math:`\hex{51}` :math:`[\I64~\I64] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I64.\NE` :math:`\hex{52}` :math:`[\I64~\I64] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I64.\LT\K{\_s}` :math:`\hex{53}` :math:`[\I64~\I64] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I64.\LT\K{\_u}` :math:`\hex{54}` :math:`[\I64~\I64] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I64.\GT\K{\_s}` :math:`\hex{55}` :math:`[\I64~\I64] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I64.\GT\K{\_u}` :math:`\hex{56}` :math:`[\I64~\I64] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I64.\LE\K{\_s}` :math:`\hex{57}` :math:`[\I64~\I64] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I64.\LE\K{\_u}` :math:`\hex{58}` :math:`[\I64~\I64] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I64.\GE\K{\_s}` :math:`\hex{59}` :math:`[\I64~\I64] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I64.\GE\K{\_u}` :math:`\hex{5A}` :math:`[\I64~\I64] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F32.\EQ` :math:`\hex{5B}` :math:`[\F32~\F32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F32.\NE` :math:`\hex{5C}` :math:`[\F32~\F32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F32.\LT` :math:`\hex{5D}` :math:`[\F32~\F32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F32.\GT` :math:`\hex{5E}` :math:`[\F32~\F32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F32.\LE` :math:`\hex{5F}` :math:`[\F32~\F32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F32.\GE` :math:`\hex{60}` :math:`[\F32~\F32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F64.\EQ` :math:`\hex{61}` :math:`[\F64~\F64] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F64.\NE` :math:`\hex{62}` :math:`[\F64~\F64] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F64.\LT` :math:`\hex{63}` :math:`[\F64~\F64] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F64.\GT` :math:`\hex{64}` :math:`[\F64~\F64] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F64.\LE` :math:`\hex{65}` :math:`[\F64~\F64] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F64.\GE` :math:`\hex{66}` :math:`[\F64~\F64] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I32.\CLZ` :math:`\hex{67}` :math:`[\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I32.\CTZ` :math:`\hex{68}` :math:`[\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I32.\POPCNT` :math:`\hex{69}` :math:`[\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I32.\ADD` :math:`\hex{6A}` :math:`[\I32~\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I32.\SUB` :math:`\hex{6B}` :math:`[\I32~\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I32.\MUL` :math:`\hex{6C}` :math:`[\I32~\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I32.\DIV\K{\_s}` :math:`\hex{6D}` :math:`[\I32~\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I32.\DIV\K{\_u}` :math:`\hex{6E}` :math:`[\I32~\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I32.\REM\K{\_s}` :math:`\hex{6F}` :math:`[\I32~\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I32.\REM\K{\_u}` :math:`\hex{70}` :math:`[\I32~\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I32.\AND` :math:`\hex{71}` :math:`[\I32~\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I32.\OR` :math:`\hex{72}` :math:`[\I32~\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I32.\XOR` :math:`\hex{73}` :math:`[\I32~\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I32.\SHL` :math:`\hex{74}` :math:`[\I32~\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I32.\SHR\K{\_s}` :math:`\hex{75}` :math:`[\I32~\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I32.\SHR\K{\_u}` :math:`\hex{76}` :math:`[\I32~\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I32.\ROTL` :math:`\hex{77}` :math:`[\I32~\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I32.\ROTR` :math:`\hex{78}` :math:`[\I32~\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I64.\CLZ` :math:`\hex{79}` :math:`[\I64] \to [\I64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I64.\CTZ` :math:`\hex{7A}` :math:`[\I64] \to [\I64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I64.\POPCNT` :math:`\hex{7B}` :math:`[\I64] \to [\I64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I64.\ADD` :math:`\hex{7C}` :math:`[\I64~\I64] \to [\I64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I64.\SUB` :math:`\hex{7D}` :math:`[\I64~\I64] \to [\I64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I64.\MUL` :math:`\hex{7E}` :math:`[\I64~\I64] \to [\I64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I64.\DIV\K{\_s}` :math:`\hex{7F}` :math:`[\I64~\I64] \to [\I64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I64.\DIV\K{\_u}` :math:`\hex{80}` :math:`[\I64~\I64] \to [\I64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I64.\REM\K{\_s}` :math:`\hex{81}` :math:`[\I64~\I64] \to [\I64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I64.\REM\K{\_u}` :math:`\hex{82}` :math:`[\I64~\I64] \to [\I64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I64.\AND` :math:`\hex{83}` :math:`[\I64~\I64] \to [\I64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I64.\OR` :math:`\hex{84}` :math:`[\I64~\I64] \to [\I64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I64.\XOR` :math:`\hex{85}` :math:`[\I64~\I64] \to [\I64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I64.\SHL` :math:`\hex{86}` :math:`[\I64~\I64] \to [\I64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I64.\SHR\K{\_s}` :math:`\hex{87}` :math:`[\I64~\I64] \to [\I64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I64.\SHR\K{\_u}` :math:`\hex{88}` :math:`[\I64~\I64] \to [\I64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I64.\ROTL` :math:`\hex{89}` :math:`[\I64~\I64] \to [\I64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I64.\ROTR` :math:`\hex{8A}` :math:`[\I64~\I64] \to [\I64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F32.\ABS` :math:`\hex{8B}` :math:`[\F32] \to [\F32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F32.\NEG` :math:`\hex{8C}` :math:`[\F32] \to [\F32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F32.\CEIL` :math:`\hex{8D}` :math:`[\F32] \to [\F32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F32.\FLOOR` :math:`\hex{8E}` :math:`[\F32] \to [\F32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F32.\TRUNC` :math:`\hex{8F}` :math:`[\F32] \to [\F32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F32.\NEAREST` :math:`\hex{90}` :math:`[\F32] \to [\F32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F32.\SQRT` :math:`\hex{91}` :math:`[\F32] \to [\F32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F32.\ADD` :math:`\hex{92}` :math:`[\F32~\F32] \to [\F32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F32.\SUB` :math:`\hex{93}` :math:`[\F32~\F32] \to [\F32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F32.\MUL` :math:`\hex{94}` :math:`[\F32~\F32] \to [\F32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F32.\DIV` :math:`\hex{95}` :math:`[\F32~\F32] \to [\F32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F32.\FMIN` :math:`\hex{96}` :math:`[\F32~\F32] \to [\F32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F32.\FMAX` :math:`\hex{97}` :math:`[\F32~\F32] \to [\F32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F32.\COPYSIGN` :math:`\hex{98}` :math:`[\F32~\F32] \to [\F32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F64.\ABS` :math:`\hex{99}` :math:`[\F64] \to [\F64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F64.\NEG` :math:`\hex{9A}` :math:`[\F64] \to [\F64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F64.\CEIL` :math:`\hex{9B}` :math:`[\F64] \to [\F64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F64.\FLOOR` :math:`\hex{9C}` :math:`[\F64] \to [\F64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F64.\TRUNC` :math:`\hex{9D}` :math:`[\F64] \to [\F64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F64.\NEAREST` :math:`\hex{9E}` :math:`[\F64] \to [\F64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F64.\SQRT` :math:`\hex{9F}` :math:`[\F64] \to [\F64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F64.\ADD` :math:`\hex{A0}` :math:`[\F64~\F64] \to [\F64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F64.\SUB` :math:`\hex{A1}` :math:`[\F64~\F64] \to [\F64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F64.\MUL` :math:`\hex{A2}` :math:`[\F64~\F64] \to [\F64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F64.\DIV` :math:`\hex{A3}` :math:`[\F64~\F64] \to [\F64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F64.\FMIN` :math:`\hex{A4}` :math:`[\F64~\F64] \to [\F64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F64.\FMAX` :math:`\hex{A5}` :math:`[\F64~\F64] \to [\F64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F64.\COPYSIGN` :math:`\hex{A6}` :math:`[\F64~\F64] \to [\F64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I32.\WRAP\K{\_}\I64` :math:`\hex{A7}` :math:`[\I64] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I32.\TRUNC\K{\_}\F32\K{\_s}` :math:`\hex{A8}` :math:`[\F32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I32.\TRUNC\K{\_}\F32\K{\_u}` :math:`\hex{A9}` :math:`[\F32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I32.\TRUNC\K{\_}\F64\K{\_s}` :math:`\hex{AA}` :math:`[\F64] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I32.\TRUNC\K{\_}\F64\K{\_u}` :math:`\hex{AB}` :math:`[\F64] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I64.\EXTEND\K{\_}\I32\K{\_s}` :math:`\hex{AC}` :math:`[\I32] \to [\I64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I64.\EXTEND\K{\_}\I32\K{\_u}` :math:`\hex{AD}` :math:`[\I32] \to [\I64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I64.\TRUNC\K{\_}\F32\K{\_s}` :math:`\hex{AE}` :math:`[\F32] \to [\I64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I64.\TRUNC\K{\_}\F32\K{\_u}` :math:`\hex{AF}` :math:`[\F32] \to [\I64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I64.\TRUNC\K{\_}\F64\K{\_s}` :math:`\hex{B0}` :math:`[\F64] \to [\I64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I64.\TRUNC\K{\_}\F64\K{\_u}` :math:`\hex{B1}` :math:`[\F64] \to [\I64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F32.\CONVERT\K{\_}\I32\K{\_s}` :math:`\hex{B2}` :math:`[\I32] \to [\F32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F32.\CONVERT\K{\_}\I32\K{\_u}` :math:`\hex{B3}` :math:`[\I32] \to [\F32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F32.\CONVERT\K{\_}\I64\K{\_s}` :math:`\hex{B4}` :math:`[\I64] \to [\F32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F32.\CONVERT\K{\_}\I64\K{\_u}` :math:`\hex{B5}` :math:`[\I64] \to [\F32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F32.\DEMOTE\K{\_}\F64` :math:`\hex{B6}` :math:`[\F64] \to [\F32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F64.\CONVERT\K{\_}\I32\K{\_s}` :math:`\hex{B7}` :math:`[\I32] \to [\F64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F64.\CONVERT\K{\_}\I32\K{\_u}` :math:`\hex{B8}` :math:`[\I32] \to [\F64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F64.\CONVERT\K{\_}\I64\K{\_s}` :math:`\hex{B9}` :math:`[\I64] \to [\F64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F64.\CONVERT\K{\_}\I64\K{\_u}` :math:`\hex{BA}` :math:`[\I64] \to [\F64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F64.\PROMOTE\K{\_}\F32` :math:`\hex{BB}` :math:`[\F32] \to [\F64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I32.\REINTERPRET\K{\_}\F32` :math:`\hex{BC}` :math:`[\F32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I64.\REINTERPRET\K{\_}\F64` :math:`\hex{BD}` :math:`[\F64] \to [\I64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F32.\REINTERPRET\K{\_}\I32` :math:`\hex{BE}` :math:`[\I32] \to [\F32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F64.\REINTERPRET\K{\_}\I64` :math:`\hex{BF}` :math:`[\I64] \to [\F64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -====================================== ================ ========================================== ======================================== =============================================================== +====================================== ================== ========================================== ======================================== =============================================================== +Instruction Binary Opcode Type Validation Execution +====================================== ================== ========================================== ======================================== =============================================================== +:math:`\UNREACHABLE` :math:`\hex{00}` :math:`[t_1^\ast] \to [t_2^\ast]` :ref:`validation ` :ref:`execution ` +:math:`\NOP` :math:`\hex{01}` :math:`[] \to []` :ref:`validation ` :ref:`execution ` +:math:`\BLOCK~[t^?]` :math:`\hex{02}` :math:`[] \to [t^\ast]` :ref:`validation ` :ref:`execution ` +:math:`\LOOP~[t^?]` :math:`\hex{03}` :math:`[] \to [t^\ast]` :ref:`validation ` :ref:`execution ` +:math:`\IF~[t^?]` :math:`\hex{04}` :math:`[] \to [t^\ast]` :ref:`validation ` :ref:`execution ` +:math:`\ELSE` :math:`\hex{05}` +(reserved) :math:`\hex{06}` +(reserved) :math:`\hex{07}` +(reserved) :math:`\hex{08}` +(reserved) :math:`\hex{09}` +(reserved) :math:`\hex{0A}` +:math:`\END` :math:`\hex{0B}` +:math:`\BR~l` :math:`\hex{0C}` :math:`[t_1^\ast~t^?] \to [t_2^\ast]` :ref:`validation ` :ref:`execution ` +:math:`\BRIF~l` :math:`\hex{0D}` :math:`[t^?~\I32] \to [t^?]` :ref:`validation ` :ref:`execution ` +:math:`\BRTABLE~l^\ast~l` :math:`\hex{0E}` :math:`[t_1^\ast~t^?~\I32] \to [t_2^\ast]` :ref:`validation ` :ref:`execution ` +:math:`\RETURN` :math:`\hex{0F}` :math:`[t_1^\ast~t^?] \to [t_2^\ast]` :ref:`validation ` :ref:`execution ` +:math:`\CALL~x` :math:`\hex{10}` :math:`[t_1^\ast] \to [t_2^\ast]` :ref:`validation ` :ref:`execution ` +:math:`\CALLINDIRECT~x` :math:`\hex{11}` :math:`[t_1^\ast~\I32] \to [t_2^\ast]` :ref:`validation ` :ref:`execution ` +(reserved) :math:`\hex{12}` +(reserved) :math:`\hex{13}` +(reserved) :math:`\hex{14}` +(reserved) :math:`\hex{15}` +(reserved) :math:`\hex{16}` +(reserved) :math:`\hex{17}` +(reserved) :math:`\hex{18}` +(reserved) :math:`\hex{19}` +:math:`\DROP` :math:`\hex{1A}` :math:`[t] \to []` :ref:`validation ` :ref:`execution ` +:math:`\SELECT` :math:`\hex{1B}` :math:`[t~t~\I32] \to [t]` :ref:`validation ` :ref:`execution ` +(reserved) :math:`\hex{1C}` +(reserved) :math:`\hex{1D}` +(reserved) :math:`\hex{1E}` +(reserved) :math:`\hex{1F}` +:math:`\LOCALGET~x` :math:`\hex{20}` :math:`[] \to [t]` :ref:`validation ` :ref:`execution ` +:math:`\LOCALSET~x` :math:`\hex{21}` :math:`[t] \to []` :ref:`validation ` :ref:`execution ` +:math:`\LOCALTEE~x` :math:`\hex{22}` :math:`[t] \to [t]` :ref:`validation ` :ref:`execution ` +:math:`\GLOBALGET~x` :math:`\hex{23}` :math:`[] \to [t]` :ref:`validation ` :ref:`execution ` +:math:`\GLOBALSET~x` :math:`\hex{24}` :math:`[t] \to []` :ref:`validation ` :ref:`execution ` +(reserved) :math:`\hex{25}` +(reserved) :math:`\hex{26}` +(reserved) :math:`\hex{27}` +:math:`\I32.\LOAD~\memarg` :math:`\hex{28}` :math:`[\I32] \to [\I32]` :ref:`validation ` :ref:`execution ` +:math:`\I64.\LOAD~\memarg` :math:`\hex{29}` :math:`[\I32] \to [\I64]` :ref:`validation ` :ref:`execution ` +:math:`\F32.\LOAD~\memarg` :math:`\hex{2A}` :math:`[\I32] \to [\F32]` :ref:`validation ` :ref:`execution ` +:math:`\F64.\LOAD~\memarg` :math:`\hex{2B}` :math:`[\I32] \to [\F64]` :ref:`validation ` :ref:`execution ` +:math:`\I32.\LOAD\K{8\_s}~\memarg` :math:`\hex{2C}` :math:`[\I32] \to [\I32]` :ref:`validation ` :ref:`execution ` +:math:`\I32.\LOAD\K{8\_u}~\memarg` :math:`\hex{2D}` :math:`[\I32] \to [\I32]` :ref:`validation ` :ref:`execution ` +:math:`\I32.\LOAD\K{16\_s}~\memarg` :math:`\hex{2E}` :math:`[\I32] \to [\I32]` :ref:`validation ` :ref:`execution ` +:math:`\I32.\LOAD\K{16\_u}~\memarg` :math:`\hex{2F}` :math:`[\I32] \to [\I32]` :ref:`validation ` :ref:`execution ` +:math:`\I64.\LOAD\K{8\_s}~\memarg` :math:`\hex{30}` :math:`[\I32] \to [\I64]` :ref:`validation ` :ref:`execution ` +:math:`\I64.\LOAD\K{8\_u}~\memarg` :math:`\hex{31}` :math:`[\I32] \to [\I64]` :ref:`validation ` :ref:`execution ` +:math:`\I64.\LOAD\K{16\_s}~\memarg` :math:`\hex{32}` :math:`[\I32] \to [\I64]` :ref:`validation ` :ref:`execution ` +:math:`\I64.\LOAD\K{16\_u}~\memarg` :math:`\hex{33}` :math:`[\I32] \to [\I64]` :ref:`validation ` :ref:`execution ` +:math:`\I64.\LOAD\K{32\_s}~\memarg` :math:`\hex{34}` :math:`[\I32] \to [\I64]` :ref:`validation ` :ref:`execution ` +:math:`\I64.\LOAD\K{32\_u}~\memarg` :math:`\hex{35}` :math:`[\I32] \to [\I64]` :ref:`validation ` :ref:`execution ` +:math:`\I32.\STORE~\memarg` :math:`\hex{36}` :math:`[\I32~\I32] \to []` :ref:`validation ` :ref:`execution ` +:math:`\I64.\STORE~\memarg` :math:`\hex{37}` :math:`[\I32~\I64] \to []` :ref:`validation ` :ref:`execution ` +:math:`\F32.\STORE~\memarg` :math:`\hex{38}` :math:`[\I32~\F32] \to []` :ref:`validation ` :ref:`execution ` +:math:`\F64.\STORE~\memarg` :math:`\hex{39}` :math:`[\I32~\F64] \to []` :ref:`validation ` :ref:`execution ` +:math:`\I32.\STORE\K{8}~\memarg` :math:`\hex{3A}` :math:`[\I32~\I32] \to []` :ref:`validation ` :ref:`execution ` +:math:`\I32.\STORE\K{16}~\memarg` :math:`\hex{3B}` :math:`[\I32~\I32] \to []` :ref:`validation ` :ref:`execution ` +:math:`\I64.\STORE\K{8}~\memarg` :math:`\hex{3C}` :math:`[\I32~\I64] \to []` :ref:`validation ` :ref:`execution ` +:math:`\I64.\STORE\K{16}~\memarg` :math:`\hex{3D}` :math:`[\I32~\I64] \to []` :ref:`validation ` :ref:`execution ` +:math:`\I64.\STORE\K{32}~\memarg` :math:`\hex{3E}` :math:`[\I32~\I64] \to []` :ref:`validation ` :ref:`execution ` +:math:`\MEMORYSIZE` :math:`\hex{3F}` :math:`[] \to [\I32]` :ref:`validation ` :ref:`execution ` +:math:`\MEMORYGROW` :math:`\hex{40}` :math:`[\I32] \to [\I32]` :ref:`validation ` :ref:`execution ` +:math:`\I32.\CONST~\i32` :math:`\hex{41}` :math:`[] \to [\I32]` :ref:`validation ` :ref:`execution ` +:math:`\I64.\CONST~\i64` :math:`\hex{42}` :math:`[] \to [\I64]` :ref:`validation ` :ref:`execution ` +:math:`\F32.\CONST~\f32` :math:`\hex{43}` :math:`[] \to [\F32]` :ref:`validation ` :ref:`execution ` +:math:`\F64.\CONST~\f64` :math:`\hex{44}` :math:`[] \to [\F64]` :ref:`validation ` :ref:`execution ` +:math:`\I32.\EQZ` :math:`\hex{45}` :math:`[\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I32.\EQ` :math:`\hex{46}` :math:`[\I32~\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I32.\NE` :math:`\hex{47}` :math:`[\I32~\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I32.\LT\K{\_s}` :math:`\hex{48}` :math:`[\I32~\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I32.\LT\K{\_u}` :math:`\hex{49}` :math:`[\I32~\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I32.\GT\K{\_s}` :math:`\hex{4A}` :math:`[\I32~\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I32.\GT\K{\_u}` :math:`\hex{4B}` :math:`[\I32~\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I32.\LE\K{\_s}` :math:`\hex{4C}` :math:`[\I32~\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I32.\LE\K{\_u}` :math:`\hex{4D}` :math:`[\I32~\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I32.\GE\K{\_s}` :math:`\hex{4E}` :math:`[\I32~\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I32.\GE\K{\_u}` :math:`\hex{4F}` :math:`[\I32~\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I64.\EQZ` :math:`\hex{50}` :math:`[\I64] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I64.\EQ` :math:`\hex{51}` :math:`[\I64~\I64] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I64.\NE` :math:`\hex{52}` :math:`[\I64~\I64] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I64.\LT\K{\_s}` :math:`\hex{53}` :math:`[\I64~\I64] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I64.\LT\K{\_u}` :math:`\hex{54}` :math:`[\I64~\I64] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I64.\GT\K{\_s}` :math:`\hex{55}` :math:`[\I64~\I64] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I64.\GT\K{\_u}` :math:`\hex{56}` :math:`[\I64~\I64] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I64.\LE\K{\_s}` :math:`\hex{57}` :math:`[\I64~\I64] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I64.\LE\K{\_u}` :math:`\hex{58}` :math:`[\I64~\I64] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I64.\GE\K{\_s}` :math:`\hex{59}` :math:`[\I64~\I64] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I64.\GE\K{\_u}` :math:`\hex{5A}` :math:`[\I64~\I64] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\F32.\EQ` :math:`\hex{5B}` :math:`[\F32~\F32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\F32.\NE` :math:`\hex{5C}` :math:`[\F32~\F32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\F32.\LT` :math:`\hex{5D}` :math:`[\F32~\F32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\F32.\GT` :math:`\hex{5E}` :math:`[\F32~\F32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\F32.\LE` :math:`\hex{5F}` :math:`[\F32~\F32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\F32.\GE` :math:`\hex{60}` :math:`[\F32~\F32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\F64.\EQ` :math:`\hex{61}` :math:`[\F64~\F64] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\F64.\NE` :math:`\hex{62}` :math:`[\F64~\F64] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\F64.\LT` :math:`\hex{63}` :math:`[\F64~\F64] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\F64.\GT` :math:`\hex{64}` :math:`[\F64~\F64] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\F64.\LE` :math:`\hex{65}` :math:`[\F64~\F64] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\F64.\GE` :math:`\hex{66}` :math:`[\F64~\F64] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I32.\CLZ` :math:`\hex{67}` :math:`[\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I32.\CTZ` :math:`\hex{68}` :math:`[\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I32.\POPCNT` :math:`\hex{69}` :math:`[\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I32.\ADD` :math:`\hex{6A}` :math:`[\I32~\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I32.\SUB` :math:`\hex{6B}` :math:`[\I32~\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I32.\MUL` :math:`\hex{6C}` :math:`[\I32~\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I32.\DIV\K{\_s}` :math:`\hex{6D}` :math:`[\I32~\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I32.\DIV\K{\_u}` :math:`\hex{6E}` :math:`[\I32~\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I32.\REM\K{\_s}` :math:`\hex{6F}` :math:`[\I32~\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I32.\REM\K{\_u}` :math:`\hex{70}` :math:`[\I32~\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I32.\AND` :math:`\hex{71}` :math:`[\I32~\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I32.\OR` :math:`\hex{72}` :math:`[\I32~\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I32.\XOR` :math:`\hex{73}` :math:`[\I32~\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I32.\SHL` :math:`\hex{74}` :math:`[\I32~\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I32.\SHR\K{\_s}` :math:`\hex{75}` :math:`[\I32~\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I32.\SHR\K{\_u}` :math:`\hex{76}` :math:`[\I32~\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I32.\ROTL` :math:`\hex{77}` :math:`[\I32~\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I32.\ROTR` :math:`\hex{78}` :math:`[\I32~\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I64.\CLZ` :math:`\hex{79}` :math:`[\I64] \to [\I64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I64.\CTZ` :math:`\hex{7A}` :math:`[\I64] \to [\I64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I64.\POPCNT` :math:`\hex{7B}` :math:`[\I64] \to [\I64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I64.\ADD` :math:`\hex{7C}` :math:`[\I64~\I64] \to [\I64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I64.\SUB` :math:`\hex{7D}` :math:`[\I64~\I64] \to [\I64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I64.\MUL` :math:`\hex{7E}` :math:`[\I64~\I64] \to [\I64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I64.\DIV\K{\_s}` :math:`\hex{7F}` :math:`[\I64~\I64] \to [\I64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I64.\DIV\K{\_u}` :math:`\hex{80}` :math:`[\I64~\I64] \to [\I64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I64.\REM\K{\_s}` :math:`\hex{81}` :math:`[\I64~\I64] \to [\I64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I64.\REM\K{\_u}` :math:`\hex{82}` :math:`[\I64~\I64] \to [\I64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I64.\AND` :math:`\hex{83}` :math:`[\I64~\I64] \to [\I64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I64.\OR` :math:`\hex{84}` :math:`[\I64~\I64] \to [\I64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I64.\XOR` :math:`\hex{85}` :math:`[\I64~\I64] \to [\I64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I64.\SHL` :math:`\hex{86}` :math:`[\I64~\I64] \to [\I64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I64.\SHR\K{\_s}` :math:`\hex{87}` :math:`[\I64~\I64] \to [\I64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I64.\SHR\K{\_u}` :math:`\hex{88}` :math:`[\I64~\I64] \to [\I64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I64.\ROTL` :math:`\hex{89}` :math:`[\I64~\I64] \to [\I64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I64.\ROTR` :math:`\hex{8A}` :math:`[\I64~\I64] \to [\I64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\F32.\ABS` :math:`\hex{8B}` :math:`[\F32] \to [\F32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\F32.\NEG` :math:`\hex{8C}` :math:`[\F32] \to [\F32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\F32.\CEIL` :math:`\hex{8D}` :math:`[\F32] \to [\F32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\F32.\FLOOR` :math:`\hex{8E}` :math:`[\F32] \to [\F32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\F32.\TRUNC` :math:`\hex{8F}` :math:`[\F32] \to [\F32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\F32.\NEAREST` :math:`\hex{90}` :math:`[\F32] \to [\F32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\F32.\SQRT` :math:`\hex{91}` :math:`[\F32] \to [\F32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\F32.\ADD` :math:`\hex{92}` :math:`[\F32~\F32] \to [\F32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\F32.\SUB` :math:`\hex{93}` :math:`[\F32~\F32] \to [\F32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\F32.\MUL` :math:`\hex{94}` :math:`[\F32~\F32] \to [\F32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\F32.\DIV` :math:`\hex{95}` :math:`[\F32~\F32] \to [\F32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\F32.\FMIN` :math:`\hex{96}` :math:`[\F32~\F32] \to [\F32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\F32.\FMAX` :math:`\hex{97}` :math:`[\F32~\F32] \to [\F32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\F32.\COPYSIGN` :math:`\hex{98}` :math:`[\F32~\F32] \to [\F32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\F64.\ABS` :math:`\hex{99}` :math:`[\F64] \to [\F64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\F64.\NEG` :math:`\hex{9A}` :math:`[\F64] \to [\F64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\F64.\CEIL` :math:`\hex{9B}` :math:`[\F64] \to [\F64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\F64.\FLOOR` :math:`\hex{9C}` :math:`[\F64] \to [\F64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\F64.\TRUNC` :math:`\hex{9D}` :math:`[\F64] \to [\F64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\F64.\NEAREST` :math:`\hex{9E}` :math:`[\F64] \to [\F64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\F64.\SQRT` :math:`\hex{9F}` :math:`[\F64] \to [\F64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\F64.\ADD` :math:`\hex{A0}` :math:`[\F64~\F64] \to [\F64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\F64.\SUB` :math:`\hex{A1}` :math:`[\F64~\F64] \to [\F64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\F64.\MUL` :math:`\hex{A2}` :math:`[\F64~\F64] \to [\F64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\F64.\DIV` :math:`\hex{A3}` :math:`[\F64~\F64] \to [\F64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\F64.\FMIN` :math:`\hex{A4}` :math:`[\F64~\F64] \to [\F64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\F64.\FMAX` :math:`\hex{A5}` :math:`[\F64~\F64] \to [\F64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\F64.\COPYSIGN` :math:`\hex{A6}` :math:`[\F64~\F64] \to [\F64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I32.\WRAP\K{\_}\I64` :math:`\hex{A7}` :math:`[\I64] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I32.\TRUNC\K{\_}\F32\K{\_s}` :math:`\hex{A8}` :math:`[\F32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I32.\TRUNC\K{\_}\F32\K{\_u}` :math:`\hex{A9}` :math:`[\F32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I32.\TRUNC\K{\_}\F64\K{\_s}` :math:`\hex{AA}` :math:`[\F64] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I32.\TRUNC\K{\_}\F64\K{\_u}` :math:`\hex{AB}` :math:`[\F64] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I64.\EXTEND\K{\_}\I32\K{\_s}` :math:`\hex{AC}` :math:`[\I32] \to [\I64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I64.\EXTEND\K{\_}\I32\K{\_u}` :math:`\hex{AD}` :math:`[\I32] \to [\I64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I64.\TRUNC\K{\_}\F32\K{\_s}` :math:`\hex{AE}` :math:`[\F32] \to [\I64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I64.\TRUNC\K{\_}\F32\K{\_u}` :math:`\hex{AF}` :math:`[\F32] \to [\I64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I64.\TRUNC\K{\_}\F64\K{\_s}` :math:`\hex{B0}` :math:`[\F64] \to [\I64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I64.\TRUNC\K{\_}\F64\K{\_u}` :math:`\hex{B1}` :math:`[\F64] \to [\I64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\F32.\CONVERT\K{\_}\I32\K{\_s}` :math:`\hex{B2}` :math:`[\I32] \to [\F32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\F32.\CONVERT\K{\_}\I32\K{\_u}` :math:`\hex{B3}` :math:`[\I32] \to [\F32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\F32.\CONVERT\K{\_}\I64\K{\_s}` :math:`\hex{B4}` :math:`[\I64] \to [\F32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\F32.\CONVERT\K{\_}\I64\K{\_u}` :math:`\hex{B5}` :math:`[\I64] \to [\F32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\F32.\DEMOTE\K{\_}\F64` :math:`\hex{B6}` :math:`[\F64] \to [\F32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\F64.\CONVERT\K{\_}\I32\K{\_s}` :math:`\hex{B7}` :math:`[\I32] \to [\F64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\F64.\CONVERT\K{\_}\I32\K{\_u}` :math:`\hex{B8}` :math:`[\I32] \to [\F64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\F64.\CONVERT\K{\_}\I64\K{\_s}` :math:`\hex{B9}` :math:`[\I64] \to [\F64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\F64.\CONVERT\K{\_}\I64\K{\_u}` :math:`\hex{BA}` :math:`[\I64] \to [\F64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\F64.\PROMOTE\K{\_}\F32` :math:`\hex{BB}` :math:`[\F32] \to [\F64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I32.\REINTERPRET\K{\_}\F32` :math:`\hex{BC}` :math:`[\F32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I64.\REINTERPRET\K{\_}\F64` :math:`\hex{BD}` :math:`[\F64] \to [\I64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\F32.\REINTERPRET\K{\_}\I32` :math:`\hex{BE}` :math:`[\I32] \to [\F32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\F64.\REINTERPRET\K{\_}\I64` :math:`\hex{BF}` :math:`[\I64] \to [\F64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\MEMORYINIT` :math:`\hex{FC08}` :math:`[\I32~\I32~\I32] \to []` :ref:`validation ` :ref:`execution ` +:math:`\DATADROP` :math:`\hex{FC09}` :math:`[] \to []` :ref:`validation ` :ref:`execution ` +:math:`\MEMORYCOPY` :math:`\hex{FC0A}` :math:`[\I32~\I32~\I32] \to []` :ref:`validation ` :ref:`execution ` +:math:`\MEMORYFILL` :math:`\hex{FC0B}` :math:`[\I32~\I32~\I32] \to []` :ref:`validation ` :ref:`execution ` +:math:`\TABLEINIT` :math:`\hex{FC0C}` :math:`[\I32~\I32~\I32] \to []` :ref:`validation ` :ref:`execution ` +:math:`\ELEMDROP` :math:`\hex{FC0D}` :math:`[] \to []` :ref:`validation ` :ref:`execution ` +:math:`\TABLECOPY` :math:`\hex{FC0E}` :math:`[\I32~\I32~\I32] \to []` :ref:`validation ` :ref:`execution ` +====================================== ================== ========================================== ======================================== =============================================================== From e27b4eadf3c78447ae1241f1aa6d3f3e77584870 Mon Sep 17 00:00:00 2001 From: Ben Smith Date: Fri, 5 Apr 2019 16:01:58 -0700 Subject: [PATCH 078/199] [spec] DataCount section, syntax, and validation (#80) The data count section has a count that must match the number of data segments. If the data count section isn't present, then `memory.init` and `data.drop` cannot be used. Fixes issue #73. --- document/core/binary/modules.rst | 79 +++++++++++++++++++++------- document/core/util/macros.def | 1 + document/core/valid/instructions.rst | 4 +- 3 files changed, 63 insertions(+), 21 deletions(-) diff --git a/document/core/binary/modules.rst b/document/core/binary/modules.rst index d0309d6bd8..afdd7ef558 100644 --- a/document/core/binary/modules.rst +++ b/document/core/binary/modules.rst @@ -84,22 +84,23 @@ In these cases, the empty result :math:`\epsilon` is interpreted as the empty ve The following section ids are used: -== ======================================== -Id Section -== ======================================== - 0 :ref:`custom section ` - 1 :ref:`type section ` - 2 :ref:`import section ` - 3 :ref:`function section ` - 4 :ref:`table section ` - 5 :ref:`memory section ` - 6 :ref:`global section ` - 7 :ref:`export section ` - 8 :ref:`start section ` - 9 :ref:`element section ` -10 :ref:`code section ` -11 :ref:`data section ` -== ======================================== +== =============================================== +Id Section +== =============================================== + 0 :ref:`custom section ` + 1 :ref:`type section ` + 2 :ref:`import section ` + 3 :ref:`function section ` + 4 :ref:`table section ` + 5 :ref:`memory section ` + 6 :ref:`global section ` + 7 :ref:`export section ` + 8 :ref:`start section ` + 9 :ref:`element section ` +10 :ref:`code section ` +11 :ref:`data section ` +12 :ref:`data count section ` +== =============================================== .. index:: ! custom section @@ -433,6 +434,32 @@ It decodes into a vector of :ref:`data segments ` that represent th segments have a |DMEM| value of :math:`0`. +.. index:: ! data count section, data count, data segment + pair: binary format; data count + pair: section; data count +.. _binary-datacountsec: + +Data Count Section +~~~~~~~~~~~~~~~~~~ + +The *data count section* has the id 12. +It decodes into an optional :ref:`u32 ` that represents the number of :ref:`data segments ` in the :ref:`data section `. If this count does not match the length of the data segment vector, the module is malformed. + +.. math:: + \begin{array}{llclll} + \production{data count section} & \Bdatacountsec &::=& + \X{n}^?{:}\Bsection_{12}(\Bu32) &\Rightarrow& \X{n}^? \\ + \end{array} + +.. note:: + The data count section is used to simplify single-pass validation. Since the + data section occurs after the code section, the :math:`\MEMORYINIT` and + :math:`\DATADROP` instructions would not be able to check whether the data + segment index is valid until the data section is read. The data count section + occurs before the code section, so a single-pass validator can use this count + instead of deferring validation. + + .. index:: module, section, type definition, function type, function, table, memory, global, element, data, start function, import, export, context, version pair: binary format; module .. _binary-magic: @@ -450,6 +477,8 @@ The preamble is followed by a sequence of :ref:`sections `. while other sections must occur at most once and in the prescribed order. All sections can be empty. The lengths of vectors produced by the (possibly empty) :ref:`function ` and :ref:`code ` section must match up. +Similarly, the data count must match the length of the :ref:`data segment ` vector. +The :math:`\MEMORYINIT` and :math:`\DATADROP` instructions can only be used if the data count section is present. .. math:: \begin{array}{llcllll} @@ -479,9 +508,11 @@ The lengths of vectors produced by the (possibly empty) :ref:`function ` :math:`C.\CDATA[x]` must be |SPASSIVE|. - * Then the instruction is valid with type :math:`[] \to []`. .. math:: From 864f382f26e94a4b8cff4a4ceb366df3c0f31d51 Mon Sep 17 00:00:00 2001 From: Andreas Rossberg Date: Tue, 16 Apr 2019 10:53:38 +0200 Subject: [PATCH 079/199] [spec] Simplify datacount side condition (#83) * Add definition of free index sets * Simplify datacount side condition * Explain convention about multiple occurrences of meta variables --- document/core/binary/conventions.rst | 3 +++ document/core/binary/modules.rst | 25 ++++++++----------------- document/core/syntax/conventions.rst | 4 ++++ document/core/syntax/modules.rst | 20 +++++++++++++++++--- document/core/text/conventions.rst | 2 ++ document/core/util/macros.def | 13 +++++++++++++ 6 files changed, 47 insertions(+), 20 deletions(-) diff --git a/document/core/binary/conventions.rst b/document/core/binary/conventions.rst index 8d38399773..cacd25134b 100644 --- a/document/core/binary/conventions.rst +++ b/document/core/binary/conventions.rst @@ -59,6 +59,9 @@ In order to distinguish symbols of the binary syntax from symbols of the abstrac * Some productions are augmented by side conditions in parentheses, which restrict the applicability of the production. They provide a shorthand for a combinatorial expansion of the production into many separate cases. +* If the same meta variable or non-terminal symbol appears multiple times in a production (in the syntax or in an attribute), then all those occurrences must have the same instantiation. + (This is a shorthand for a side condition requiring multiple different variables to be equal.) + .. note:: For example, the :ref:`binary grammar ` for :ref:`value types ` is given as follows: diff --git a/document/core/binary/modules.rst b/document/core/binary/modules.rst index afdd7ef558..7c5cdc745a 100644 --- a/document/core/binary/modules.rst +++ b/document/core/binary/modules.rst @@ -476,9 +476,11 @@ The preamble is followed by a sequence of :ref:`sections `. :ref:`Custom sections ` may be inserted at any place in this sequence, while other sections must occur at most once and in the prescribed order. All sections can be empty. + The lengths of vectors produced by the (possibly empty) :ref:`function ` and :ref:`code ` section must match up. -Similarly, the data count must match the length of the :ref:`data segment ` vector. -The :math:`\MEMORYINIT` and :math:`\DATADROP` instructions can only be used if the data count section is present. + +Similarly, the optional data count must match the length of the :ref:`data segment ` vector. +Furthermore, it must be present if any :math:`data index ` occurs in the code section. .. math:: \begin{array}{llcllll} @@ -512,7 +514,7 @@ The :math:`\MEMORYINIT` and :math:`\DATADROP` instructions can only be used if t \Bcustomsec^\ast \\ &&& \X{code}^n{:\,}\Bcodesec \\ &&& \Bcustomsec^\ast \\ &&& - \data^{\X{m'}}{:\,}\Bdatasec \\ &&& + \data^m{:\,}\Bdatasec \\ &&& \Bcustomsec^\ast \quad\Rightarrow\quad \{~ \begin{array}[t]{@{}l@{}} @@ -522,15 +524,12 @@ The :math:`\MEMORYINIT` and :math:`\DATADROP` instructions can only be used if t \MMEMS~\mem^\ast, \\ \MGLOBALS~\global^\ast, \\ \MELEM~\elem^\ast, \\ - \MDATA~\data^{\X{m'}}, \\ + \MDATA~\data^m, \\ \MSTART~\start^?, \\ \MIMPORTS~\import^\ast, \\ \MEXPORTS~\export^\ast ~\} \\ - \end{array} \\ &&& - (\begin{array}[t]{@{}c@{~}l@{}} - \iff & m^? \neq \epsilon \\ - \vee & \forall (t^\ast, e) \in \X{code}^n, \MEMORYINIT \notin e \wedge \DATADROP \notin e) \\ - \end{array} \\ + \end{array} \\ &&& + (\iff m^? \neq \epsilon \vee \freedataidx(\X{code}^n) = \emptyset) \\ \end{array} where for each :math:`t_i^\ast, e_i` in :math:`\X{code}^n`, @@ -538,14 +537,6 @@ where for each :math:`t_i^\ast, e_i` in :math:`\X{code}^n`, .. math:: \func^n[i] = \{ \FTYPE~\typeidx^n[i], \FLOCALS~t_i^\ast, \FBODY~e_i \} ) \\ -and where, - -.. math:: - \begin{array}{lcl@{\qquad}l} - \X{m'} &=& m & (\iff m^? \neq \epsilon) \\ - \X{m'} &=& 0 & (\otherwise) - \end{array} - .. note:: The version of the WebAssembly binary format may increase in the future if backward-incompatible changes have to be made to the format. diff --git a/document/core/syntax/conventions.rst b/document/core/syntax/conventions.rst index c0890ba98f..979d6bc4e3 100644 --- a/document/core/syntax/conventions.rst +++ b/document/core/syntax/conventions.rst @@ -41,6 +41,9 @@ The following conventions are adopted in defining grammar rules for abstract syn * Some productions are augmented with side conditions in parentheses, ":math:`(\iff \X{condition})`", that provide a shorthand for a combinatorial expansion of the production into many separate cases. +* If the same meta variable or non-terminal symbol appears multiple times in a production, then all those occurrences must have the same instantiation. + (This is a shorthand for a side condition requiring multiple different variables to be equal.) + .. _notation-epsilon: .. _notation-length: @@ -82,6 +85,7 @@ Moreover, the following conventions are employed: (similarly for :math:`x^\ast`, :math:`x^+`, :math:`x^?`). This implicitly expresses a form of mapping syntactic constructions over a sequence. + Productions of the following form are interpreted as *records* that map a fixed set of fields :math:`\K{field}_i` to "values" :math:`A_i`, respectively: .. math:: diff --git a/document/core/syntax/modules.rst b/document/core/syntax/modules.rst index 4ffd0007d8..f6354e3fab 100644 --- a/document/core/syntax/modules.rst +++ b/document/core/syntax/modules.rst @@ -81,15 +81,24 @@ Each class of definition has its own *index space*, as distinguished by the foll The index space for :ref:`functions `, :ref:`tables `, :ref:`memories ` and :ref:`globals ` includes respective :ref:`imports ` declared in the same module. The indices of these imports precede the indices of other definitions in the same index space. -Element indices reference :ref:`element segments `. - -Data indices reference :ref:`data segments `. +Element indices reference :ref:`element segments ` and data indices reference :ref:`data segments `. The index space for :ref:`locals ` is only accessible inside a :ref:`function ` and includes the parameters of that function, which precede the local variables. Label indices reference :ref:`structured control instructions ` inside an instruction sequence. +.. _free-typeidx: +.. _free-funcidx: +.. _free-tableidx: +.. _free-memidx: +.. _free-globalidx: +.. _free-elemidx: +.. _free-dataidx: +.. _free-localidx: +.. _free-labelidx: +.. _free-index: + Conventions ........... @@ -97,6 +106,11 @@ Conventions * The meta variables :math:`x, y` range over indices in any of the other index spaces. +* The notation :math:`\F{idx}(A)` denotes the set of indices from index space :math:`\X{idx}` occurring free in :math:`A`. + +.. note:: + For example, if :math:`\instr^\ast` is :math:`(\DATADROP~x) (\MEMORYINIT~y)`, then :math:`\freedataidx(\instr^\ast) = \{x, y\}`. + .. index:: ! type definition, type index, function type pair: abstract syntax; type definition diff --git a/document/core/text/conventions.rst b/document/core/text/conventions.rst index ad9e29d4ab..ab5f07aafb 100644 --- a/document/core/text/conventions.rst +++ b/document/core/text/conventions.rst @@ -54,6 +54,8 @@ In order to distinguish symbols of the textual syntax from symbols of the abstra * Some productions are augmented by side conditions in parentheses, which restrict the applicability of the production. They provide a shorthand for a combinatorial expansion of the production into many separate cases. +* If the same meta variable or non-terminal symbol appears multiple times in a production (in the syntax or in an attribute), then all those occurrences must have the same instantiation. + .. _text-syntactic: * A distinction is made between *lexical* and *syntactic* productions. For the latter, arbitrary :ref:`white space ` is allowed in any place where the grammar contains spaces. The productions defining :ref:`lexical syntax ` and the syntax of :Ref:`values ` are considered lexical, all others are syntactic. diff --git a/document/core/util/macros.def b/document/core/util/macros.def index f8bc3378a2..41c7bda98e 100644 --- a/document/core/util/macros.def +++ b/document/core/util/macros.def @@ -226,6 +226,19 @@ .. |labelidx| mathdef:: \xref{syntax/modules}{syntax-labelidx}{\X{labelidx}} +.. Indices, meta functions + +.. |freetypeidx| mathdef:: \xref{syntax/modules}{syntax-typeidx}{\F{typeidx}} +.. |freefuncidx| mathdef:: \xref{syntax/modules}{syntax-funcidx}{\F{funcidx}} +.. |freetableidx| mathdef:: \xref{syntax/modules}{syntax-tableidx}{\F{tableidx}} +.. |freememidx| mathdef:: \xref{syntax/modules}{syntax-memidx}{\F{memidx}} +.. |freeglobalidx| mathdef:: \xref{syntax/modules}{syntax-globalidx}{\F{globalidx}} +.. |freeelemidx| mathdef:: \xref{syntax/modules}{syntax-elemidx}{\F{elemidx}} +.. |freedataidx| mathdef:: \xref{syntax/modules}{syntax-dataidx}{\F{dataidx}} +.. |freelocalidx| mathdef:: \xref{syntax/modules}{syntax-localidx}{\F{localidx}} +.. |freelabelidx| mathdef:: \xref{syntax/modules}{syntax-labelidx}{\F{labelidx}} + + .. Modules, terminals .. |MTYPES| mathdef:: \xref{syntax/modules}{syntax-module}{\K{types}} From 5ad80596f9e809bafbb3dfc6f9e48851fde3d6f8 Mon Sep 17 00:00:00 2001 From: Andreas Rossberg Date: Thu, 18 Apr 2019 13:25:54 +0200 Subject: [PATCH 080/199] [spec] Adjust soundness appendix --- document/core/appendix/embedding.rst | 2 +- document/core/appendix/index-rules.rst | 4 +- document/core/appendix/properties.rst | 59 +++++++++++++++++++++----- 3 files changed, 52 insertions(+), 13 deletions(-) diff --git a/document/core/appendix/embedding.rst b/document/core/appendix/embedding.rst index 8c866c78ce..9b649818ca 100644 --- a/document/core/appendix/embedding.rst +++ b/document/core/appendix/embedding.rst @@ -414,7 +414,7 @@ Tables .. _embed-table-grow: :math:`\F{table\_grow}(\store, \tableaddr, n:\u32, \val) : \store ~|~ \error` -........................................................................ +............................................................................. 1. Try :ref:`growing ` the :ref:`table instance ` :math:`\store.\STABLES[\tableaddr]` by :math:`n` elements: diff --git a/document/core/appendix/index-rules.rst b/document/core/appendix/index-rules.rst index 92c05b923a..a91ccf9c21 100644 --- a/document/core/appendix/index-rules.rst +++ b/document/core/appendix/index-rules.rst @@ -45,8 +45,8 @@ Typing of Runtime Constructs =============================================== =============================================================================== Construct Judgement =============================================== =============================================================================== -:ref:`Value ` :math:`\vdashval \val : \valtype` -:ref:`Result ` :math:`\vdashresult \result : \resulttype` +:ref:`Value ` :math:`S \vdashval \val : \valtype` +:ref:`Result ` :math:`S \vdashresult \result : \resulttype` :ref:`External value ` :math:`S \vdashexternval \externval : \externtype` :ref:`Function instance ` :math:`S \vdashfuncinst \funcinst : \functype` :ref:`Table instance ` :math:`S \vdashtableinst \tableinst : \tabletype` diff --git a/document/core/appendix/properties.rst b/document/core/appendix/properties.rst index 62cbd75ace..9b4d80d417 100644 --- a/document/core/appendix/properties.rst +++ b/document/core/appendix/properties.rst @@ -29,15 +29,54 @@ Values and Results :ref:`Values ` and :ref:`results ` can be classified by :ref:`value types ` and :ref:`result types ` as follows. -:ref:`Values ` :math:`t.\CONST~c` -............................................. +:ref:`Numeric Values ` :math:`t.\CONST~c` +..................................................... -* The value is valid with :ref:`value type ` :math:`t`. +* The value is valid with :ref:`number type ` :math:`t`. .. math:: \frac{ }{ - \vdashval t.\CONST~c : t + S \vdashval t.\CONST~c : t + } + + +:ref:`Null References ` :math:`\REFNULL` +.................................................... + +* The value is valid with :ref:`reference type ` :math:`\NULLREF`. + +.. math:: + \frac{ + }{ + S \vdashval \REFNULL : \NULLREF + } + + +:ref:`Function References ` :math:`\REFFUNCADDR~a` +.............................................................. + +* The :ref:`external value ` :math:`\EVFUNC~a` must be :ref:`valid `. + +* Then the value is valid with :ref:`reference type ` :math:`\FUNCREF`. + +.. math:: + \frac{ + S \vdashexternval \EVFUNC~a : \ETFUNC~\functype + }{ + S \vdashval \REFFUNCADDR~a : \FUNCREF + } + + +:ref:`Host References ` :math:`\REFHOST~a` +........................................................... + +* The value is valid with :ref:`reference type ` :math:`\ANYREF`. + +.. math:: + \frac{ + }{ + S \vdashval \REFHOST~a : \ANYREF } @@ -54,9 +93,9 @@ Values and Results .. math:: \frac{ - (\vdashval \val : t)^\ast + (S \vdashval \val : t)^\ast }{ - \vdashresult \val^\ast : [t^\ast] + S \vdashresult \val^\ast : [t^\ast] } @@ -68,7 +107,7 @@ Values and Results .. math:: \frac{ }{ - \vdashresult \TRAP : [t^\ast] + S \vdashresult \TRAP : [t^\ast] } @@ -183,7 +222,7 @@ Module instances are classified by *module contexts*, which are regular :ref:`co \forall S_1, \val^\ast,~ {\vdashstore S_1 \ok} \wedge {\vdashstoreextends S \extendsto S_1} \wedge - {\vdashresult \val^\ast : [t_1^\ast]} + {S_1 \vdashresult \val^\ast : [t_1^\ast]} \Longrightarrow {} \\ \qquad \X{hf}(S_1; \val^\ast) \supset \emptyset \wedge {} \\ \qquad \forall R \in \X{hf}(S_1; \val^\ast),~ @@ -191,7 +230,7 @@ Module instances are classified by *module contexts*, which are regular :ref:`co \exists S_2, \result,~ {\vdashstore S_2 \ok} \wedge {\vdashstoreextends S_1 \extendsto S_2} \wedge - {\vdashresult \result : [t_2^\ast]} \wedge + {S_2 \vdashresult \result : [t_2^\ast]} \wedge R = (S_2; \result) \end{array} }{ @@ -437,7 +476,7 @@ Finally, :ref:`frames ` are classified with *frame contexts*, whic \frac{ S \vdashmoduleinst \moduleinst : C \qquad - (\vdashval \val : t)^\ast + (S \vdashval \val : t)^\ast }{ S \vdashframe \{\ALOCALS~\val^\ast, \AMODULE~\moduleinst\} : (C, \CLOCALS~t^\ast) } From a2d5f93a209b1a919f60b4773924c436215d3c94 Mon Sep 17 00:00:00 2001 From: Andreas Rossberg Date: Thu, 18 Apr 2019 14:14:29 +0200 Subject: [PATCH 081/199] [spec] Adjust invoke --- document/core/appendix/properties.rst | 58 ++---------------------- document/core/exec/modules.rst | 65 ++++++++++++++++++++++++++- 2 files changed, 66 insertions(+), 57 deletions(-) diff --git a/document/core/appendix/properties.rst b/document/core/appendix/properties.rst index 9b4d80d417..d5d528d56b 100644 --- a/document/core/appendix/properties.rst +++ b/document/core/appendix/properties.rst @@ -21,64 +21,12 @@ In order to state and prove soundness precisely, the typing rules must be extend .. index:: value, value type, result, result type, trap -.. _valid-val: .. _valid-result: -Values and Results -~~~~~~~~~~~~~~~~~~ - -:ref:`Values ` and :ref:`results ` can be classified by :ref:`value types ` and :ref:`result types ` as follows. - -:ref:`Numeric Values ` :math:`t.\CONST~c` -..................................................... - -* The value is valid with :ref:`number type ` :math:`t`. - -.. math:: - \frac{ - }{ - S \vdashval t.\CONST~c : t - } - - -:ref:`Null References ` :math:`\REFNULL` -.................................................... - -* The value is valid with :ref:`reference type ` :math:`\NULLREF`. - -.. math:: - \frac{ - }{ - S \vdashval \REFNULL : \NULLREF - } - - -:ref:`Function References ` :math:`\REFFUNCADDR~a` -.............................................................. - -* The :ref:`external value ` :math:`\EVFUNC~a` must be :ref:`valid `. - -* Then the value is valid with :ref:`reference type ` :math:`\FUNCREF`. - -.. math:: - \frac{ - S \vdashexternval \EVFUNC~a : \ETFUNC~\functype - }{ - S \vdashval \REFFUNCADDR~a : \FUNCREF - } - - -:ref:`Host References ` :math:`\REFHOST~a` -........................................................... - -* The value is valid with :ref:`reference type ` :math:`\ANYREF`. - -.. math:: - \frac{ - }{ - S \vdashval \REFHOST~a : \ANYREF - } +Results +~~~~~~~ +:ref:`Results ` can be classified by :ref:`result types ` as follows. :ref:`Results ` :math:`\val^\ast` ................................................ diff --git a/document/core/exec/modules.rst b/document/core/exec/modules.rst index 4aad62cbdf..384ef7fe49 100644 --- a/document/core/exec/modules.rst +++ b/document/core/exec/modules.rst @@ -89,6 +89,67 @@ The following auxiliary typing rules specify this typing relation relative to a } +.. index:: value, value type, validation +.. _valid-val: + +Value Typing +~~~~~~~~~~~~ + +For the purpose of checking argument :ref:`values ` against the parameter types of exported :ref:`functions `, +values are classified by :ref:`value types `. +The following auxiliary typing rules specify this typing relation relative to a :ref:`store ` :math:`S` in which possibly referenced addresses live. + +:ref:`Numeric Values ` :math:`t.\CONST~c` +..................................................... + +* The value is valid with :ref:`number type ` :math:`t`. + +.. math:: + \frac{ + }{ + S \vdashval t.\CONST~c : t + } + + +:ref:`Null References ` :math:`\REFNULL` +.................................................... + +* The value is valid with :ref:`reference type ` :math:`\NULLREF`. + +.. math:: + \frac{ + }{ + S \vdashval \REFNULL : \NULLREF + } + + +:ref:`Function References ` :math:`\REFFUNCADDR~a` +.............................................................. + +* The :ref:`external value ` :math:`\EVFUNC~a` must be :ref:`valid `. + +* Then the value is valid with :ref:`reference type ` :math:`\FUNCREF`. + +.. math:: + \frac{ + S \vdashexternval \EVFUNC~a : \ETFUNC~\functype + }{ + S \vdashval \REFFUNCADDR~a : \FUNCREF + } + + +:ref:`Host References ` :math:`\REFHOST~a` +........................................................... + +* The value is valid with :ref:`reference type ` :math:`\ANYREF`. + +.. math:: + \frac{ + }{ + S \vdashval \REFHOST~a : \ANYREF + } + + .. index:: ! matching, external type .. _exec-import: .. _match: @@ -777,7 +838,7 @@ The following steps are performed: 5. For each :ref:`value type ` :math:`t_i` in :math:`t_1^n` and corresponding :ref:`value ` :math:`val_i` in :math:`\val^\ast`, do: - a. If :math:`\val_i` is not :math:`t_i.\CONST~c_i` for some :math:`c_i`, then: + a. If :math:`\val_i` is not :ref:`valid ` with value type :math:`t_i`, then: i. Fail. @@ -798,6 +859,6 @@ The values :math:`\val_{\F{res}}^m` are returned as the results of the invocatio \begin{array}{@{}lcl} \invoke(S, \funcaddr, \val^n) &=& S; F; \val^n~(\INVOKE~\funcaddr) \\ &(\iff & S.\SFUNCS[\funcaddr].\FITYPE = [t_1^n] \to [t_2^m] \\ - &\wedge& \val^n = (t_1.\CONST~c)^n \\ + &\wedge& (S \vdashval \val : t_1)^n \\ &\wedge& F = \{ \AMODULE~\{\}, \ALOCALS~\epsilon \}) \\ \end{array} From 8b3fb3797e6a7bd1dbaf9780a06a48f354d55a97 Mon Sep 17 00:00:00 2001 From: Andreas Rossberg Date: Fri, 19 Apr 2019 00:16:12 +0200 Subject: [PATCH 082/199] [spec] Fix latex issue --- document/core/appendix/embedding.rst | 58 ++++++++++++++-------------- 1 file changed, 29 insertions(+), 29 deletions(-) diff --git a/document/core/appendix/embedding.rst b/document/core/appendix/embedding.rst index 9b649818ca..754e594a5a 100644 --- a/document/core/appendix/embedding.rst +++ b/document/core/appendix/embedding.rst @@ -325,18 +325,18 @@ Tables .. _embed-table-alloc: -:math:`\F{table\_alloc}(\store, \tabletype) : (\store, \tableaddr, \val)` -......................................................................... +:math:`\F{table\_alloc}(\store, \tabletype) : (\store, \tableaddr, \reff)` +.......................................................................... 1. Pre-condition: :math:`\tabletype` is :math:`valid `. -2. Let :math:`\tableaddr` be the result of :ref:`allocating a table ` in :math:`\store` with :ref:`table type ` :math:`\tabletype`. +2. Let :math:`\tableaddr` be the result of :ref:`allocating a table ` in :math:`\store` with :ref:`table type ` :math:`\tabletype` and initialization value :math:`\reff`. 3. Return the new store paired with :math:`\tableaddr`. .. math:: \begin{array}{lclll} - \F{table\_alloc}(S, \X{tt}, v) &=& (S', \X{a}) && (\iff \alloctable(S, \X{tt}, v) = S', \X{a}) \\ + \F{table\_alloc}(S, \X{tt}, r) &=& (S', \X{a}) && (\iff \alloctable(S, \X{tt}, r) = S', \X{a}) \\ \end{array} @@ -359,46 +359,46 @@ Tables .. _embed-table-read: -:math:`\F{table\_read}(\store, \tableaddr, i:\u32) : \funcaddr^? ~|~ \error` -............................................................................ +:math:`\F{table\_read}(\store, \tableaddr, i:\X{u32}) : \reff ~|~ \error` +......................................................................... 1. Let :math:`\X{ti}` be the :ref:`table instance ` :math:`\store.\STABLES[\tableaddr]`. 2. If :math:`i` is larger than or equal to the length of :math:`\X{ti}.\TIELEM`, then return :math:`\ERROR`. -3. Else, return :math:`\X{ti}.\TIELEM[i]`. +3. Else, return the :ref:`reference value ` :math:`\X{ti}.\TIELEM[i]`. .. math:: \begin{array}{lclll} - \F{table\_read}(S, a, i) &=& \X{fa}^? && (\iff S.\STABLES[a].\TIELEM[i] = \X{fa}^?) \\ + \F{table\_read}(S, a, i) &=& r && (\iff S.\STABLES[a].\TIELEM[i] = r) \\ \F{table\_read}(S, a, i) &=& \ERROR && (\otherwise) \\ \end{array} .. _embed-table-write: -:math:`\F{table\_write}(\store, \tableaddr, i:\u32, \funcaddr^?) : \store ~|~ \error` -....................................................................................... +:math:`\F{table\_write}(\store, \tableaddr, i:\X{u32}, \reff) : \store ~|~ \error` +.................................................................................. 1. Let :math:`\X{ti}` be the :ref:`table instance ` :math:`\store.\STABLES[\tableaddr]`. 2. If :math:`i` is larger than or equal to the length of :math:`\X{ti}.\TIELEM`, then return :math:`\ERROR`. -3. Replace :math:`\X{ti}.\TIELEM[i]` with the optional :ref:`function address ` :math:`\X{fa}^?`. +3. Replace :math:`\X{ti}.\TIELEM[i]` with the :ref:`reference value ` :math:`\reff`. 4. Return the updated store. .. math:: \begin{array}{lclll} - \F{table\_write}(S, a, i, \X{fa}^?) &=& S' && (\iff S' = S \with \STABLES[a].\TIELEM[i] = \X{fa}^?) \\ - \F{table\_write}(S, a, i, \X{fa}^?) &=& \ERROR && (\otherwise) \\ + \F{table\_write}(S, a, i, r) &=& S' && (\iff S' = S \with \STABLES[a].\TIELEM[i] = r) \\ + \F{table\_write}(S, a, i, r) &=& \ERROR && (\otherwise) \\ \end{array} .. _embed-table-size: -:math:`\F{table\_size}(\store, \tableaddr) : \u32` -.................................................. +:math:`\F{table\_size}(\store, \tableaddr) : \X{u32}` +..................................................... 1. Return the length of :math:`\store.\STABLES[\tableaddr].\TIELEM`. @@ -413,10 +413,10 @@ Tables .. _embed-table-grow: -:math:`\F{table\_grow}(\store, \tableaddr, n:\u32, \val) : \store ~|~ \error` -............................................................................. +:math:`\F{table\_grow}(\store, \tableaddr, n:\X{u32}, \reff) : \store ~|~ \error` +................................................................................. -1. Try :ref:`growing ` the :ref:`table instance ` :math:`\store.\STABLES[\tableaddr]` by :math:`n` elements: +1. Try :ref:`growing ` the :ref:`table instance ` :math:`\store.\STABLES[\tableaddr]` by :math:`n` elements with initialization value :math:`\reff`: a. If it succeeds, return the updated store. @@ -425,9 +425,9 @@ Tables .. math:: ~ \\ \begin{array}{lclll} - \F{table\_grow}(S, a, n, v) &=& S' && - (\iff S' = S \with \STABLES[a] = \growtable(S.\STABLES[a], n, v)) \\ - \F{table\_grow}(S, a, n, v) &=& \ERROR && (\otherwise) \\ + \F{table\_grow}(S, a, n, r) &=& S' && + (\iff S' = S \with \STABLES[a] = \growtable(S.\STABLES[a], n, r)) \\ + \F{table\_grow}(S, a, n, r) &=& \ERROR && (\otherwise) \\ \end{array} @@ -473,8 +473,8 @@ Memories .. _embed-mem-read: -:math:`\F{mem\_read}(\store, \memaddr, i:\u32) : \byte ~|~ \error` -.................................................................. +:math:`\F{mem\_read}(\store, \memaddr, i:\X{u32}) : \byte ~|~ \error` +..................................................................... 1. Let :math:`\X{mi}` be the :ref:`memory instance ` :math:`\store.\SMEMS[\memaddr]`. @@ -491,8 +491,8 @@ Memories .. _embed-mem-write: -:math:`\F{mem\_write}(\store, \memaddr, i:\u32, \byte) : \store ~|~ \error` -........................................................................... +:math:`\F{mem\_write}(\store, \memaddr, i:\X{u32}, \byte) : \store ~|~ \error` +.............................................................................. 1. Let :math:`\X{mi}` be the :ref:`memory instance ` :math:`\store.\SMEMS[\memaddr]`. @@ -511,8 +511,8 @@ Memories .. _embed-mem-size: -:math:`\F{mem\_size}(\store, \memaddr) : \u32` -.............................................. +:math:`\F{mem\_size}(\store, \memaddr) : \X{u32}` +................................................. 1. Return the length of :math:`\store.\SMEMS[\memaddr].\MIDATA` divided by the :ref:`page size `. @@ -527,8 +527,8 @@ Memories .. _embed-mem-grow: -:math:`\F{mem\_grow}(\store, \memaddr, n:\u32) : \store ~|~ \error` -................................................................... +:math:`\F{mem\_grow}(\store, \memaddr, n:\X{u32}) : \store ~|~ \error` +...................................................................... 1. Try :ref:`growing ` the :ref:`memory instance ` :math:`\store.\SMEMS[\memaddr]` by :math:`n` :ref:`pages `: From 02117e47dd9fc9913abeace14e6f369371089c4b Mon Sep 17 00:00:00 2001 From: Andreas Rossberg Date: Fri, 19 Apr 2019 07:38:19 +0200 Subject: [PATCH 083/199] [spec] Remove Sphinx/Latex workaround --- document/core/appendix/embedding.rst | 32 ++++++++++++++-------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/document/core/appendix/embedding.rst b/document/core/appendix/embedding.rst index 754e594a5a..6294239760 100644 --- a/document/core/appendix/embedding.rst +++ b/document/core/appendix/embedding.rst @@ -359,8 +359,8 @@ Tables .. _embed-table-read: -:math:`\F{table\_read}(\store, \tableaddr, i:\X{u32}) : \reff ~|~ \error` -......................................................................... +:math:`\F{table\_read}(\store, \tableaddr, i:\u32) : \reff ~|~ \error` +...................................................................... 1. Let :math:`\X{ti}` be the :ref:`table instance ` :math:`\store.\STABLES[\tableaddr]`. @@ -377,8 +377,8 @@ Tables .. _embed-table-write: -:math:`\F{table\_write}(\store, \tableaddr, i:\X{u32}, \reff) : \store ~|~ \error` -.................................................................................. +:math:`\F{table\_write}(\store, \tableaddr, i:\u32, \reff) : \store ~|~ \error` +............................................................................... 1. Let :math:`\X{ti}` be the :ref:`table instance ` :math:`\store.\STABLES[\tableaddr]`. @@ -397,8 +397,8 @@ Tables .. _embed-table-size: -:math:`\F{table\_size}(\store, \tableaddr) : \X{u32}` -..................................................... +:math:`\F{table\_size}(\store, \tableaddr) : \u32` +.................................................. 1. Return the length of :math:`\store.\STABLES[\tableaddr].\TIELEM`. @@ -413,8 +413,8 @@ Tables .. _embed-table-grow: -:math:`\F{table\_grow}(\store, \tableaddr, n:\X{u32}, \reff) : \store ~|~ \error` -................................................................................. +:math:`\F{table\_grow}(\store, \tableaddr, n:\u32, \reff) : \store ~|~ \error` +.............................................................................. 1. Try :ref:`growing ` the :ref:`table instance ` :math:`\store.\STABLES[\tableaddr]` by :math:`n` elements with initialization value :math:`\reff`: @@ -473,8 +473,8 @@ Memories .. _embed-mem-read: -:math:`\F{mem\_read}(\store, \memaddr, i:\X{u32}) : \byte ~|~ \error` -..................................................................... +:math:`\F{mem\_read}(\store, \memaddr, i:\u32) : \byte ~|~ \error` +.................................................................. 1. Let :math:`\X{mi}` be the :ref:`memory instance ` :math:`\store.\SMEMS[\memaddr]`. @@ -491,8 +491,8 @@ Memories .. _embed-mem-write: -:math:`\F{mem\_write}(\store, \memaddr, i:\X{u32}, \byte) : \store ~|~ \error` -.............................................................................. +:math:`\F{mem\_write}(\store, \memaddr, i:\u32, \byte) : \store ~|~ \error` +........................................................................... 1. Let :math:`\X{mi}` be the :ref:`memory instance ` :math:`\store.\SMEMS[\memaddr]`. @@ -511,8 +511,8 @@ Memories .. _embed-mem-size: -:math:`\F{mem\_size}(\store, \memaddr) : \X{u32}` -................................................. +:math:`\F{mem\_size}(\store, \memaddr) : \u32` +.............................................. 1. Return the length of :math:`\store.\SMEMS[\memaddr].\MIDATA` divided by the :ref:`page size `. @@ -527,8 +527,8 @@ Memories .. _embed-mem-grow: -:math:`\F{mem\_grow}(\store, \memaddr, n:\X{u32}) : \store ~|~ \error` -...................................................................... +:math:`\F{mem\_grow}(\store, \memaddr, n:\u32) : \store ~|~ \error` +................................................................... 1. Try :ref:`growing ` the :ref:`memory instance ` :math:`\store.\SMEMS[\memaddr]` by :math:`n` :ref:`pages `: From 4c9726154ccedda35ea1a13006f072653a49dfaf Mon Sep 17 00:00:00 2001 From: Ben Smith Date: Fri, 19 Apr 2019 10:12:34 -0700 Subject: [PATCH 084/199] [spec] Proper binary format for element segments (#82) The element segment binary format allows for `ref.null` as well as `ref.func`. TODO: text format --- document/core/binary/modules.rst | 20 ++++++------- document/core/syntax/modules.rst | 8 ++++-- document/core/util/macros.def | 6 ++++ document/core/valid/modules.rst | 48 ++++++++++++++++++++++++-------- 4 files changed, 59 insertions(+), 23 deletions(-) diff --git a/document/core/binary/modules.rst b/document/core/binary/modules.rst index 7c5cdc745a..dbdc17c6d1 100644 --- a/document/core/binary/modules.rst +++ b/document/core/binary/modules.rst @@ -314,6 +314,7 @@ It decodes into an optional :ref:`start function ` that represents single: element; segment .. _binary-elem: .. _binary-elemsec: +.. _binary-elemexpr: Element Section ~~~~~~~~~~~~~~~ @@ -327,13 +328,14 @@ It decodes into a vector of :ref:`element segments ` that represent \X{seg}^\ast{:}\Bsection_9(\Bvec(\Belem)) &\Rightarrow& \X{seg} \\ \production{element segment} & \Belem &::=& \hex{00}~~e{:}\Bexpr~~y^\ast{:}\Bvec(\Bfuncidx) - &\Rightarrow& \{ \ETABLE~0, \EOFFSET~e, \EINIT~y^\ast \} \\ - \production{element segment} & \Belem &::=& - \hex{01}~~y^\ast{:}\Bvec(\Bfuncidx) - &\Rightarrow& \{ \EINIT~y^\ast \} \\ - \production{element segment} & \Belem &::=& + &\Rightarrow& \{ \ETABLE~0, \EOFFSET~e, \EINIT~((\REFFUNC~y)~\END)^\ast \} \\ &&|& + \hex{01}~~e^\ast{:}\Bvec(\Belemexpr) + &\Rightarrow& \{ \EINIT~e^\ast \} \\ &&|& \hex{02}~~x{:}\Btableidx~~e{:}\Bexpr~~y^\ast{:}\Bvec(\Bfuncidx) - &\Rightarrow& \{ \ETABLE~x, \EOFFSET~e, \EINIT~y^\ast \} \\ + &\Rightarrow& \{ \ETABLE~x, \EOFFSET~e, \EINIT~((\REFFUNC~y)~\END)^\ast \} \\ + \production{elemexpr} & \Belemexpr &::=& + \hex{D0}~\hex{0B} &\Rightarrow& \REFNULL~\END \\ &&|& + \hex{D2}~x{:}\Bfuncidx~\hex{0B} &\Rightarrow& (\REFFUNC~x)~\END \\ \end{array} .. note:: @@ -419,11 +421,9 @@ It decodes into a vector of :ref:`data segments ` that represent th \X{seg}^\ast{:}\Bsection_{11}(\Bvec(\Bdata)) &\Rightarrow& \X{seg} \\ \production{data segment} & \Bdata &::=& \hex{00}~~e{:}\Bexpr~~b^\ast{:}\Bvec(\Bbyte) - &\Rightarrow& \{ \DMEM~0, \DOFFSET~e, \DINIT~b^\ast \} \\ - \production{data segment} & \Bdata &::=& + &\Rightarrow& \{ \DMEM~0, \DOFFSET~e, \DINIT~b^\ast \} \\ &&|& \hex{01}~~b^\ast{:}\Bvec(\Bbyte) - &\Rightarrow& \{ \DINIT~b^\ast \} \\ - \production{data segment} & \Bdata &::=& + &\Rightarrow& \{ \DINIT~b^\ast \} \\ &&|& \hex{02}~~x{:}\Bmemidx~~e{:}\Bexpr~~b^\ast{:}\Bvec(\Bbyte) &\Rightarrow& \{ \DMEM~x, \DOFFSET~e, \DINIT~b^\ast \} \\ \end{array} diff --git a/document/core/syntax/modules.rst b/document/core/syntax/modules.rst index f6354e3fab..4aeff728e5 100644 --- a/document/core/syntax/modules.rst +++ b/document/core/syntax/modules.rst @@ -247,6 +247,7 @@ starting with the smallest index not referencing a global :ref:`import ` :ref:`expression `. diff --git a/document/core/util/macros.def b/document/core/util/macros.def index 41c7bda98e..82d89a12ff 100644 --- a/document/core/util/macros.def +++ b/document/core/util/macros.def @@ -267,6 +267,9 @@ .. |EOFFSET| mathdef:: \xref{syntax/modules}{syntax-elem}{\K{offset}} .. |EINIT| mathdef:: \xref{syntax/modules}{syntax-elem}{\K{init}} +.. |REFNULL| mathdef:: \xref{syntax/modules}{syntax-elemexpr}{\K{ref.null}} +.. |REFFUNC| mathdef:: \xref{syntax/modules}{syntax-elemexpr}{\K{ref.func}} + .. |DMEM| mathdef:: \xref{syntax/modules}{syntax-data}{\K{data}} .. |DOFFSET| mathdef:: \xref{syntax/modules}{syntax-data}{\K{offset}} .. |DINIT| mathdef:: \xref{syntax/modules}{syntax-data}{\K{init}} @@ -302,6 +305,7 @@ .. |importdesc| mathdef:: \xref{syntax/modules}{syntax-importdesc}{\X{importdesc}} .. |exportdesc| mathdef:: \xref{syntax/modules}{syntax-exportdesc}{\X{exportdesc}} .. |elem| mathdef:: \xref{syntax/modules}{syntax-elem}{\X{elem}} +.. |elemexpr| mathdef:: \xref{syntax/modules}{syntax-elemexpr}{\X{elemexpr}} .. |data| mathdef:: \xref{syntax/modules}{syntax-data}{\X{data}} .. |start| mathdef:: \xref{syntax/modules}{syntax-start}{\X{start}} @@ -529,6 +533,7 @@ .. |Bimportdesc| mathdef:: \xref{binary/modules}{binary-importdesc}{\B{importdesc}} .. |Bexportdesc| mathdef:: \xref{binary/modules}{binary-exportdesc}{\B{exportdesc}} .. |Belem| mathdef:: \xref{binary/modules}{binary-elem}{\B{elem}} +.. |Belemexpr| mathdef:: \xref{binary/modules}{binary-elemexpr}{\B{elemexpr}} .. |Bcode| mathdef:: \xref{binary/modules}{binary-code}{\B{code}} .. |Blocal| mathdef:: \xref{binary/modules}{binary-local}{\B{local}} .. |Blocals| mathdef:: \xref{binary/modules}{binary-local}{\B{locals}} @@ -773,6 +778,7 @@ .. |vdashmem| mathdef:: \xref{valid/modules}{valid-mem}{\vdash} .. |vdashglobal| mathdef:: \xref{valid/modules}{valid-global}{\vdash} .. |vdashelem| mathdef:: \xref{valid/modules}{valid-elem}{\vdash} +.. |vdashelemexpr| mathdef:: \xref{valid/modules}{valid-elemexpr}{\vdash} .. |vdashdata| mathdef:: \xref{valid/modules}{valid-data}{\vdash} .. |vdashstart| mathdef:: \xref{valid/modules}{valid-start}{\vdash} .. |vdashexport| mathdef:: \xref{valid/modules}{valid-export}{\vdash} diff --git a/document/core/valid/modules.rst b/document/core/valid/modules.rst index 038ae156a8..b24d6fa895 100644 --- a/document/core/valid/modules.rst +++ b/document/core/valid/modules.rst @@ -147,7 +147,7 @@ Element Segments Element segments :math:`\elem` are classified by :ref:`segment types `. -:math:`\{ \ETABLE~x, \EOFFSET~\expr, \EINIT~y^\ast \}` +:math:`\{ \ETABLE~x, \EOFFSET~\expr, \EINIT~e^\ast \}` ...................................................... * The table :math:`C.\CTABLES[x]` must be defined in the context. @@ -160,8 +160,9 @@ Element segments :math:`\elem` are classified by :ref:`segment types `. -* For each :math:`y_i` in :math:`y^\ast`, - the function :math:`C.\CFUNCS[y]` must be defined in the context. +* For each :math:`e_i` in :math:`e^\ast`, + + * The element expression :math:`e_i` must be :ref:`valid `. * Then the element segment is valid with type |SACTIVE|. @@ -174,26 +175,51 @@ Element segments :math:`\elem` are classified by :ref:`segment types `. * Then the element segment is valid with type |SPASSIVE|. .. math:: \frac{ - (C.\CFUNCS[y] = \functype)^\ast + (C \vdashelemexpr e \ok)^\ast + }{ + C \vdashelem \{ \EINIT~e^\ast \} : \SPASSIVE + } + + +.. _valid-elemexpr: + +:math:`\elemexpr` +................. + +* An element expression must be: + + * either of the form :math:`\REFNULL~\END`, + + * or of the form :math:`(\REFFUNC~x)~\END`, in which case :math:`C.\CFUNCS[x]` must be defined in the context. + +.. math:: + \frac{ + }{ + C \vdashelemexpr \REFNULL~\END \ok + } + \qquad + \frac{ + C.\CFUNCS[x] = \functype }{ - C \vdashelem \{ \EINIT~y^\ast \} : \SPASSIVE + C \vdashelemexpr (\REFFUNC~x)~\END \ok } From 05672b0d33fc84c679bc9e9208bea89f401f35b9 Mon Sep 17 00:00:00 2001 From: Andreas Rossberg Date: Sat, 20 Apr 2019 08:42:09 +0200 Subject: [PATCH 085/199] [test] Disallow table size overflow --- test/core/table_grow.wast | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/test/core/table_grow.wast b/test/core/table_grow.wast index bd9c395a4e..158df3cab1 100644 --- a/test/core/table_grow.wast +++ b/test/core/table_grow.wast @@ -35,6 +35,17 @@ (assert_trap (invoke "get" (i32.const 5)) "out of bounds table access") +;; Reject growing to size outside i32 value range +(module + (table $t 0x10 anyref) + (func $f (export "grow") (result i32) + (table.grow $t (ref.func $f) (i32.const 0xffff_fff0)) + ) +) + +(assert_return (invoke "grow") (i32.const -1)) + + (module (table $t 0 anyref) (func (export "grow") (param i32) (result i32) From 09dccac7d53cbaa2375b3260db50f4dc48c2f3a5 Mon Sep 17 00:00:00 2001 From: Andreas Rossberg Date: Tue, 23 Apr 2019 12:50:03 +0200 Subject: [PATCH 086/199] [spec] Correctly account for subtyping in global/table instances (#39) * Make types explicit in global/table/memory instances * Allow global/table values/elements to be subtypes * Simplify externval typing --- document/core/appendix/embedding.rst | 42 +++++------- document/core/appendix/index-rules.rst | 3 + document/core/appendix/properties.rst | 85 ++++++++++++++--------- document/core/exec/modules.rst | 94 +++++++++++++++----------- document/core/exec/runtime.rst | 27 ++++---- document/core/util/macros.def | 6 +- 6 files changed, 144 insertions(+), 113 deletions(-) diff --git a/document/core/appendix/embedding.rst b/document/core/appendix/embedding.rst index 6294239760..15ce8c7d5b 100644 --- a/document/core/appendix/embedding.rst +++ b/document/core/appendix/embedding.rst @@ -280,15 +280,13 @@ Functions :math:`\F{func\_type}(\store, \funcaddr) : \functype` ..................................................... -1. Assert: the :ref:`external value ` :math:`\EVFUNC~\funcaddr` is :ref:`valid ` with :ref:`external type ` :math:`\ETFUNC~\functype`. +1. Return :math:`S.\SFUNCS[a].\FITYPE`. -2. Return :math:`\functype`. - -3. Post-condition: :math:`\functype` is :ref:`valid `. +2. Post-condition: the returned :ref:`function type ` is :ref:`valid `. .. math:: \begin{array}{lclll} - \F{func\_type}(S, a) &=& \X{ft} && (\iff S \vdashexternval \EVFUNC~a : \ETFUNC~\X{ft}) \\ + \F{func\_type}(S, a) &=& S.\SFUNCS[a].\FITYPE \\ \end{array} @@ -345,15 +343,13 @@ Tables :math:`\F{table\_type}(\store, \tableaddr) : \tabletype` ........................................................ -1. Assert: the :ref:`external value ` :math:`\EVTABLE~\tableaddr` is :ref:`valid ` with :ref:`external type ` :math:`\ETTABLE~\tabletype`. - -2. Return :math:`\tabletype`. +1. Return :math:`S.\STABLES[a].\TITYPE`. -3. Post-condition: :math:`\tabletype` is :math:`valid `. +2. Post-condition: the returned :ref:`table type ` is :math:`valid `. .. math:: \begin{array}{lclll} - \F{table\_type}(S, a) &=& \X{tt} && (\iff S \vdashexternval \EVTABLE~a : \ETTABLE~\X{tt}) \\ + \F{table\_type}(S, a) &=& S.\STABLES[a].\TITYPE \\ \end{array} @@ -459,15 +455,13 @@ Memories :math:`\F{mem\_type}(\store, \memaddr) : \memtype` .................................................. -1. Assert: the :ref:`external value ` :math:`\EVMEM~\memaddr` is :ref:`valid ` with :ref:`external type ` :math:`\ETMEM~\memtype`. - -2. Return :math:`\memtype`. +1. Return :math:`S.\SMEMS[a].\MITYPE`. -3. Post-condition: :math:`\memtype` is :math:`valid `. +2. Post-condition: the returned :ref:`memory type ` is :math:`valid `. .. math:: \begin{array}{lclll} - \F{mem\_type}(S, a) &=& \X{mt} && (\iff S \vdashexternval \EVMEM~a : \ETMEM~\X{mt}) \\ + \F{mem\_type}(S, a) &=& S.\SMEMS[a].\MITYPE \\ \end{array} @@ -574,15 +568,13 @@ Globals :math:`\F{global\_type}(\store, \globaladdr) : \globaltype` ........................................................... -1. Assert: the :ref:`external value ` :math:`\EVGLOBAL~\globaladdr` is :ref:`valid ` with :ref:`external type ` :math:`\ETGLOBAL~\globaltype`. +1. Return :math:`S.\SGLOBALS[a].\GITYPE`. -2. Return :math:`\globaltype`. - -3. Post-condition: :math:`\globaltype` is :math:`valid `. +2. Post-condition: the returned :ref:`global type ` is :math:`valid `. .. math:: \begin{array}{lclll} - \F{global\_type}(S, a) &=& \X{gt} && (\iff S \vdashexternval \EVGLOBAL~a : \ETGLOBAL~\X{gt}) \\ + \F{global\_type}(S, a) &=& S.\SGLOBALS[a].\GITYPE \\ \end{array} @@ -608,15 +600,17 @@ Globals 1. Let :math:`\X{gi}` be the :ref:`global instance ` :math:`\store.\SGLOBALS[\globaladdr]`. -2. If :math:`\X{gi}.\GIMUT` is not :math:`\MVAR`, then return :math:`\ERROR`. +2. Let :math:`\mut~t` be the structure of the :ref:`global type ` :math:`\X{gi}.\GITYPE`. -3. Replace :math:`\X{gi}.\GIVALUE` with the :ref:`value ` :math:`\val`. +3. If :math:`\mut` is not :math:`\MVAR`, then return :math:`\ERROR`. -4. Return the updated store. +4. Replace :math:`\X{gi}.\GIVALUE` with the :ref:`value ` :math:`\val`. + +5. Return the updated store. .. math:: ~ \\ \begin{array}{lclll} - \F{global\_write}(S, a, v) &=& S' && (\iff S.\SGLOBALS[a].\GIMUT = \MVAR \wedge S' = S \with \SGLOBALS[a].\GIVALUE = v) \\ + \F{global\_write}(S, a, v) &=& S' && (\iff S.\SGLOBALS[a].\GITYPE = \MVAR~t \wedge S' = S \with \SGLOBALS[a].\GIVALUE = v) \\ \F{global\_write}(S, a, v) &=& \ERROR && (\otherwise) \\ \end{array} diff --git a/document/core/appendix/index-rules.rst b/document/core/appendix/index-rules.rst index a91ccf9c21..fe1fb3f2ff 100644 --- a/document/core/appendix/index-rules.rst +++ b/document/core/appendix/index-rules.rst @@ -78,7 +78,10 @@ Matching =============================================== =============================================================================== Construct Judgement =============================================== =============================================================================== +:ref:`Number type ` :math:`\vdashnumtypematch \numtype_1 \matchesvaltype \numtype_2` +:ref:`Reference type ` :math:`\vdashreftypematch \reftype_1 \matchesvaltype \reftype_2` :ref:`Value type ` :math:`\vdashvaltypematch \valtype_1 \matchesvaltype \valtype_2` +:ref:`Result type ` :math:`\vdashresulttypematch [t_1^?] \matchesresulttype [t_2^?]` :ref:`External type ` :math:`\vdashexterntypematch \externtype_1 \matchesexterntype \externtype_2` :ref:`Limits ` :math:`\vdashlimitsmatch \limits_1 \matcheslimits \limits_2` =============================================== =============================================================================== diff --git a/document/core/appendix/properties.rst b/document/core/appendix/properties.rst index d5d528d56b..490e2c5545 100644 --- a/document/core/appendix/properties.rst +++ b/document/core/appendix/properties.rst @@ -196,59 +196,80 @@ Module instances are classified by *module contexts*, which are regular :ref:`co .. index:: table type, table instance, limits, function address .. _valid-tableinst: -:ref:`Table Instances ` :math:`\{ \TIELEM~(\X{fa}^?)^n, \TIMAX~m^? \}` -.............................................................................................. +:ref:`Table Instances ` :math:`\{ \TITYPE~(\limits~t), \TIELEM~\reff^\ast \}` +............................................................................................... -* For each optional :ref:`function address ` :math:`\X{fa}^?_i` in the table elements :math:`(\X{fa}^?)^n`: +* The :ref:`table type ` :math:`\limits~t` must be :ref:`valid `. - * Either :math:`\X{fa}^?_i` is empty. +* The length of :math:`\reff^\ast` must equal :math:`\limits.\LMIN`. - * Or the :ref:`external value ` :math:`\EVFUNC~\X{fa}` must be :ref:`valid ` with some :ref:`external type ` :math:`\ETFUNC~\X{ft}`. +* For each :ref:`reference ` :math:`\reff_i` in the table elements :math:`\reff^n`: -* The :ref:`limits ` :math:`\{\LMIN~n, \LMAX~m^?\}` must be :ref:`valid `. + * The :ref:`reference ` :math:`\reff_i` must be :ref:`valid ` with some :ref:`reference type ` :math:`t'_i`. -* Then the table instance is valid with :ref:`table type ` :math:`\{\LMIN~n, \LMAX~m^?\}~\FUNCREF`. + * The :ref:`reference type ` :math:`t'_i` must :ref:`match ` the :ref:`reference type ` :math:`t`. + +* Then the table instance is valid with :ref:`table type ` :math:`\limits~t`. .. math:: \frac{ - ((S \vdash \EVFUNC~\X{fa} : \ETFUNC~\functype)^?)^n + \vdashtabletype \limits~t \ok + \qquad + n = \limits.\LMIN \qquad - \vdashlimits \{\LMIN~n, \LMAX~m^?\} \ok + (S \vdash \reff : t')^n + \qquad + (\vdashreftypematch t' \matchesvaltype t)^n }{ - S \vdashtableinst \{ \TIELEM~(\X{fa}^?)^n, \TIMAX~m^? \} : \{\LMIN~n, \LMAX~m^?\}~\FUNCREF + S \vdashtableinst \{ \TITYPE~(\limits~t), \TIELEM~\reff^n \} : \limits~t } .. index:: memory type, memory instance, limits, byte .. _valid-meminst: -:ref:`Memory Instances ` :math:`\{ \MIDATA~b^n, \MIMAX~m^? \}` -.............................................................................. +:ref:`Memory Instances ` :math:`\{ \MITYPE~\limits, \MIDATA~b^\ast \}` +...................................................................................... + +* The :ref:`memory type ` :math:`\{\LMIN~n, \LMAX~m^?\}` must be :ref:`valid `. -* The :ref:`limits ` :math:`\{\LMIN~n, \LMAX~m^?\}` must be :ref:`valid `. +* The length of :math:`b^\ast` must equal :math:`\limits.\LMIN` multiplied by the :ref:`page size ` :math:`64\,\F{Ki}`. -* Then the memory instance is valid with :ref:`memory type ` :math:`\{\LMIN~n, \LMAX~m^?\}`. +* Then the memory instance is valid with :ref:`memory type ` :math:`\limits`. .. math:: \frac{ - \vdashlimits \{\LMIN~n, \LMAX~m^?\} \ok + \vdashmemtype \limits \ok + \qquad + n = \limits.\LMIN \cdot 64\,\F{Ki} }{ - S \vdashmeminst \{ \MIDATA~b^n, \MIMAX~m^? \} : \{\LMIN~n, \LMAX~m^?\} + S \vdashmeminst \{ \MITYPE~\limits, \MIDATA~b^n \} : \limits } .. index:: global type, global instance, value, mutability .. _valid-globalinst: -:ref:`Global Instances ` :math:`\{ \GIVALUE~(t.\CONST~c), \GIMUT~\mut \}` -............................................................................................ +:ref:`Global Instances ` :math:`\{ \GITYPE~(\mut~t), \GIVALUE~\val \}` +......................................................................................... + +* The :ref:`global type ` :math:`\mut~t` must be :ref:`valid `. + +* The :ref:`value ` :math:`\val` must be :ref:`valid ` with some :ref:`value type ` :math:`t'`. -* The global instance is valid with :ref:`global type ` :math:`\mut~t`. +* The :ref:`value type ` :math:`t'` must :ref:`match ` the :ref:`value type ` :math:`t`. + +* Then the global instance is valid with :ref:`global type ` :math:`\mut~t`. .. math:: \frac{ + \vdashglobaltype \mut~t \ok + \qquad + S \vdashval \val : t' + \qquad + \vdashvaltypematch t' \matchesvaltype t }{ - S \vdashglobalinst \{ \GIVALUE~(t.\CONST~c), \GIMUT~\mut \} : \mut~t + S \vdashglobalinst \{ \GITYPE~(\mut~t), \GIVALUE~\val \} : \mut~t } @@ -508,7 +529,7 @@ To that end, all previous typing judgements :math:`C \vdash \X{prop}` are genera :math:`\INITELEM~\tableaddr~o~x^n` .................................. -* The :ref:`external table value ` :math:`\EVTABLE~\tableaddr` must be :ref:`valid ` with some :ref:`external table type ` :math:`\ETTABLE~\limits~\FUNCREF`. +* The :ref:`external table value ` :math:`\EVTABLE~\tableaddr` must be :ref:`valid ` with some :ref:`external table type ` :math:`\ETTABLE~(\limits~\FUNCREF)`. * The index :math:`o + n` must be smaller than or equal to :math:`\limits.\LMIN`. @@ -676,15 +697,15 @@ a store state :math:`S'` extends state :math:`S`, written :math:`S \extendsto S' :ref:`Table Instance ` :math:`\tableinst` ........................................................... -* The length of :math:`\tableinst.\TIELEM` must not shrink. +* The :ref:`table type ` :math:`\tableinst.\TITYPE` must remain unchanged. -* The value of :math:`\tableinst.\TIMAX` must remain unchanged. +* The length of :math:`\tableinst.\TIELEM` must not shrink. .. math:: \frac{ n_1 \leq n_2 }{ - \vdashtableinstextends \{\TIELEM~(\X{fa}_1^?)^{n_1}, \TIMAX~m\} \extendsto \{\TIELEM~(\X{fa}_2^?)^{n_2}, \TIMAX~m\} + \vdashtableinstextends \{\TITYPE~\X{tt}, \TIELEM~(\X{fa}_1^?)^{n_1}\} \extendsto \{\TITYPE~\X{tt}, \TIELEM~(\X{fa}_2^?)^{n_2}\} } @@ -694,15 +715,15 @@ a store state :math:`S'` extends state :math:`S`, written :math:`S \extendsto S' :ref:`Memory Instance ` :math:`\meminst` ........................................................ -* The length of :math:`\meminst.\MIDATA` must not shrink. +* The :ref:`memory type ` :math:`\meminst.\MITYPE` must remain unchanged. -* The value of :math:`\meminst.\MIMAX` must remain unchanged. +* The length of :math:`\meminst.\MIDATA` must not shrink. .. math:: \frac{ n_1 \leq n_2 }{ - \vdashmeminstextends \{\MIDATA~b_1^{n_1}, \MIMAX~m\} \extendsto \{\MIDATA~b_2^{n_2}, \MIMAX~m\} + \vdashmeminstextends \{\MITYPE~\X{mt}, \MIDATA~b_1^{n_1}\} \extendsto \{\MITYPE~\X{mt}, \MIDATA~b_2^{n_2}\} } @@ -712,17 +733,17 @@ a store state :math:`S'` extends state :math:`S`, written :math:`S \extendsto S' :ref:`Global Instance ` :math:`\globalinst` .............................................................. -* The :ref:`mutability ` :math:`\globalinst.\GIMUT` must remain unchanged. +* The :ref:`global type ` :math:`\globalinst.\GITYPE` must remain unchanged. -* The :ref:`value type ` of the :ref:`value ` :math:`\globalinst.\GIVALUE` must remain unchanged. +* Let :math:`\mut~t` be the structure of :math:`\globalinst.\GITYPE`. -* If :math:`\globalinst.\GIMUT` is |MCONST|, then the :ref:`value ` :math:`\globalinst.\GIVALUE` must remain unchanged. +* If :math:`\mut` is |MCONST|, then the :ref:`value ` :math:`\globalinst.\GIVALUE` must remain unchanged. .. math:: \frac{ - \mut = \MVAR \vee c_1 = c_2 + \mut = \MVAR \vee \val_1 = \val_2 }{ - \vdashglobalinstextends \{\GIVALUE~(t.\CONST~c_1), \GIMUT~\mut\} \extendsto \{\GIVALUE~(t.\CONST~c_2), \GIMUT~\mut\} + \vdashglobalinstextends \{\GITYPE~(\mut~t), \GIVALUE~\val_1\} \extendsto \{\GITYPE~(\mut~t), \GIVALUE~\val_2\} } diff --git a/document/core/exec/modules.rst b/document/core/exec/modules.rst index 384ef7fe49..ac6a2849e4 100644 --- a/document/core/exec/modules.rst +++ b/document/core/exec/modules.rst @@ -23,51 +23,48 @@ The following auxiliary typing rules specify this typing relation relative to a :math:`\EVFUNC~a` ................. -* The store entry :math:`S.\SFUNCS[a]` must be a :ref:`function instance ` :math:`\{\FITYPE~\functype, \dots\}`. +* The store entry :math:`S.\SFUNCS[a]` must exist. -* Then :math:`\EVFUNC~a` is valid with :ref:`external type ` :math:`\ETFUNC~\functype`. +* Then :math:`\EVFUNC~a` is valid with :ref:`external type ` :math:`\ETFUNC~S.\SFUNCS[a].\FITYPE`. .. math:: \frac{ - S.\SFUNCS[a] = \{\FITYPE~\functype, \dots\} }{ - S \vdashexternval \EVFUNC~a : \ETFUNC~\functype + S \vdashexternval \EVFUNC~a : \ETFUNC~S.\SFUNCS[a].\FITYPE } -.. index:: table type, table address, limits +.. index:: table type, table address .. _valid-externval-table: :math:`\EVTABLE~a` .................. -* The store entry :math:`S.\STABLES[a]` must be a :ref:`table instance ` :math:`\{\TIELEM~(\X{fa}^?)^n, \TIMAX~m^?\}`. +* The store entry :math:`S.\STABLES[a]` must exist. -* Then :math:`\EVTABLE~a` is valid with :ref:`external type ` :math:`\ETTABLE~(\{\LMIN~n, \LMAX~m^?\}~\FUNCREF)`. +* Then :math:`\EVTABLE~a` is valid with :ref:`external type ` :math:`\ETTABLE~S.\STABLES[a].\TITYPE`. .. math:: \frac{ - S.\STABLES[a] = \{ \TIELEM~(\X{fa}^?)^n, \TIMAX~m^? \} }{ - S \vdashexternval \EVTABLE~a : \ETTABLE~(\{\LMIN~n, \LMAX~m^?\}~\FUNCREF) + S \vdashexternval \EVTABLE~a : \ETTABLE~S.\STABLES[a].\TITYPE } -.. index:: memory type, memory address, limits +.. index:: memory type, memory address .. _valid-externval-mem: :math:`\EVMEM~a` ................ -* The store entry :math:`S.\SMEMS[a]` must be a :ref:`memory instance ` :math:`\{\MIDATA~b^{n\cdot64\,\F{Ki}}, \MIMAX~m^?\}`, for some :math:`n`. +* The store entry :math:`S.\SMEMS[a]` must exist. -* Then :math:`\EVMEM~a` is valid with :ref:`external type ` :math:`\ETMEM~(\{\LMIN~n, \LMAX~m^?\})`. +* Then :math:`\EVMEM~a` is valid with :ref:`external type ` :math:`\ETMEM~S.\SMEMS[a].\MITYPE`. .. math:: \frac{ - S.\SMEMS[a] = \{ \MIDATA~b^{n\cdot64\,\F{Ki}}, \MIMAX~m^? \} }{ - S \vdashexternval \EVMEM~a : \ETMEM~\{\LMIN~n, \LMAX~m^?\} + S \vdashexternval \EVMEM~a : \ETMEM~S.\SMEMS[a].\MITYPE } @@ -77,15 +74,14 @@ The following auxiliary typing rules specify this typing relation relative to a :math:`\EVGLOBAL~a` ................... -* The store entry :math:`S.\SGLOBALS[a]` must be a :ref:`global instance ` :math:`\{\GIVALUE~(t.\CONST~c), \GIMUT~\mut\}`. +* The store entry :math:`S.\SGLOBALS[a]` must exist. -* Then :math:`\EVGLOBAL~a` is valid with :ref:`external type ` :math:`\ETGLOBAL~(\mut~t)`. +* Then :math:`\EVGLOBAL~a` is valid with :ref:`external type ` :math:`\ETGLOBAL~S.\SGLOBALS[a].\GITYPE`. .. math:: \frac{ - S.\SGLOBALS[a] = \{ \GIVALUE~(t.\CONST~c), \GIMUT~\mut \} }{ - S \vdashexternval \EVGLOBAL~a : \ETGLOBAL~(\mut~t) + S \vdashexternval \EVGLOBAL~a : \ETGLOBAL~S.\SGLOBALS[a].\GITYPE } @@ -99,6 +95,8 @@ For the purpose of checking argument :ref:`values ` against th values are classified by :ref:`value types `. The following auxiliary typing rules specify this typing relation relative to a :ref:`store ` :math:`S` in which possibly referenced addresses live. +.. _valid-num: + :ref:`Numeric Values ` :math:`t.\CONST~c` ..................................................... @@ -110,6 +108,7 @@ The following auxiliary typing rules specify this typing relation relative to a S \vdashval t.\CONST~c : t } +.. _valid-ref: :ref:`Null References ` :math:`\REFNULL` .................................................... @@ -359,13 +358,13 @@ New instances of :ref:`functions `, :ref:`tables ` ................................ -1. Let :math:`\tabletype` be the :ref:`table type ` to allocate and :math:`\val` the initialization value. +1. Let :math:`\tabletype` be the :ref:`table type ` to allocate and :math:`\reff` the initialization value. 2. Let :math:`(\{\LMIN~n, \LMAX~m^?\}~\reftype)` be the structure of :ref:`table type ` :math:`\tabletype`. 3. Let :math:`a` be the first free :ref:`table address ` in :math:`S`. -4. Let :math:`\tableinst` be the :ref:`table instance ` :math:`\{ \TIELEM~\REFNULL^n, \TIMAX~m^? \}` with :math:`n` empty elements. +4. Let :math:`\tableinst` be the :ref:`table instance ` :math:`\{ \TITYPE~\tabletype, \TIELEM~\reff^n \}` with :math:`n` elements set to :math:`\reff`. 5. Append :math:`\tableinst` to the |STABLES| of :math:`S`. @@ -373,11 +372,11 @@ New instances of :ref:`functions `, :ref:`tables `, :ref:`tables ` in :math:`S`. -4. Let :math:`\meminst` be the :ref:`memory instance ` :math:`\{ \MIDATA~(\hex{00})^{n \cdot 64\,\F{Ki}}, \MIMAX~m^? \}` that contains :math:`n` pages of zeroed :ref:`bytes `. +4. Let :math:`\meminst` be the :ref:`memory instance ` :math:`\{ \MITYPE~\memtype, \MIDATA~(\hex{00})^{n \cdot 64\,\F{Ki}} \}` that contains :math:`n` pages of zeroed :ref:`bytes `. 5. Append :math:`\meminst` to the |SMEMS| of :math:`S`. @@ -406,7 +405,7 @@ New instances of :ref:`functions `, :ref:`tables `, :ref:`tables ` to allocate and :math:`\val` the :ref:`value ` to initialize the global with. -2. Let :math:`\mut~t` be the structure of :ref:`global type ` :math:`\globaltype`. - -3. Let :math:`a` be the first free :ref:`global address ` in :math:`S`. +2. Let :math:`a` be the first free :ref:`global address ` in :math:`S`. -4. Let :math:`\globalinst` be the :ref:`global instance ` :math:`\{ \GIVALUE~\val, \GIMUT~\mut \}`. +3. Let :math:`\globalinst` be the :ref:`global instance ` :math:`\{ \GITYPE~\globaltype, \GIVALUE~\val \}`. -5. Append :math:`\globalinst` to the |SGLOBALS| of :math:`S`. +4. Append :math:`\globalinst` to the |SGLOBALS| of :math:`S`. -6. Return :math:`a`. +5. Return :math:`a`. .. math:: \begin{array}{rlll} \allocglobal(S, \globaltype, \val) &=& S', \globaladdr \\[1ex] \mbox{where:} \hfill \\ - \globaltype &=& \mut~t \\ \globaladdr &=& |S.\SGLOBALS| \\ - \globalinst &=& \{ \GIVALUE~\val, \GIMUT~\mut \} \\ + \globalinst &=& \{ \GITYPE~\globaltype, \GIVALUE~\val \} \\ S' &=& S \compose \{\SGLOBALS~\globalinst\} \\ \end{array} @@ -446,24 +442,32 @@ New instances of :ref:`functions `, :ref:`tables ` ........................................ -1. Let :math:`\tableinst` be the :ref:`table instance ` to grow, :math:`n` the number of elements by which to grow it, and :math:`\val` the initialization value. +1. Let :math:`\tableinst` be the :ref:`table instance ` to grow, :math:`n` the number of elements by which to grow it, and :math:`\reff` the initialization value. 2. Let :math:`\X{len}` be :math:`n` added to the length of :math:`\tableinst.\TIELEM`. 3. If :math:`\X{len}` is larger than :math:`2^{32}`, then fail. -4. If :math:`\tableinst.\TIMAX` is not empty and smaller than :math:`\X{len}`, then fail. +4. Let :math:`\limits~t` be the structure of :ref:`table type ` :math:`\tableinst.\TITYPE`. + +5. Let :math:`\limits'` be :math:`\limits` with :math:`\LMIN` updated to :math:`\X{len}`. -5. Append :math:`\REFNULL^n` to :math:`\tableinst.\TIELEM`. +6. If :math:`\limits'` is not :ref:`valid `, then fail. + +7. Append :math:`\reff^n` to :math:`\tableinst.\TIELEM`. + +8. Set :math:`\tableinst.\TITYPE` to the :ref:`table type ` :math:`\limits'~t`. .. math:: \begin{array}{rllll} - \growtable(\tableinst, n, \val) &=& \tableinst \with \TIELEM = \tableinst.\TIELEM~\val^n \\ + \growtable(\tableinst, n, \reff) &=& \tableinst \with \TITYPE = \limits'~t \with \TIELEM = \tableinst.\TIELEM~\reff^n \\ && ( \begin{array}[t]{@{}r@{~}l@{}} \iff & \X{len} = n + |\tableinst.\TIELEM| \\ \wedge & \X{len} \leq 2^{32} \\ - \wedge & (\tableinst.\TIMAX = \epsilon \vee \X{len} \leq \tableinst.\TIMAX)) \\ + \wedge & \limits~t = \tableinst.\TITYPE \\ + \wedge & \limits' = \limits \with \LMIN = \X{len} \\ + \wedge & \vdashlimits \limits' \ok \\ \end{array} \\ \end{array} @@ -482,18 +486,26 @@ Growing :ref:`memories ` 4. If :math:`\X{len}` is larger than :math:`2^{16}`, then fail. -5. If :math:`\meminst.\MIMAX` is not empty and its value is smaller than :math:`\X{len}`, then fail. +5. Let :math:`\limits` be the structure of :ref:`memory type ` :math:`\meminst.\MITYPE`. + +6. Let :math:`\limits'` be :math:`\limits` with :math:`\LMIN` updated to :math:`\X{len}`. + +7. If :math:`\limits'` is not :ref:`valid `, then fail. + +8. Append :math:`n` times :math:`64\,\F{Ki}` :ref:`bytes ` with value :math:`\hex{00}` to :math:`\meminst.\MIDATA`. -6. Append :math:`n` times :math:`64\,\F{Ki}` :ref:`bytes ` with value :math:`\hex{00}` to :math:`\meminst.\MIDATA`. +9. Set :math:`\meminst.\MITYPE` to the :ref:`memory type ` :math:`\limits'`. .. math:: \begin{array}{rllll} - \growmem(\meminst, n) &=& \meminst \with \MIDATA = \meminst.\MIDATA~(\hex{00})^{n \cdot 64\,\F{Ki}} \\ + \growmem(\meminst, n) &=& \meminst \with \MITYPE = \limits' \with \MIDATA = \meminst.\MIDATA~(\hex{00})^{n \cdot 64\,\F{Ki}} \\ && ( \begin{array}[t]{@{}r@{~}l@{}} \iff & \X{len} = n + |\meminst.\MIDATA| / 64\,\F{Ki} \\ \wedge & \X{len} \leq 2^{16} \\ - \wedge & (\meminst.\MIMAX = \epsilon \vee \X{len} \leq \meminst.\MIMAX)) \\ + \wedge & \limits = \meminst.\MITYPE \\ + \wedge & \limits' = \limits \with \LMIN = \X{len} \\ + \wedge & \vdashlimits \limits' \ok \\ \end{array} \\ \end{array} diff --git a/document/core/exec/runtime.rst b/document/core/exec/runtime.rst index e4febcbac4..b336ca704d 100644 --- a/document/core/exec/runtime.rst +++ b/document/core/exec/runtime.rst @@ -249,18 +249,18 @@ Table Instances ~~~~~~~~~~~~~~~ A *table instance* is the runtime representation of a :ref:`table `. -It holds a vector of *function elements* and an optional maximum size, if one was specified in the :ref:`table type ` at the table's definition site. - -Each table element is a :ref:`reference value `. -Table elements can be mutated through :ref:`table instructions `, the execution of an :ref:`element segment `, or by external means provided by the :ref:`embedder `. +It records its :ref:`type ` and holds a vector of :ref:`reference values `. .. math:: \begin{array}{llll} \production{(table instance)} & \tableinst &::=& - \{ \TIELEM~\vec(\reff), \TIMAX~\u32^? \} \\ + \{ \TITYPE~\tabletype, \TIELEM~\vec(\reff) \} \\ \end{array} -It is an invariant of the semantics that the length of the element vector never exceeds the maximum size, if present. +Table elements can be mutated through :ref:`table instructions `, the execution of an active :ref:`element segment `, or by external means provided by the :ref:`embedder `. + +It is an invariant of the semantics that all table elements have a type :ref:`matching ` the element type of :math:`\tabletype`. +It also is an invariant that the length of the element vector never exceeds the maximum size of :math:`\tabletype`, if present. .. index:: ! memory instance, memory, byte, ! page size, memory type, embedder, data segment, instruction @@ -273,20 +273,19 @@ Memory Instances ~~~~~~~~~~~~~~~~ A *memory instance* is the runtime representation of a linear :ref:`memory `. -It holds a vector of :ref:`bytes ` and an optional maximum size, if one was specified at the definition site of the memory. +It records its :ref:`type ` and holds a vector of :ref:`bytes `. .. math:: \begin{array}{llll} \production{(memory instance)} & \meminst &::=& - \{ \MIDATA~\vec(\byte), \MIMAX~\u32^? \} \\ + \{ \MITYPE~\memtype, \MIDATA~\vec(\byte) \} \\ \end{array} The length of the vector always is a multiple of the WebAssembly *page size*, which is defined to be the constant :math:`65536` -- abbreviated :math:`64\,\F{Ki}`. -Like in a :ref:`memory type `, the maximum size in a memory instance is given in units of this page size. -The bytes can be mutated through :ref:`memory instructions `, the execution of a :ref:`data segment `, or by external means provided by the :ref:`embedder `. +The bytes can be mutated through :ref:`memory instructions `, the execution of an active :ref:`data segment `, or by external means provided by the :ref:`embedder `. -It is an invariant of the semantics that the length of the byte vector, divided by page size, never exceeds the maximum size, if present. +It is an invariant of the semantics that the length of the byte vector, divided by page size, never exceeds the maximum size of :math:`\memtype`, if present. .. index:: ! global instance, global, value, mutability, instruction, embedder @@ -298,16 +297,18 @@ Global Instances ~~~~~~~~~~~~~~~~ A *global instance* is the runtime representation of a :ref:`global ` variable. -It holds an individual :ref:`value ` and a flag indicating whether it is mutable. +It records its :ref:`type ` and holds an individual :ref:`value `. .. math:: \begin{array}{llll} \production{(global instance)} & \globalinst &::=& - \{ \GIVALUE~\val, \GIMUT~\mut \} \\ + \{ \GITYPE~\valtype, \GIVALUE~\val \} \\ \end{array} The value of mutable globals can be mutated through :ref:`variable instructions ` or by external means provided by the :ref:`embedder `. +It is an invariant of the semantics that the value has a type :ref:`matching ` the :ref:`value type ` of :math:`\globaltype`. + .. index:: ! export instance, export, name, external value pair: abstract syntax; export instance diff --git a/document/core/util/macros.def b/document/core/util/macros.def index f332303e4e..d66f9a52d2 100644 --- a/document/core/util/macros.def +++ b/document/core/util/macros.def @@ -806,14 +806,14 @@ .. |FICODE| mathdef:: \xref{exec/runtime}{syntax-funcinst}{\K{code}} .. |FIHOSTCODE| mathdef:: \xref{exec/runtime}{syntax-funcinst}{\K{hostcode}} +.. |TITYPE| mathdef:: \xref{exec/runtime}{syntax-tableinst}{\K{type}} .. |TIELEM| mathdef:: \xref{exec/runtime}{syntax-tableinst}{\K{elem}} -.. |TIMAX| mathdef:: \xref{exec/runtime}{syntax-tableinst}{\K{max}} +.. |MITYPE| mathdef:: \xref{exec/runtime}{syntax-meminst}{\K{type}} .. |MIDATA| mathdef:: \xref{exec/runtime}{syntax-meminst}{\K{data}} -.. |MIMAX| mathdef:: \xref{exec/runtime}{syntax-meminst}{\K{max}} +.. |GITYPE| mathdef:: \xref{exec/runtime}{syntax-globalinst}{\K{type}} .. |GIVALUE| mathdef:: \xref{exec/runtime}{syntax-globalinst}{\K{value}} -.. |GIMUT| mathdef:: \xref{exec/runtime}{syntax-globalinst}{\K{mut}} .. |EINAME| mathdef:: \xref{exec/runtime}{syntax-exportinst}{\K{name}} .. |EIVALUE| mathdef:: \xref{exec/runtime}{syntax-exportinst}{\K{value}} From 1fec5c1e92a2ee9599f9be489c130c3526fe37b6 Mon Sep 17 00:00:00 2001 From: Andreas Rossberg Date: Thu, 25 Apr 2019 15:36:40 +0200 Subject: [PATCH 087/199] Update host bindings proposal links --- proposals/reference-types/Overview.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/proposals/reference-types/Overview.md b/proposals/reference-types/Overview.md index 44b94ae603..21a37a6208 100644 --- a/proposals/reference-types/Overview.md +++ b/proposals/reference-types/Overview.md @@ -6,8 +6,8 @@ TODO: more text, motivation, explanation Motivation: -* Easier and more efficient interop with host environment (see the [host bindings proposal](https://github.com/WebAssembly/host-bindings/blob/master/proposals/host-bindings/Overview.md)) - - allow host references to be represented directly by type `anyref` (see [here](https://github.com/WebAssembly/host-bindings/issues/9)) +* Easier and more efficient interop with host environment (see e.g. the [WebIDL bindings proposal](https://github.com/WebAssembly/webidl-bindings/blob/master/proposals/webidl-bindings/Overview.md)) + - allow host references to be represented directly by type `anyref` (see [here](https://github.com/WebAssembly/webidl-bindings/issues/9)) - without having to go through tables, allocating slots, and maintaining index bijections at the boundaries * Basic manipulation of tables inside Wasm @@ -19,7 +19,7 @@ by repurposing tables as a general memory for opaque data types * Set the stage for later additions: - Typed function references (see [below](#typed-function-references)) - - Exception references (see the [exception handling proposal](https://github.com/WebAssembly/exception-handling/blob/master/proposals/Level-1.md) and [here](https://github.com/WebAssembly/host-bindings/issues/10)) + - Exception references (see the [exception handling proposal](https://github.com/WebAssembly/exception-handling/blob/master/proposals/Level-1.md) and [here](https://github.com/WebAssembly/webidl-bindings/issues/10)) - A smoother transition path to GC (see the [GC proposal](https://github.com/WebAssembly/gc/blob/master/proposals/gc/Overview.md)) Get the most important parts soon! From b8f64783aac69c83cc67b5e9e8b92e6f4105fb3b Mon Sep 17 00:00:00 2001 From: Andreas Rossberg Date: Thu, 25 Apr 2019 15:39:15 +0200 Subject: [PATCH 088/199] Fix links 2 --- proposals/reference-types/Overview.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/proposals/reference-types/Overview.md b/proposals/reference-types/Overview.md index 21a37a6208..54acc0fc35 100644 --- a/proposals/reference-types/Overview.md +++ b/proposals/reference-types/Overview.md @@ -6,7 +6,7 @@ TODO: more text, motivation, explanation Motivation: -* Easier and more efficient interop with host environment (see e.g. the [WebIDL bindings proposal](https://github.com/WebAssembly/webidl-bindings/blob/master/proposals/webidl-bindings/Overview.md)) +* Easier and more efficient interop with host environment (see e.g. the [WebIDL bindings proposal](https://github.com/WebAssembly/webidl-bindings/blob/master/proposals/webidl-bindings/Explainer.md)) - allow host references to be represented directly by type `anyref` (see [here](https://github.com/WebAssembly/webidl-bindings/issues/9)) - without having to go through tables, allocating slots, and maintaining index bijections at the boundaries From d6cd9976ca25b058faf02603f5eef40a39f5ccd2 Mon Sep 17 00:00:00 2001 From: Andreas Rossberg Date: Tue, 30 Apr 2019 19:58:58 +0200 Subject: [PATCH 089/199] [interpreter] Forgot commit --- interpreter/runtime/global.ml | 20 ++++++++++++-------- interpreter/runtime/memory.ml | 23 ++++++++++++++--------- interpreter/runtime/memory.mli | 2 +- interpreter/runtime/table.ml | 28 ++++++++++++++++------------ interpreter/runtime/table.mli | 2 +- interpreter/syntax/ast.ml | 3 +-- test/core/linking.wast | 25 +++++++++++++++++++++++++ 7 files changed, 70 insertions(+), 33 deletions(-) diff --git a/interpreter/runtime/global.ml b/interpreter/runtime/global.ml index 828da61d44..c83d352613 100644 --- a/interpreter/runtime/global.ml +++ b/interpreter/runtime/global.ml @@ -1,20 +1,24 @@ open Types open Values -type global = {mutable content : value; ty : value_type; mut : mutability} +type global = {ty : global_type; mutable content : value} type t = global exception Type exception NotMutable -let alloc (GlobalType (ty, mut)) v = - if not (match_value_type (type_of_value v) ty) then raise Type; - {content = v; ty; mut} +let alloc (GlobalType (t, mut) as gt) v = + if not (match_value_type (type_of_value v) t) then raise Type; + {ty = gt; content = v} -let type_of glob = GlobalType (glob.ty, glob.mut) +let type_of glob = + glob.ty + +let load glob = + glob.content -let load glob = glob.content let store glob v = - if glob.mut <> Mutable then raise NotMutable; - if not (match_value_type (type_of_value v) glob.ty) then raise Type; + let GlobalType (t, mut) = glob.ty in + if mut <> Mutable then raise NotMutable; + if not (match_value_type (type_of_value v) t) then raise Type; glob.content <- v diff --git a/interpreter/runtime/memory.ml b/interpreter/runtime/memory.ml index e4db937d7d..e122544fb6 100644 --- a/interpreter/runtime/memory.ml +++ b/interpreter/runtime/memory.ml @@ -11,7 +11,7 @@ type pack_size = Pack8 | Pack16 | Pack32 type extension = SX | ZX type memory' = (int, int8_unsigned_elt, c_layout) Array1.t -type memory = {mutable content : memory'; max : size option} +type memory = {mutable ty : memory_type; mutable content : memory'} type t = memory exception Type @@ -27,9 +27,10 @@ let packed_size = function | Pack16 -> 2 | Pack32 -> 4 -let within_limits n = function +let valid_limits {min; max} = + match max with | None -> true - | Some max -> I32.le_u n max + | Some m -> I32.le_u min m let create n = if I32.gt_u n 0x10000l then raise SizeOverflow else @@ -40,9 +41,9 @@ let create n = mem with Out_of_memory -> raise OutOfMemory -let alloc (MemoryType {min; max}) = - assert (within_limits min max); - {content = create min; max} +let alloc (MemoryType lim as mt) = + if not (valid_limits lim) then raise Type; + {ty = mt; content = create lim.min} let bound mem = Array1_64.dim mem.content @@ -51,16 +52,20 @@ let size mem = Int64.(to_int32 (div (bound mem) page_size)) let type_of mem = - MemoryType {min = size mem; max = mem.max} + mem.ty let grow mem delta = - let old_size = size mem in + let MemoryType lim = mem.ty in + assert (lim.min = size mem); + let old_size = lim.min in let new_size = Int32.add old_size delta in if I32.gt_u old_size new_size then raise SizeOverflow else - if not (within_limits new_size mem.max) then raise SizeLimit else + let lim' = {lim with min = new_size} in + if not (valid_limits lim') then raise SizeLimit else let after = create new_size in let dim = Array1_64.dim mem.content in Array1.blit (Array1_64.sub mem.content 0L dim) (Array1_64.sub after 0L dim); + mem.ty <- MemoryType lim'; mem.content <- after let load_byte mem a = diff --git a/interpreter/runtime/memory.mli b/interpreter/runtime/memory.mli index 67b4e6da26..6fe9d32f43 100644 --- a/interpreter/runtime/memory.mli +++ b/interpreter/runtime/memory.mli @@ -20,7 +20,7 @@ exception OutOfMemory val page_size : int64 val packed_size : pack_size -> int -val alloc : memory_type -> memory (* raises SizeOverflow, OutOfMemory *) +val alloc : memory_type -> memory (* raises Type, SizeOverflow, OutOfMemory *) val type_of : memory -> memory_type val size : memory -> size val bound : memory -> address diff --git a/interpreter/runtime/table.ml b/interpreter/runtime/table.ml index 9a5c173eab..a57ddc7025 100644 --- a/interpreter/runtime/table.ml +++ b/interpreter/runtime/table.ml @@ -4,9 +4,7 @@ open Values type size = int32 type index = int32 -type table' = ref_ array -type table = - {mutable content : table'; max : size option; elem_type : ref_type} +type table = {mutable ty : table_type; mutable content : ref_ array} type t = table exception Type @@ -15,38 +13,44 @@ exception SizeOverflow exception SizeLimit exception OutOfMemory -let within_limits size = function +let valid_limits {min; max} = + match max with | None -> true - | Some max -> I32.le_u size max + | Some m -> I32.le_u min m let create size r = try Lib.Array32.make size r with Out_of_memory | Invalid_argument _ -> raise OutOfMemory -let alloc (TableType ({min; max}, elem_type)) r = - assert (within_limits min max); - {content = create min r; max; elem_type} +let alloc (TableType (lim, _) as tt) r = + if not (valid_limits lim) then raise Type; + {ty = tt; content = create lim.min r} let size tab = Lib.Array32.length tab.content let type_of tab = - TableType ({min = size tab; max = tab.max}, tab.elem_type) + tab.ty let grow tab delta r = - let old_size = size tab in + let TableType (lim, t) = tab.ty in + assert (lim.min = size tab); + let old_size = lim.min in let new_size = Int32.add old_size delta in if I32.gt_u old_size new_size then raise SizeOverflow else - if not (within_limits new_size tab.max) then raise SizeLimit else + let lim' = {lim with min = new_size} in + if not (valid_limits lim') then raise SizeLimit else let after = create new_size r in Array.blit tab.content 0 after 0 (Array.length tab.content); + tab.ty <- TableType (lim', t); tab.content <- after let load tab i = try Lib.Array32.get tab.content i with Invalid_argument _ -> raise Bounds let store tab i r = - if not (match_ref_type (type_of_ref r) tab.elem_type) then raise Type; + let TableType (lim, t) = tab.ty in + if not (match_ref_type (type_of_ref r) t) then raise Type; try Lib.Array32.set tab.content i r with Invalid_argument _ -> raise Bounds let blit tab offset rs = diff --git a/interpreter/runtime/table.mli b/interpreter/runtime/table.mli index b07b398012..b452afcbcb 100644 --- a/interpreter/runtime/table.mli +++ b/interpreter/runtime/table.mli @@ -13,7 +13,7 @@ exception SizeOverflow exception SizeLimit exception OutOfMemory -val alloc : table_type -> ref_ -> table (* raises OutOfMemory *) +val alloc : table_type -> ref_ -> table (* raises Type, OutOfMemory *) val type_of : table -> table_type val size : table -> size val grow : table -> size -> ref_ -> unit diff --git a/interpreter/syntax/ast.ml b/interpreter/syntax/ast.ml index 0f57ba31f0..93fed9ea62 100644 --- a/interpreter/syntax/ast.ml +++ b/interpreter/syntax/ast.ml @@ -55,8 +55,7 @@ type testop = (I32Op.testop, I64Op.testop, F32Op.testop, F64Op.testop) Values.op type relop = (I32Op.relop, I64Op.relop, F32Op.relop, F64Op.relop) Values.op type cvtop = (I32Op.cvtop, I64Op.cvtop, F32Op.cvtop, F64Op.cvtop) Values.op -type 'a memop = - {ty : num_type; align : int; offset : Memory.offset; sz : 'a option} +type 'a memop = {ty : num_type; align : int; offset : int32; sz : 'a option} type loadop = (Memory.pack_size * Memory.extension) memop type storeop = Memory.pack_size memop diff --git a/test/core/linking.wast b/test/core/linking.wast index b5d4b6064e..9f8f9bd70d 100644 --- a/test/core/linking.wast +++ b/test/core/linking.wast @@ -109,6 +109,18 @@ ) +(module $Mglobal-ex + (func $f) + (global (export "g") anyref (ref.func $f)) +) +(register "Mglobal-ex" $Mglobal-ex) + +(assert_unlinkable + (module (global (import "Mglobal-ex" "g") funcref)) + "incompatible import type" +) + + ;; Tables (module $Mt @@ -265,6 +277,19 @@ (assert_trap (invoke $Mt "call" (i32.const 7)) "uninitialized") +(module $Mtable-ex + (func $f) + (table $t (export "t") 1 anyref) + (elem (i32.const 0) $f) +) +(register "Mtable-ex" $Mtable-ex) + +(assert_unlinkable + (module (table (import "Mtable-ex" "t") 1 funcref)) + "incompatible import type" +) + + ;; Memories (module $Mm From 16b65a2c9a4f298fee47e3617a104a30e546a6eb Mon Sep 17 00:00:00 2001 From: Andreas Rossberg Date: Tue, 30 Apr 2019 20:01:30 +0200 Subject: [PATCH 090/199] [interpreter] Eps --- interpreter/runtime/global.ml | 4 ++-- interpreter/runtime/memory.ml | 4 ++-- interpreter/runtime/table.ml | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/interpreter/runtime/global.ml b/interpreter/runtime/global.ml index c83d352613..181399e0a1 100644 --- a/interpreter/runtime/global.ml +++ b/interpreter/runtime/global.ml @@ -7,9 +7,9 @@ type t = global exception Type exception NotMutable -let alloc (GlobalType (t, mut) as gt) v = +let alloc (GlobalType (t, _) as ty) v = if not (match_value_type (type_of_value v) t) then raise Type; - {ty = gt; content = v} + {ty; content = v} let type_of glob = glob.ty diff --git a/interpreter/runtime/memory.ml b/interpreter/runtime/memory.ml index e122544fb6..c72ef0c3ac 100644 --- a/interpreter/runtime/memory.ml +++ b/interpreter/runtime/memory.ml @@ -41,9 +41,9 @@ let create n = mem with Out_of_memory -> raise OutOfMemory -let alloc (MemoryType lim as mt) = +let alloc (MemoryType lim as ty) = if not (valid_limits lim) then raise Type; - {ty = mt; content = create lim.min} + {ty; content = create lim.min} let bound mem = Array1_64.dim mem.content diff --git a/interpreter/runtime/table.ml b/interpreter/runtime/table.ml index a57ddc7025..db7dacee67 100644 --- a/interpreter/runtime/table.ml +++ b/interpreter/runtime/table.ml @@ -22,9 +22,9 @@ let create size r = try Lib.Array32.make size r with Out_of_memory | Invalid_argument _ -> raise OutOfMemory -let alloc (TableType (lim, _) as tt) r = +let alloc (TableType (lim, _) as ty) r = if not (valid_limits lim) then raise Type; - {ty = tt; content = create lim.min r} + {ty; content = create lim.min r} let size tab = Lib.Array32.length tab.content From 29540aca3248d2a9158b0681aac53272117e1ab5 Mon Sep 17 00:00:00 2001 From: Andreas Rossberg Date: Sat, 11 May 2019 14:26:39 +0200 Subject: [PATCH 091/199] [spec/interpreter/test] Avoid lubs and glbs (#43) --- document/core/appendix/algorithm.rst | 148 ++++++------- document/core/appendix/index-instructions.rst | 2 +- document/core/binary/instructions.rst | 5 +- document/core/binary/types.rst | 6 + document/core/exec/instructions.rst | 11 +- document/core/syntax/instructions.rst | 6 +- document/core/syntax/types.rst | 11 +- document/core/text/instructions.rst | 2 +- document/core/util/macros.def | 2 + document/core/valid/instructions.rst | 30 ++- document/core/valid/types.rst | 9 + interpreter/binary/decode.ml | 5 +- interpreter/binary/encode.ml | 4 +- interpreter/exec/eval.ml | 4 +- interpreter/host/spectest.ml | 1 + interpreter/script/js.ml | 4 + interpreter/syntax/ast.ml | 2 +- interpreter/syntax/operators.ml | 2 +- interpreter/syntax/types.ml | 52 +---- interpreter/syntax/values.ml | 1 + interpreter/text/arrange.ml | 4 +- interpreter/text/parser.mly | 40 +++- interpreter/valid/valid.ml | 83 +++---- test/core/br_table.wast | 53 ++++- test/core/select.wast | 207 ++++++++++++------ test/core/unreached-invalid.wast | 14 -- 26 files changed, 424 insertions(+), 284 deletions(-) diff --git a/document/core/appendix/algorithm.rst b/document/core/appendix/algorithm.rst index 259b01071d..f13ddc3eec 100644 --- a/document/core/appendix/algorithm.rst +++ b/document/core/appendix/algorithm.rst @@ -22,48 +22,29 @@ Data Structures ~~~~~~~~~~~~~~~ Types are representable as an enumeration. -In addition to the plain types from the WebAssembly validation semantics, an extended notion of operand type includes a bottom type `Unknown` that is used as the type of :ref:`polymorphic ` operands. - A simple subtyping check can be defined on these types. -In addition, corresponding functions computing the join (least upper bound) and meet (greatest lower bound) of two types are used. -Because there is no top type, a join does not exist in all cases. -Similarly, a meet must always be defined on known value types that exclude the auxiliary bottom type `Unknown`, -hence a meet does not exist in all cases either. -A type error is encountered if a join or meet is required when it does not exist. .. code-block:: pseudo - type val_type = I32 | I64 | F32 | F64 | Anyref | Funcref | Nullref - type opd_type = val_type | Unknown + type val_type = I32 | I64 | F32 | F64 | Anyref | Funcref | Nullref | Bot + + func is_num(t : val_type) : bool = + return t = I32 || t = I64 || t = F32 || t = F64 || t = Bot - func is_ref(t : opd_type) : bool = - return t = Anyref || t = Funcref || t = Nullref + func is_ref(t : val_type) : bool = + return t = Anyref || t = Funcref || t = Nullref || t = Bot - func matches(t1 : opd_type, t2 : opd_type) : bool = - return t1 = t2 || t1 = Unknown || + func matches(t1 : val_type, t2 : val_type) : bool = + return t1 = t2 || t1 = Bot || (t1 = Nullref && is_ref(t2)) || (is_ref(t1) && t2 = Anyref) - func join(t1 : opd_type, t2 : opd_type) : opd_type = - if (t1 = t2) return t1 - if (matches(t1, t2)) return t2 - if (matches(t2, t1)) return t1 - error_if(not (is_ref(t1) && is_ref(t2))) - return Anyref - - func meet(t1 : val_type, t2 : val_type) : val_type = - if (t1 = t2) return t1 - if (matches(t1, t2)) return t1 - if (matches(t2, t1)) return t2 - error_if(not (is_ref(t1) && is_ref(t2))) - return Nullref - -The algorithm uses two separate stacks: the *operand stack* and the *control stack*. +The algorithm uses two separate stacks: the *value stack* and the *control stack*. The former tracks the :ref:`types ` of operand values on the :ref:`stack `, the latter surrounding :ref:`structured control instructions ` and their associated :ref:`blocks `. .. code-block:: pseudo - type opd_stack = stack(opd_type) + type val_stack = stack(val_type) type ctrl_stack = stack(ctrl_frame) type ctrl_frame = { @@ -73,7 +54,7 @@ the latter surrounding :ref:`structured control instructions `, or :code:`Unknown` when the type is not known. +For each value, the value stack records its :ref:`value type `. For each entered block, the control stack records a *control frame* with the type of the associated :ref:`label ` (used to type-check branches), the result type of the block (used to check its result), the height of the operand stack at the start of the block (used to check that operands do not underflow the current block), and a flag recording whether the remainder of the block is unreachable (used to handle :ref:`stack-polymorphic ` typing after branches). @@ -85,43 +66,48 @@ For the purpose of presenting the algorithm, the operand and control stacks are .. code-block:: pseudo - var opds : opd_stack + var vals : val_stack var ctrls : ctrl_stack However, these variables are not manipulated directly by the main checking function, but through a set of auxiliary functions: .. code-block:: pseudo - func push_opd(type : opd_type) = - opds.push(type) + func push_val(type : val_type) = + vals.push(type) - func pop_opd() : opd_type = - if (opds.size() = ctrls[0].height && ctrls[0].unreachable) return Unknown - error_if(opds.size() = ctrls[0].height) - return opds.pop() + func pop_val() : val_type = + if (vals.size() = ctrls[0].height && ctrls[0].unreachable) return Bot + error_if(vals.size() = ctrls[0].height) + return vals.pop() - func pop_opd(expect : val_type) = - let actual = pop_opd() + func pop_val(expect : val_type) : val_type = + let actual = pop_val() error_if(not matches(actual, expect)) + return actual - func push_opds(types : list(val_type)) = foreach (t in types) push_opd(t) - func pop_opds(types : list(val_type)) = foreach (t in reverse(types)) pop_opd(t) + func push_vals(types : list(val_type)) = foreach (t in types) push_val(t) + func pop_vals(types : list(val_type)) : list(val_type) = + var popped := [] + foreach (t in reverse(types)) popped.append(pop_val(t)) + return popped -Pushing an operand simply pushes the respective type to the operand stack. +Pushing an operand value simply pushes the respective type to the value stack. -Popping an operand checks that the operand stack does not underflow the current block and then removes one type. -But first, a special case is handled where the block contains no known operands, but has been marked as unreachable. +Popping an operand value checks that the value stack does not underflow the current block and then removes one type. +But first, a special case is handled where the block contains no known values, but has been marked as unreachable. That can occur after an unconditional branch, when the stack is typed :ref:`polymorphically `. -In that case, an unknown type is returned. +In that case, the :code:`Bot` type is returned, because that is a *principal* choice trivially satisfying all use constraints. -A second function for popping an operand takes an expected (known) type, which the actual operand type is checked against. -The types may differ by subtyping, inlcuding the case where the actual type is unknown. +A second function for popping an operand value takes an expected type, which the actual operand type is checked against. +The types may differ by subtyping, including the case where the actual type is :code:`Bot`, and thereby matches unconditionally. +The function returns the actual type popped from the stack. Finally, there are accumulative functions for pushing or popping multiple operand types. .. note:: The notation :code:`stack[i]` is meant to index the stack from the top, - so that :code:`ctrls[0]` accesses the element pushed last. + so that, e.g., :code:`ctrls[0]` accesses the element pushed last. The control stack is likewise manipulated through auxiliary functions: @@ -129,19 +115,19 @@ The control stack is likewise manipulated through auxiliary functions: .. code-block:: pseudo func push_ctrl(label : list(val_type), out : list(val_type)) = -  let frame = ctrl_frame(label, out, opds.size(), false) +  let frame = ctrl_frame(label, out, vals.size(), false)   ctrls.push(frame) func pop_ctrl() : list(val_type) =  error_if(ctrls.is_empty())  let frame = ctrls[0] -   pop_opds(frame.end_types) -   error_if(opds.size() =/= frame.height) +   pop_vals(frame.end_types) +   error_if(vals.size() =/= frame.height) ctrls.pop()   return frame.end_types func unreachable() = -   opds.resize(ctrls[0].height) +   vals.resize(ctrls[0].height)   ctrls[0].unreachable := true Pushing a control frame takes the types of the label and result values. @@ -152,18 +138,18 @@ It then verifies that the operand stack contains the right types of values expec Afterwards, it checks that the stack has shrunk back to its initial height. Finally, the current frame can be marked as unreachable. -In that case, all existing operand types are purged from the operand stack, in order to allow for the :ref:`stack-polymorphism ` logic in :code:`pop_opd` to take effect. +In that case, all existing operand types are purged from the value stack, in order to allow for the :ref:`stack-polymorphism ` logic in :code:`pop_val` to take effect. .. note:: Even with the unreachable flag set, consecutive operands are still pushed to and popped from the operand stack. That is necessary to detect invalid :ref:`examples ` like :math:`(\UNREACHABLE~(\I32.\CONST)~\I64.\ADD)`. - However, a polymorphic stack cannot underflow, but instead generates :code:`Unknown` types as needed. + However, a polymorphic stack cannot underflow, but instead generates :code:`Bot` types as needed. .. index:: opcode -Validation of Opcode Sequences -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +Validation of Instruction Sequences +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ The following function shows the validation of a number of representative instructions that manipulate the stack. Other instructions are checked in a similar manner. @@ -177,18 +163,26 @@ Other instructions are checked in a similar manner. func validate(opcode) = switch (opcode) case (i32.add) - pop_opd(I32) - pop_opd(I32) - push_opd(I32) + pop_val(I32) + pop_val(I32) + push_val(I32) case (drop) - pop_opd() + pop_val() case (select) - pop_opd(I32) - let t1 = pop_opd() - let t2 = pop_opd() - push_opd(join(t1, t2)) + pop_val(I32) + let t1 = pop_val() + let t2 = pop_val() + error_if(not (is_num(t1) && is_num(t2))) + error_if(t1 =/= t2 && t1 =/= Bot && t2 =/= Bot) + push_val(if (t1 = Bot) t2 else t1) + + case (select t) + pop_val(I32) + pop_val(t) + pop_val(t) + push_val(t)    case (unreachable)       unreachable() @@ -200,12 +194,12 @@ Other instructions are checked in a similar manner. push_ctrl([], [t*]) case (if t*) - pop_opd(I32) + pop_val(I32) push_ctrl([t*], [t*]) case (end) let results = pop_ctrl() - push_opds(results) + push_vals(results) case (else) let results = pop_ctrl() @@ -213,26 +207,22 @@ Other instructions are checked in a similar manner. case (br n)      error_if(ctrls.size() < n) -       pop_opds(ctrls[n].label_types) +       pop_vals(ctrls[n].label_types)       unreachable() case (br_if n)      error_if(ctrls.size() < n) - pop_opd(I32) -       pop_opds(ctrls[n].label_types) -       push_opds(ctrls[n].label_types) + pop_val(I32) +       pop_vals(ctrls[n].label_types) +       push_vals(ctrls[n].label_types)    case (br_table n* m) + pop_val(I32)       error_if(ctrls.size() < m) - var ts = ctrls[m].label_types + let arity = ctrls[m].label_types.size()       foreach (n in n*)         error_if(ctrls.size() < n) - ts := meet(ts, ctrls[n].label_types) - pop_opd(I32) -       pop_opds(ts) +         error_if(ctrls[n].label_types.size() =/= arity) + push_vals(pop_vals(ctrls[n].label_types)) + pop_vals(ctrls[m].label_types)       unreachable() - -.. note:: - It is an invariant under the current WebAssembly instruction set that an operand of :code:`Unknown` type is never duplicated on the stack. - This would change if the language were extended with stack operators like :code:`dup`. - Under such an extension, the above algorithm would need to be refined by replacing the :code:`Unknown` type with proper *type variables* to ensure that all uses are consistent. diff --git a/document/core/appendix/index-instructions.rst b/document/core/appendix/index-instructions.rst index 29ee73d615..394a98e504 100644 --- a/document/core/appendix/index-instructions.rst +++ b/document/core/appendix/index-instructions.rst @@ -35,7 +35,7 @@ Instruction Binary Opcode Type (reserved) :math:`\hex{19}` :math:`\DROP` :math:`\hex{1A}` :math:`[t] \to []` :ref:`validation ` :ref:`execution ` :math:`\SELECT` :math:`\hex{1B}` :math:`[t~t~\I32] \to [t]` :ref:`validation ` :ref:`execution ` -(reserved) :math:`\hex{1C}` +:math:`\SELECT~t` :math:`\hex{1C}` :math:`[t~t~\I32] \to [t]` :ref:`validation ` :ref:`execution ` (reserved) :math:`\hex{1D}` (reserved) :math:`\hex{1E}` (reserved) :math:`\hex{1F}` diff --git a/document/core/binary/instructions.rst b/document/core/binary/instructions.rst index e1ad15ce04..27deed05f5 100644 --- a/document/core/binary/instructions.rst +++ b/document/core/binary/instructions.rst @@ -92,7 +92,7 @@ Reference Instructions Parametric Instructions ~~~~~~~~~~~~~~~~~~~~~~~ -:ref:`Parametric instructions ` are represented by single byte codes. +:ref:`Parametric instructions ` are represented by single byte codes, possibly followed by a type annotation. .. _binary-drop: .. _binary-select: @@ -101,7 +101,8 @@ Parametric Instructions \begin{array}{llclll} \production{instruction} & \Binstr &::=& \dots \\ &&|& \hex{1A} &\Rightarrow& \DROP \\ &&|& - \hex{1B} &\Rightarrow& \SELECT \\ + \hex{1B} &\Rightarrow& \SELECT \\ &&|& + \hex{1C}~~t^\ast{:}\Bvec(\Bvaltype) &\Rightarrow& \SELECT~t^\ast \\ \end{array} diff --git a/document/core/binary/types.rst b/document/core/binary/types.rst index 8e99de826d..541f45dbda 100644 --- a/document/core/binary/types.rst +++ b/document/core/binary/types.rst @@ -45,6 +45,9 @@ Reference Types \hex{6F} &\Rightarrow& \ANYREF \\ \end{array} +.. note:: + The type :math:`\NULLREF` cannot occur in a module. + .. index:: value type, number type, reference type pair: binary format; value type @@ -62,6 +65,9 @@ Value Types t{:}\Breftype &\Rightarrow& t \\ \end{array} +.. note:: + The type :math:`\BOT` cannot occur in a module. + .. index:: result type, value type pair: binary format; result type diff --git a/document/core/exec/instructions.rst b/document/core/exec/instructions.rst index 91452e8c2c..b1e9c1d0ce 100644 --- a/document/core/exec/instructions.rst +++ b/document/core/exec/instructions.rst @@ -264,8 +264,8 @@ Parametric Instructions .. _exec-select: -:math:`\SELECT` -............... +:math:`\SELECT~(t^\ast)^?` +.......................... 1. Assert: due to :ref:`validation `, a value of :ref:`value type ` |I32| is on the top of the stack. @@ -287,12 +287,15 @@ Parametric Instructions .. math:: \begin{array}{lcl@{\qquad}l} - \val_1~\val_2~(\I32\K{.}\CONST~c)~\SELECT &\stepto& \val_1 + \val_1~\val_2~(\I32\K{.}\CONST~c)~\SELECT~t^? &\stepto& \val_1 & (\iff c \neq 0) \\ - \val_1~\val_2~(\I32\K{.}\CONST~c)~\SELECT &\stepto& \val_2 + \val_1~\val_2~(\I32\K{.}\CONST~c)~\SELECT~t^? &\stepto& \val_2 & (\iff c = 0) \\ \end{array} +.. note:: + In future versions of WebAssembly, |SELECT| may allow more than one value per choice. + .. index:: variable instructions, local index, global index, address, global address, global instance, store, frame, value pair: execution; instruction diff --git a/document/core/syntax/instructions.rst b/document/core/syntax/instructions.rst index c4806d5c8e..7fe2a3af91 100644 --- a/document/core/syntax/instructions.rst +++ b/document/core/syntax/instructions.rst @@ -205,12 +205,16 @@ Instructions in this group can operate on operands of any :ref:`value type ` determining the type of these operands. If missing, the operands must be of :ref:`numeric type `. + +.. note:: + In future versions of WebAssembly, the type annotation on |SELECT| may allow for more than a single value being selected at the same time. .. index:: ! variable instruction, local, global, local index, global index diff --git a/document/core/syntax/types.rst b/document/core/syntax/types.rst index ee722c6e7d..522e479541 100644 --- a/document/core/syntax/types.rst +++ b/document/core/syntax/types.rst @@ -63,7 +63,7 @@ The type |FUNCREF| denotes the infinite union of all references to :ref:`functio The type |NULLREF| only contains a single value: the :ref:`null ` reference. It is a :ref:`subtype ` of all other reference types. -By virtue of not being representable in either the :ref:`binary format ` nor the :ref:`text format `, the |NULLREF| type cannot be used in a program; +By virtue of being representable in neither the :ref:`binary format ` nor the :ref:`text format `, the |NULLREF| type cannot be used in a program; it only occurs during :ref:`validation `. .. note:: @@ -73,7 +73,7 @@ Reference types are *opaque*, meaning that neither their size nor their bit patt Values of reference type can be stored in :ref:`tables `. -.. index:: ! value type, number type, reference type +.. index:: ! value type, number type, reference type, ! bottom type pair: abstract syntax; value type pair: value; type .. _syntax-valtype: @@ -82,11 +82,16 @@ Value Types ~~~~~~~~~~~ *Value types* classify the individual values that WebAssembly code can compute with and the values that a variable accepts. +They are either :ref:`number types `, :ref:`reference type `, or the unique *bottom type*, written :math:`\BOT`. + +The type :math:`\BOT` is a :ref:`subtype ` of all other types. +By virtue of being representable in neither the :ref:`binary format ` nor the :ref:`text format `, it cannot be used in a program; +it only occurs during :ref:`validation `. .. math:: \begin{array}{llll} \production{value type} & \valtype &::=& - \numtype ~|~ \reftype \\ + \numtype ~|~ \reftype ~|~ \BOT \\ \end{array} Conventions diff --git a/document/core/text/instructions.rst b/document/core/text/instructions.rst index e51fa8055e..d5901a87a9 100644 --- a/document/core/text/instructions.rst +++ b/document/core/text/instructions.rst @@ -163,7 +163,7 @@ Parametric Instructions \begin{array}{llclll} \production{instruction} & \Tplaininstr_I &::=& \dots \\ &&|& \text{drop} &\Rightarrow& \DROP \\ &&|& - \text{select} &\Rightarrow& \SELECT \\ + \text{select}~((t{:}\Tresult)^\ast)^? &\Rightarrow& \SELECT~(t^\ast)^? \\ \end{array} diff --git a/document/core/util/macros.def b/document/core/util/macros.def index d66f9a52d2..85cbef8616 100644 --- a/document/core/util/macros.def +++ b/document/core/util/macros.def @@ -164,6 +164,8 @@ .. |to| mathdef:: \xref{syntax/types}{syntax-functype}{\rightarrow} +.. |BOT| mathdef:: \xref{syntax/types}{syntax-valtype}{\K{bot}} + .. |I8| mathdef:: \xref{exec/runtime}{syntax-storagetype}{\K{i8}} .. |I16| mathdef:: \xref{exec/runtime}{syntax-storagetype}{\K{i16}} .. |I32| mathdef:: \xref{syntax/types}{syntax-valtype}{\K{i32}} diff --git a/document/core/valid/instructions.rst b/document/core/valid/instructions.rst index 16a432c1fc..cf38da6ad0 100644 --- a/document/core/valid/instructions.rst +++ b/document/core/valid/instructions.rst @@ -35,7 +35,7 @@ Two degrees of polymorphism can be distinguished: In both cases, the unconstrained types or type sequences can be chosen arbitrarily, as long as they meet the constraints imposed for the surrounding parts of the program. .. note:: - For example, the |SELECT| instruction is valid with type :math:`[t~t~\I32] \to [t]`, for any possible :ref:`value type ` :math:`t`. Consequently, both instruction sequences + For example, the |SELECT| instruction is valid with type :math:`[t~t~\I32] \to [t]`, for any possible :ref:`number type ` :math:`t`. Consequently, both instruction sequences .. math:: (\I32.\CONST~1)~~(\I32.\CONST~2)~~(\I32.\CONST~3)~~\SELECT{} @@ -61,6 +61,8 @@ In both cases, the unconstrained types or type sequences can be chosen arbitrari is invalid, because there is no possible type to pick for the |UNREACHABLE| instruction that would make the sequence well-typed. +The :ref:`Appendix ` describes a type checking :ref:`algorithm ` that efficiently implements validation of instruction sequences as prescribed by the rules given here. + .. index:: numeric instruction pair: validation; instruction @@ -227,22 +229,40 @@ Parametric Instructions C \vdashinstr \DROP : [t] \to [] } +.. note:: + Both |DROP| and |SELECT| without annotation are :ref:`value-polymorphic ` instructions. + + .. _valid-select: -:math:`\SELECT` -............... +:math:`\SELECT~(t^\ast)^?` +.......................... + +* If :math:`t^\ast` is present, then: + + * The length of :math:`t^\ast` must be :math:`1`. -* The instruction is valid with type :math:`[t~t~\I32] \to [t]`, for any :ref:`value type ` :math:`t`. + * Then the instruction is valid with type :math:`[t^\ast~t^\ast~\I32] \to [t^\ast]`. + +* Else: + + * The instruction is valid with type :math:`[t~t~\I32] \to [t]`, for any :ref:`value type ` :math:`t` that :ref:`matches ` some :ref:`number type `. .. math:: \frac{ + }{ + C \vdashinstr \SELECT~t : [t~t~\I32] \to [t] + } + \qquad + \frac{ + \vdashvaltypematch t \matchesvaltype \numtype }{ C \vdashinstr \SELECT : [t~t~\I32] \to [t] } .. note:: - Both |DROP| and |SELECT| are :ref:`value-polymorphic ` instructions. + In future versions of WebAssembly, |SELECT| may allow more than one value per choice. .. index:: variable instructions, local index, global index, context diff --git a/document/core/valid/types.rst b/document/core/valid/types.rst index 44536f2235..37aa01ee35 100644 --- a/document/core/valid/types.rst +++ b/document/core/valid/types.rst @@ -270,6 +270,15 @@ A :ref:`value type ` :math:`\valtype_1` matches a :ref:`value ty * Or both :math:`\valtype_1` and :math:`\valtype_2` are :ref:`reference types ` and :math:`\valtype_1` :ref:`matches ` :math:`\valtype_2`. +* Or :math:`\valtype_1` is :math:`\BOT`. + +.. math:: + ~\\[-1ex] + \frac{ + }{ + \vdashvaltypematch \BOT \matchesvaltype \valtype + } + .. _match-resulttype: diff --git a/interpreter/binary/decode.ml b/interpreter/binary/decode.ml index 08e41d36c7..691778de70 100644 --- a/interpreter/binary/decode.ml +++ b/interpreter/binary/decode.ml @@ -258,9 +258,10 @@ let rec instr s = | 0x12 | 0x13 | 0x14 | 0x15 | 0x16 | 0x17 | 0x18 | 0x19 as b -> illegal s pos b | 0x1a -> drop - | 0x1b -> select + | 0x1b -> select None + | 0x1c -> select (Some (vec value_type s)) - | 0x1c | 0x1d | 0x1e | 0x1f as b -> illegal s pos b + | 0x1d | 0x1e | 0x1f as b -> illegal s pos b | 0x20 -> local_get (at var s) | 0x21 -> local_set (at var s) diff --git a/interpreter/binary/encode.ml b/interpreter/binary/encode.ml index 7519bc2e23..3d7d13a514 100644 --- a/interpreter/binary/encode.ml +++ b/interpreter/binary/encode.ml @@ -104,6 +104,7 @@ let encode m = let value_type = function | NumType t -> num_type t | RefType t -> ref_type t + | BotType -> assert false let stack_type = function | [] -> vs7 (-0x40) @@ -166,7 +167,8 @@ let encode m = | CallIndirect (x, y) -> op 0x11; var y; var x | Drop -> op 0x1a - | Select -> op 0x1b + | Select None -> op 0x1b + | Select (Some ts) -> op 0x1c; vec value_type ts | LocalGet x -> op 0x20; var x | LocalSet x -> op 0x21; var x diff --git a/interpreter/exec/eval.ml b/interpreter/exec/eval.ml index 84eb2f4eb3..03a4ff30ad 100644 --- a/interpreter/exec/eval.ml +++ b/interpreter/exec/eval.ml @@ -172,10 +172,10 @@ let rec step (c : config) : config = | Drop, v :: vs' -> vs', [] - | Select, Num (I32 0l) :: v2 :: v1 :: vs' -> + | Select _, Num (I32 0l) :: v2 :: v1 :: vs' -> v2 :: vs', [] - | Select, Num (I32 i) :: v2 :: v1 :: vs' -> + | Select _, Num (I32 i) :: v2 :: v1 :: vs' -> v1 :: vs', [] | LocalGet x, vs -> diff --git a/interpreter/host/spectest.ml b/interpreter/host/spectest.ml index c343e1bb75..a8d32aa55e 100644 --- a/interpreter/host/spectest.ml +++ b/interpreter/host/spectest.ml @@ -15,6 +15,7 @@ let global (GlobalType (t, _) as gt) = | NumType F32Type -> Num (F32 (F32.of_float 666.6)) | NumType F64Type -> Num (F64 (F64.of_float 666.6)) | RefType _ -> Ref NullRef + | BotType -> assert false in Global.alloc gt v let table = diff --git a/interpreter/script/js.ml b/interpreter/script/js.ml index fe89d76830..6f5c3e6c25 100644 --- a/interpreter/script/js.ml +++ b/interpreter/script/js.ml @@ -306,6 +306,7 @@ let assert_return_nan_bitpattern nan_bitmask_of ts at = Test (Values.I32 I32Op.Eqz) @@ at; BrIf (0l @@ at) @@ at ] | RefType _ -> [Br (0l @@ at) @@ at] + | BotType -> assert false in [], List.flatten (List.rev_map test ts) let assert_return_canonical_nan = assert_return_nan_bitpattern abs_mask_of @@ -317,6 +318,7 @@ let assert_return_ref ts at = | RefType _ -> [ RefIsNull @@ at; BrIf (0l @@ at) @@ at ] + | BotType -> assert false in [], List.flatten (List.rev_map test ts) let assert_return_func ts at = @@ -326,6 +328,7 @@ let assert_return_func ts at = [ Call (is_funcref_idx @@ at) @@ at; Test (Values.I32 I32Op.Eqz) @@ at; BrIf (0l @@ at) @@ at ] + | BotType -> assert false in [], List.flatten (List.rev_map test ts) let wrap item_name wrap_action wrap_assertion at = @@ -374,6 +377,7 @@ let is_js_num_type = function let is_js_value_type = function | NumType t -> is_js_num_type t | RefType t -> true + | BotType -> assert false let is_js_global_type = function | GlobalType (t, mut) -> is_js_value_type t && mut = Immutable diff --git a/interpreter/syntax/ast.ml b/interpreter/syntax/ast.ml index 93fed9ea62..06e75c396c 100644 --- a/interpreter/syntax/ast.ml +++ b/interpreter/syntax/ast.ml @@ -71,7 +71,7 @@ and instr' = | Unreachable (* trap unconditionally *) | Nop (* do nothing *) | Drop (* forget a value *) - | Select (* branchless conditional *) + | Select of value_type list option (* branchless conditional *) | Block of stack_type * instr list (* execute in sequence *) | Loop of stack_type * instr list (* loop header *) | If of stack_type * instr list * instr list (* conditional *) diff --git a/interpreter/syntax/operators.ml b/interpreter/syntax/operators.ml index 3fb6a4b415..2ff649b67d 100644 --- a/interpreter/syntax/operators.ml +++ b/interpreter/syntax/operators.ml @@ -16,7 +16,7 @@ let ref_is_null = RefIsNull let unreachable = Unreachable let nop = Nop let drop = Drop -let select = Select +let select t = Select t let block ts es = Block (ts, es) let loop ts es = Loop (ts, es) let br x = Br x diff --git a/interpreter/syntax/types.ml b/interpreter/syntax/types.ml index 3e429db6bb..fb3f13b1ba 100644 --- a/interpreter/syntax/types.ml +++ b/interpreter/syntax/types.ml @@ -2,7 +2,7 @@ type num_type = I32Type | I64Type | F32Type | F64Type type ref_type = NullRefType | AnyRefType | FuncRefType -type value_type = NumType of num_type | RefType of ref_type +type value_type = NumType of num_type | RefType of ref_type | BotType type stack_type = value_type list type func_type = FuncType of stack_type * stack_type @@ -40,6 +40,7 @@ let match_value_type t1 t2 = match t1, t2 with | NumType t1', NumType t2' -> match_num_type t1' t2' | RefType t1', RefType t2' -> match_ref_type t1' t2' + | BotType, _ -> true | _, _ -> false let match_limits lim1 lim2 = @@ -70,49 +71,13 @@ let match_extern_type et1 et2 = | ExternGlobalType gt1, ExternGlobalType gt2 -> match_global_type gt1 gt2 | _, _ -> false +let is_num_type = function + | NumType _ | BotType -> true + | RefType _ -> false -(* Meet and join *) - -let join_num_type t1 t2 = - if t1 = t2 then Some t1 else None - -let join_ref_type t1 t2 = - match t1, t2 with - | AnyRefType, _ | _, NullRefType -> Some t1 - | _, AnyRefType | NullRefType, _ -> Some t2 - | _, _ when t1 = t2 -> Some t1 - | _, _ -> Some AnyRefType - -let join_value_type t1 t2 = - match t1, t2 with - | NumType t1', NumType t2' -> - Lib.Option.map (fun t' -> NumType t') (join_num_type t1' t2') - | RefType t1', RefType t2' -> - Lib.Option.map (fun t' -> RefType t') (join_ref_type t1' t2') - | _, _ -> None - - -let meet_num_type t1 t2 = - if t1 = t2 then Some t1 else None - -let meet_ref_type t1 t2 = - match t1, t2 with - | _, AnyRefType | NullRefType, _ -> Some t1 - | AnyRefType, _ | _, NullRefType -> Some t2 - | _, _ when t1 = t2 -> Some t1 - | _, _ -> Some NullRefType - -let meet_value_type t1 t2 = - match t1, t2 with - | NumType t1', NumType t2' -> - Lib.Option.map (fun t' -> NumType t') (meet_num_type t1' t2') - | RefType t1', RefType t2' -> - Lib.Option.map (fun t' -> RefType t') (meet_ref_type t1' t2') - | _, _ -> None - -let meet_stack_type ts1 ts2 = - try Some (List.map Lib.Option.force (List.map2 meet_value_type ts1 ts2)) - with Invalid_argument _ -> None +let is_ref_type = function + | NumType _ -> false + | RefType _ | BotType -> true (* Filters *) @@ -143,6 +108,7 @@ let string_of_ref_type = function let string_of_value_type = function | NumType t -> string_of_num_type t | RefType t -> string_of_ref_type t + | BotType -> "impossible" let string_of_value_types = function | [t] -> string_of_value_type t diff --git a/interpreter/syntax/values.ml b/interpreter/syntax/values.ml index de22eb36cc..cf5c6cb88c 100644 --- a/interpreter/syntax/values.ml +++ b/interpreter/syntax/values.ml @@ -44,6 +44,7 @@ let default_ref = function let default_value = function | NumType t' -> Num (default_num t') | RefType t' -> Ref (default_ref t') + | BotType -> assert false (* Conversion *) diff --git a/interpreter/text/arrange.ml b/interpreter/text/arrange.ml index e2b7adaedf..c4bb36457b 100644 --- a/interpreter/text/arrange.ml +++ b/interpreter/text/arrange.ml @@ -224,7 +224,9 @@ let rec instr e = | Unreachable -> "unreachable", [] | Nop -> "nop", [] | Drop -> "drop", [] - | Select -> "select", [] + | Select None -> "select", [] + | Select (Some []) -> "select", [Node ("result", [])] + | Select (Some ts) -> "select", decls "result" ts | Block (ts, es) -> "block", stack_type ts @ list instr es | Loop (ts, es) -> "loop", stack_type ts @ list instr es | If (ts, es1, es2) -> diff --git a/interpreter/text/parser.mly b/interpreter/text/parser.mly index 576e0dd1db..6bad089185 100644 --- a/interpreter/text/parser.mly +++ b/interpreter/text/parser.mly @@ -305,6 +305,7 @@ align_opt : instr : | plain_instr { let at = at () in fun c -> [$1 c @@ at] } + | select_instr_instr { fun c -> let e, es = $1 c in e :: es } | call_instr_instr { fun c -> let e, es = $1 c in e :: es } | block_instr { let at = at () in fun c -> [$1 c @@ at] } | expr { $1 } /* Sugar */ @@ -313,7 +314,6 @@ plain_instr : | UNREACHABLE { fun c -> unreachable } | NOP { fun c -> nop } | DROP { fun c -> drop } - | SELECT { fun c -> select } | BR var { fun c -> br ($2 c label) } | BR_IF var { fun c -> br_if ($2 c label) } | BR_TABLE var var_list @@ -346,12 +346,35 @@ plain_instr : | CONVERT { fun c -> $1 } +select_instr : + | SELECT select_instr_results + { let at = at () in fun c -> let b, ts = $2 in + select (if b then (Some ts) else None) @@ at } + +select_instr_results : + | LPAR RESULT value_type_list RPAR select_instr_results + { let _, ts = $5 in true, $3 @ ts } + | /* empty */ + { false, [] } + +select_instr_instr : + | SELECT select_instr_results_instr + { let at1 = ati 1 in + fun c -> let b, ts, es = $2 c in + select (if b then (Some ts) else None) @@ at1, es } + +select_instr_results_instr : + | LPAR RESULT value_type_list RPAR select_instr_results_instr + { fun c -> let _, ts, es = $5 c in true, $3 @ ts, es } + | instr + { fun c -> false, [], $1 c } + + call_instr : | CALL_INDIRECT var call_instr_type - { let at1 = ati 1 in fun c -> call_indirect ($2 c table) ($3 c) @@ at1 } + { let at = at () in fun c -> call_indirect ($2 c table) ($3 c) @@ at } | CALL_INDIRECT call_instr_type /* Sugar */ - { let at1 = ati 1 in - fun c -> call_indirect (0l @@ at1) ($2 c) @@ at1 } + { let at = at () in fun c -> call_indirect (0l @@ at) ($2 c) @@ at } call_instr_type : | type_use call_instr_params @@ -434,6 +457,8 @@ expr : /* Sugar */ expr1 : /* Sugar */ | plain_instr expr_list { fun c -> $2 c, $1 c } + | SELECT select_expr_results + { fun c -> let b, ts, es = $2 c in es, select (if b then (Some ts) else None) } | CALL_INDIRECT var call_expr_type { fun c -> let x, es = $3 c in es, call_indirect ($2 c table) x } | CALL_INDIRECT call_expr_type /* Sugar */ @@ -447,6 +472,12 @@ expr1 : /* Sugar */ { fun c -> let c' = $2 c [] in let ts, (es, es1, es2) = $3 c c' in es, if_ ts es1 es2 } +select_expr_results : + | LPAR RESULT value_type_list RPAR select_expr_results + { fun c -> let _, ts, es = $5 c in true, $3 @ ts, es } + | expr_list + { fun c -> false, [], $1 c } + call_expr_type : | type_use call_expr_params { let at1 = ati 1 in @@ -487,6 +518,7 @@ if_ : instr_list : | /* empty */ { fun c -> [] } + | select_instr { fun c -> [$1 c] } | call_instr { fun c -> [$1 c] } | instr instr_list { fun c -> $1 c @ $2 c } diff --git a/interpreter/valid/valid.ml b/interpreter/valid/valid.ml index 5946f68988..bb8f7bea14 100644 --- a/interpreter/valid/valid.ml +++ b/interpreter/valid/valid.ml @@ -55,49 +55,25 @@ let label (c : context) x = lookup "label" c.labels x *) type ellipses = NoEllipses | Ellipses -type infer_stack_type = ellipses * value_type option list +type infer_stack_type = ellipses * value_type list type op_type = {ins : infer_stack_type; outs : infer_stack_type} -let known = List.map (fun t -> Some t) -let stack ts = (NoEllipses, known ts) -let (-~>) ts1 ts2 = {ins = NoEllipses, ts1; outs = NoEllipses, ts2} -let (-->) ts1 ts2 = {ins = NoEllipses, known ts1; outs = NoEllipses, known ts2} -let (-->...) ts1 ts2 = {ins = Ellipses, known ts1; outs = Ellipses, known ts2} - -let string_of_infer_type t = - Lib.Option.get (Lib.Option.map string_of_value_type t) "_" -let string_of_infer_types ts = - "[" ^ String.concat " " (List.map string_of_infer_type ts) ^ "]" - -let match_type t1 t2 = - match t1, t2 with - | Some t1, Some t2 -> match_value_type t1 t2 - | _, _ -> true - -let join_type t1 t2 at = - match t1, t2 with - | _, None -> t1 - | None, _ -> t2 - | Some t1', Some t2' -> - let t = join_value_type t1' t2' in - require (t <> None) at - ("type mismatch: operator requires common supertype for " ^ - string_of_infer_type t1 ^ " and " ^ string_of_infer_type t2 ^ - " but none exists"); - t +let stack ts = (NoEllipses, ts) +let (-->) ts1 ts2 = {ins = NoEllipses, ts1; outs = NoEllipses, ts2} +let (-->...) ts1 ts2 = {ins = Ellipses, ts1; outs = Ellipses, ts2} let check_stack ts1 ts2 at = require - (List.length ts1 = List.length ts2 && List.for_all2 match_type ts1 ts2) at - ("type mismatch: operator requires " ^ string_of_infer_types ts2 ^ - " but stack has " ^ string_of_infer_types ts1) + (List.length ts1 = List.length ts2 && List.for_all2 match_value_type ts1 ts2) at + ("type mismatch: operator requires " ^ string_of_stack_type ts2 ^ + " but stack has " ^ string_of_stack_type ts1) let pop (ell1, ts1) (ell2, ts2) at = let n1 = List.length ts1 in let n2 = List.length ts2 in let n = min n1 n2 in let n3 = if ell2 = Ellipses then (n1 - n) else 0 in - check_stack (Lib.List.make n3 None @ Lib.List.drop (n2 - n) ts2) ts1 at; + check_stack (Lib.List.make n3 BotType @ Lib.List.drop (n2 - n) ts2) ts1 at; (ell2, if ell1 = Ellipses then [] else Lib.List.take (n2 - n) ts2) let push (ell1, ts1) (ell2, ts2) = @@ -106,7 +82,7 @@ let push (ell1, ts1) (ell2, ts2) = ts2 @ ts1 let peek i (ell, ts) = - try List.nth (List.rev ts) i with Failure _ -> None + try List.nth (List.rev ts) i with Failure _ -> BotType (* Type Synthesis *) @@ -200,13 +176,19 @@ let rec check_instr (c : context) (e : instr) (s : infer_stack_type) : op_type = [] --> [] | Drop -> - [peek 0 s] -~> [] + [peek 0 s] --> [] - | Select -> - let t1 = peek 2 s in - let t2 = peek 1 s in - let t = join_type t1 t2 e.at in - [t; t; Some (NumType I32Type)] -~> [t] + | Select None -> + let t = peek 1 s in + require (is_num_type t) e.at + ("type mismatch: instruction requires numeric type" ^ + " but stack has " ^ string_of_value_type t); + [t; t; NumType I32Type] --> [t] + + | Select (Some ts) -> + check_arity (List.length ts) e.at; + require (List.length ts <> 0) e.at "invalid result arity, 0 is not (yet) allowed"; + (ts @ ts @ [NumType I32Type]) --> ts | Block (ts, es) -> check_arity (List.length ts) e.at; @@ -231,18 +213,10 @@ let rec check_instr (c : context) (e : instr) (s : infer_stack_type) : op_type = (label c x @ [NumType I32Type]) --> label c x | BrTable (xs, x) -> - let ts = - List.fold_left (fun t1 t2 -> - let t = meet_stack_type t1 t2 in - require (t <> None) e.at - ("type mismatch: operator requires common subtype for " ^ - string_of_stack_type t1 ^ " and " ^ string_of_stack_type t2 ^ - " but none exists"); - Lib.Option.force t) - (label c x) (List.map (label c) xs) - in - check_stack (known ts) (known (label c x)) x.at; - List.iter (fun x' -> check_stack (known ts) (known (label c x')) x'.at) xs; + let n = List.length (label c x) in + let ts = Lib.List.table n (fun i -> peek (i + 1) s) in + check_stack ts (label c x) x.at; + List.iter (fun x' -> check_stack ts (label c x') x'.at) xs; (ts @ [NumType I32Type]) -->... [] | Return -> @@ -256,8 +230,8 @@ let rec check_instr (c : context) (e : instr) (s : infer_stack_type) : op_type = let TableType (lim, t) = table c x in let FuncType (ins, out) = type_ c y in require (match_ref_type t FuncRefType) x.at - ("type mismatch: operator requires table of functions, " ^ - "but table has " ^ string_of_ref_type t); + ("type mismatch: instruction requires table of functions" ^ + " but table has " ^ string_of_ref_type t); (ins @ [NumType I32Type]) --> out | LocalGet x -> @@ -364,7 +338,7 @@ and check_block (c : context) (es : instr list) (ts : stack_type) at = let s' = pop (stack ts) s at in require (snd s' = []) at ("type mismatch: operator requires " ^ string_of_stack_type ts ^ - " but stack has " ^ string_of_infer_types (snd s)) + " but stack has " ^ string_of_stack_type (snd s)) (* Types *) @@ -388,6 +362,7 @@ let check_value_type (t : value_type) at = match t with | NumType t' -> check_num_type t' at | RefType t' -> check_ref_type t' at + | BotType -> () let check_func_type (ft : func_type) at = let FuncType (ins, out) = ft in diff --git a/test/core/br_table.wast b/test/core/br_table.wast index f5a153447c..11b51a715e 100644 --- a/test/core/br_table.wast +++ b/test/core/br_table.wast @@ -1251,13 +1251,49 @@ ) ) - (func (export "meet-funcref") (param i32) (result anyref) + (func (export "meet-funcref-1") (param i32) (result anyref) + (block $l1 (result anyref) + (block $l2 (result funcref) + (br_table $l1 $l1 $l2 (table.get 0 (i32.const 0)) (local.get 0)) + ) + ) + ) + + (func (export "meet-funcref-2") (param i32) (result anyref) + (block $l1 (result anyref) + (block $l2 (result funcref) + (br_table $l2 $l2 $l1 (table.get 0 (i32.const 0)) (local.get 0)) + ) + ) + ) + + (func (export "meet-funcref-3") (param i32) (result anyref) (block $l1 (result anyref) (block $l2 (result funcref) (br_table $l2 $l1 $l2 (table.get 0 (i32.const 0)) (local.get 0)) ) ) ) + + (func (export "meet-funcref-4") (param i32) (result anyref) + (block $l1 (result anyref) + (block $l2 (result funcref) + (br_table $l1 $l2 $l1 (table.get 0 (i32.const 0)) (local.get 0)) + ) + ) + ) + + (func (export "meet-bottom") + (block (result f64) + (block (result f32) + (unreachable) + (br_table 0 1 1 (i32.const 1)) + ) + (drop) + (f64.const 0) + ) + (drop) + ) ) (assert_return (invoke "type-i32")) @@ -1445,9 +1481,18 @@ (assert_return (invoke "meet-anyref" (i32.const 1) (ref.host 1)) (ref.host 1)) (assert_return (invoke "meet-anyref" (i32.const 2) (ref.host 1)) (ref.host 1)) -(assert_return_func (invoke "meet-funcref" (i32.const 0))) -(assert_return_func (invoke "meet-funcref" (i32.const 1))) -(assert_return_func (invoke "meet-funcref" (i32.const 2))) +(assert_return_func (invoke "meet-funcref-1" (i32.const 0))) +(assert_return_func (invoke "meet-funcref-1" (i32.const 1))) +(assert_return_func (invoke "meet-funcref-1" (i32.const 2))) +(assert_return_func (invoke "meet-funcref-2" (i32.const 0))) +(assert_return_func (invoke "meet-funcref-2" (i32.const 1))) +(assert_return_func (invoke "meet-funcref-2" (i32.const 2))) +(assert_return_func (invoke "meet-funcref-3" (i32.const 0))) +(assert_return_func (invoke "meet-funcref-3" (i32.const 1))) +(assert_return_func (invoke "meet-funcref-3" (i32.const 2))) +(assert_return_func (invoke "meet-funcref-4" (i32.const 0))) +(assert_return_func (invoke "meet-funcref-4" (i32.const 1))) +(assert_return_func (invoke "meet-funcref-4" (i32.const 2))) (assert_invalid (module (func $type-arg-void-vs-num (result i32) diff --git a/test/core/select.wast b/test/core/select.wast index 7be0b92309..33b7f6246c 100644 --- a/test/core/select.wast +++ b/test/core/select.wast @@ -4,27 +4,62 @@ (table $tab funcref (elem $dummy)) (memory 1) - (func (export "select_i32") (param $lhs i32) (param $rhs i32) (param $cond i32) (result i32) - (select (local.get $lhs) (local.get $rhs) (local.get $cond))) - - (func (export "select_i64") (param $lhs i64) (param $rhs i64) (param $cond i32) (result i64) - (select (local.get $lhs) (local.get $rhs) (local.get $cond))) + (func (export "select-i32") (param i32 i32 i32) (result i32) + (select (local.get 0) (local.get 1) (local.get 2)) + ) + (func (export "select-i64") (param i64 i64 i32) (result i64) + (select (local.get 0) (local.get 1) (local.get 2)) + ) + (func (export "select-f32") (param f32 f32 i32) (result f32) + (select (local.get 0) (local.get 1) (local.get 2)) + ) + (func (export "select-f64") (param f64 f64 i32) (result f64) + (select (local.get 0) (local.get 1) (local.get 2)) + ) - (func (export "select_f32") (param $lhs f32) (param $rhs f32) (param $cond i32) (result f32) - (select (local.get $lhs) (local.get $rhs) (local.get $cond))) + (func (export "select-i32-t") (param i32 i32 i32) (result i32) + (select (result i32) (local.get 0) (local.get 1) (local.get 2)) + ) + (func (export "select-i64-t") (param i64 i64 i32) (result i64) + (select (result i64) (local.get 0) (local.get 1) (local.get 2)) + ) + (func (export "select-f32-t") (param f32 f32 i32) (result f32) + (select (result f32) (local.get 0) (local.get 1) (local.get 2)) + ) + (func (export "select-f64-t") (param f64 f64 i32) (result f64) + (select (result f64) (local.get 0) (local.get 1) (local.get 2)) + ) + (func (export "select-anyref") (param anyref anyref i32) (result anyref) + (select (result anyref) (local.get 0) (local.get 1) (local.get 2)) + ) - (func (export "select_f64") (param $lhs f64) (param $rhs f64) (param $cond i32) (result f64) - (select (local.get $lhs) (local.get $rhs) (local.get $cond))) + (func (export "join-nullref") (param i32) (result anyref) + (select (result anyref) (ref.null) (ref.null) (local.get 0)) + ) + (func (export "join-funcref") (param i32) (result anyref) + (select (result anyref) + (table.get $tab (i32.const 0)) + (ref.null) + (local.get 0) + ) + ) + (func (export "join-anyref") (param i32) (param anyref) (result anyref) + (select (result anyref) + (table.get $tab (i32.const 0)) + (local.get 1) + (local.get 0) + ) + ) ;; Check that both sides of the select are evaluated - (func (export "select_trap_l") (param $cond i32) (result i32) + (func (export "select-trap-left") (param $cond i32) (result i32) (select (unreachable) (i32.const 0) (local.get $cond)) ) - (func (export "select_trap_r") (param $cond i32) (result i32) + (func (export "select-trap-right") (param $cond i32) (result i32) (select (i32.const 0) (unreachable) (local.get $cond)) ) - (func (export "select_unreached") + (func (export "select-unreached") (unreachable) (select) (unreachable) (i32.const 0) (select) (unreachable) (i32.const 0) (i32.const 0) (select) @@ -33,19 +68,6 @@ ) - (func (export "join-nullref") (param i32) (result anyref) - (select (ref.null) (ref.null) (local.get 0)) - ) - - (func (export "join-funcref") (param i32) (result anyref) - (select (table.get $tab (i32.const 0)) (ref.null) (local.get 0)) - ) - - (func (export "join-anyref") (param i32) (param anyref) (result anyref) - (select (table.get $tab (i32.const 0)) (local.get 1) (local.get 0)) - ) - - ;; As the argument of control constructs and instructions (func (export "as-select-first") (param i32) (result i32) @@ -190,33 +212,64 @@ ) ) -(assert_return (invoke "select_i32" (i32.const 1) (i32.const 2) (i32.const 1)) (i32.const 1)) -(assert_return (invoke "select_i64" (i64.const 2) (i64.const 1) (i32.const 1)) (i64.const 2)) -(assert_return (invoke "select_f32" (f32.const 1) (f32.const 2) (i32.const 1)) (f32.const 1)) -(assert_return (invoke "select_f64" (f64.const 1) (f64.const 2) (i32.const 1)) (f64.const 1)) - -(assert_return (invoke "select_i32" (i32.const 1) (i32.const 2) (i32.const 0)) (i32.const 2)) -(assert_return (invoke "select_i32" (i32.const 2) (i32.const 1) (i32.const 0)) (i32.const 1)) -(assert_return (invoke "select_i64" (i64.const 2) (i64.const 1) (i32.const -1)) (i64.const 2)) -(assert_return (invoke "select_i64" (i64.const 2) (i64.const 1) (i32.const 0xf0f0f0f0)) (i64.const 2)) - -(assert_return (invoke "select_f32" (f32.const nan) (f32.const 1) (i32.const 1)) (f32.const nan)) -(assert_return (invoke "select_f32" (f32.const nan:0x20304) (f32.const 1) (i32.const 1)) (f32.const nan:0x20304)) -(assert_return (invoke "select_f32" (f32.const nan) (f32.const 1) (i32.const 0)) (f32.const 1)) -(assert_return (invoke "select_f32" (f32.const nan:0x20304) (f32.const 1) (i32.const 0)) (f32.const 1)) -(assert_return (invoke "select_f32" (f32.const 2) (f32.const nan) (i32.const 1)) (f32.const 2)) -(assert_return (invoke "select_f32" (f32.const 2) (f32.const nan:0x20304) (i32.const 1)) (f32.const 2)) -(assert_return (invoke "select_f32" (f32.const 2) (f32.const nan) (i32.const 0)) (f32.const nan)) -(assert_return (invoke "select_f32" (f32.const 2) (f32.const nan:0x20304) (i32.const 0)) (f32.const nan:0x20304)) - -(assert_return (invoke "select_f64" (f64.const nan) (f64.const 1) (i32.const 1)) (f64.const nan)) -(assert_return (invoke "select_f64" (f64.const nan:0x20304) (f64.const 1) (i32.const 1)) (f64.const nan:0x20304)) -(assert_return (invoke "select_f64" (f64.const nan) (f64.const 1) (i32.const 0)) (f64.const 1)) -(assert_return (invoke "select_f64" (f64.const nan:0x20304) (f64.const 1) (i32.const 0)) (f64.const 1)) -(assert_return (invoke "select_f64" (f64.const 2) (f64.const nan) (i32.const 1)) (f64.const 2)) -(assert_return (invoke "select_f64" (f64.const 2) (f64.const nan:0x20304) (i32.const 1)) (f64.const 2)) -(assert_return (invoke "select_f64" (f64.const 2) (f64.const nan) (i32.const 0)) (f64.const nan)) -(assert_return (invoke "select_f64" (f64.const 2) (f64.const nan:0x20304) (i32.const 0)) (f64.const nan:0x20304)) +(assert_return (invoke "select-i32" (i32.const 1) (i32.const 2) (i32.const 1)) (i32.const 1)) +(assert_return (invoke "select-i64" (i64.const 2) (i64.const 1) (i32.const 1)) (i64.const 2)) +(assert_return (invoke "select-f32" (f32.const 1) (f32.const 2) (i32.const 1)) (f32.const 1)) +(assert_return (invoke "select-f64" (f64.const 1) (f64.const 2) (i32.const 1)) (f64.const 1)) + +(assert_return (invoke "select-i32" (i32.const 1) (i32.const 2) (i32.const 0)) (i32.const 2)) +(assert_return (invoke "select-i32" (i32.const 2) (i32.const 1) (i32.const 0)) (i32.const 1)) +(assert_return (invoke "select-i64" (i64.const 2) (i64.const 1) (i32.const -1)) (i64.const 2)) +(assert_return (invoke "select-i64" (i64.const 2) (i64.const 1) (i32.const 0xf0f0f0f0)) (i64.const 2)) + +(assert_return (invoke "select-f32" (f32.const nan) (f32.const 1) (i32.const 1)) (f32.const nan)) +(assert_return (invoke "select-f32" (f32.const nan:0x20304) (f32.const 1) (i32.const 1)) (f32.const nan:0x20304)) +(assert_return (invoke "select-f32" (f32.const nan) (f32.const 1) (i32.const 0)) (f32.const 1)) +(assert_return (invoke "select-f32" (f32.const nan:0x20304) (f32.const 1) (i32.const 0)) (f32.const 1)) +(assert_return (invoke "select-f32" (f32.const 2) (f32.const nan) (i32.const 1)) (f32.const 2)) +(assert_return (invoke "select-f32" (f32.const 2) (f32.const nan:0x20304) (i32.const 1)) (f32.const 2)) +(assert_return (invoke "select-f32" (f32.const 2) (f32.const nan) (i32.const 0)) (f32.const nan)) +(assert_return (invoke "select-f32" (f32.const 2) (f32.const nan:0x20304) (i32.const 0)) (f32.const nan:0x20304)) + +(assert_return (invoke "select-f64" (f64.const nan) (f64.const 1) (i32.const 1)) (f64.const nan)) +(assert_return (invoke "select-f64" (f64.const nan:0x20304) (f64.const 1) (i32.const 1)) (f64.const nan:0x20304)) +(assert_return (invoke "select-f64" (f64.const nan) (f64.const 1) (i32.const 0)) (f64.const 1)) +(assert_return (invoke "select-f64" (f64.const nan:0x20304) (f64.const 1) (i32.const 0)) (f64.const 1)) +(assert_return (invoke "select-f64" (f64.const 2) (f64.const nan) (i32.const 1)) (f64.const 2)) +(assert_return (invoke "select-f64" (f64.const 2) (f64.const nan:0x20304) (i32.const 1)) (f64.const 2)) +(assert_return (invoke "select-f64" (f64.const 2) (f64.const nan) (i32.const 0)) (f64.const nan)) +(assert_return (invoke "select-f64" (f64.const 2) (f64.const nan:0x20304) (i32.const 0)) (f64.const nan:0x20304)) + +(assert_return (invoke "select-i32-t" (i32.const 1) (i32.const 2) (i32.const 1)) (i32.const 1)) +(assert_return (invoke "select-i64-t" (i64.const 2) (i64.const 1) (i32.const 1)) (i64.const 2)) +(assert_return (invoke "select-f32-t" (f32.const 1) (f32.const 2) (i32.const 1)) (f32.const 1)) +(assert_return (invoke "select-f64-t" (f64.const 1) (f64.const 2) (i32.const 1)) (f64.const 1)) +(assert_return (invoke "select-anyref" (ref.host 1) (ref.host 2) (i32.const 1)) (ref.host 1)) + +(assert_return (invoke "select-i32-t" (i32.const 1) (i32.const 2) (i32.const 0)) (i32.const 2)) +(assert_return (invoke "select-i32-t" (i32.const 2) (i32.const 1) (i32.const 0)) (i32.const 1)) +(assert_return (invoke "select-i64-t" (i64.const 2) (i64.const 1) (i32.const -1)) (i64.const 2)) +(assert_return (invoke "select-i64-t" (i64.const 2) (i64.const 1) (i32.const 0xf0f0f0f0)) (i64.const 2)) +(assert_return (invoke "select-anyref" (ref.host 1) (ref.host 2) (i32.const 0)) (ref.host 2)) +(assert_return (invoke "select-anyref" (ref.host 2) (ref.host 1) (i32.const 0)) (ref.host 1)) + +(assert_return (invoke "select-f32-t" (f32.const nan) (f32.const 1) (i32.const 1)) (f32.const nan)) +(assert_return (invoke "select-f32-t" (f32.const nan:0x20304) (f32.const 1) (i32.const 1)) (f32.const nan:0x20304)) +(assert_return (invoke "select-f32-t" (f32.const nan) (f32.const 1) (i32.const 0)) (f32.const 1)) +(assert_return (invoke "select-f32-t" (f32.const nan:0x20304) (f32.const 1) (i32.const 0)) (f32.const 1)) +(assert_return (invoke "select-f32-t" (f32.const 2) (f32.const nan) (i32.const 1)) (f32.const 2)) +(assert_return (invoke "select-f32-t" (f32.const 2) (f32.const nan:0x20304) (i32.const 1)) (f32.const 2)) +(assert_return (invoke "select-f32-t" (f32.const 2) (f32.const nan) (i32.const 0)) (f32.const nan)) +(assert_return (invoke "select-f32-t" (f32.const 2) (f32.const nan:0x20304) (i32.const 0)) (f32.const nan:0x20304)) + +(assert_return (invoke "select-f64-t" (f64.const nan) (f64.const 1) (i32.const 1)) (f64.const nan)) +(assert_return (invoke "select-f64-t" (f64.const nan:0x20304) (f64.const 1) (i32.const 1)) (f64.const nan:0x20304)) +(assert_return (invoke "select-f64-t" (f64.const nan) (f64.const 1) (i32.const 0)) (f64.const 1)) +(assert_return (invoke "select-f64-t" (f64.const nan:0x20304) (f64.const 1) (i32.const 0)) (f64.const 1)) +(assert_return (invoke "select-f64-t" (f64.const 2) (f64.const nan) (i32.const 1)) (f64.const 2)) +(assert_return (invoke "select-f64-t" (f64.const 2) (f64.const nan:0x20304) (i32.const 1)) (f64.const 2)) +(assert_return (invoke "select-f64-t" (f64.const 2) (f64.const nan) (i32.const 0)) (f64.const nan)) +(assert_return (invoke "select-f64-t" (f64.const 2) (f64.const nan:0x20304) (i32.const 0)) (f64.const nan:0x20304)) (assert_return (invoke "join-nullref" (i32.const 1)) (ref.null)) (assert_return (invoke "join-nullref" (i32.const 0)) (ref.null)) @@ -227,10 +280,10 @@ (assert_return_func (invoke "join-anyref" (i32.const 1) (ref.host 1))) (assert_return (invoke "join-anyref" (i32.const 0) (ref.host 1)) (ref.host 1)) -(assert_trap (invoke "select_trap_l" (i32.const 1)) "unreachable") -(assert_trap (invoke "select_trap_l" (i32.const 0)) "unreachable") -(assert_trap (invoke "select_trap_r" (i32.const 1)) "unreachable") -(assert_trap (invoke "select_trap_r" (i32.const 0)) "unreachable") +(assert_trap (invoke "select-trap-left" (i32.const 1)) "unreachable") +(assert_trap (invoke "select-trap-left" (i32.const 0)) "unreachable") +(assert_trap (invoke "select-trap-right" (i32.const 1)) "unreachable") +(assert_trap (invoke "select-trap-right" (i32.const 0)) "unreachable") (assert_return (invoke "as-select-first" (i32.const 0)) (i32.const 1)) (assert_return (invoke "as-select-first" (i32.const 1)) (i32.const 0)) @@ -309,22 +362,54 @@ (assert_return (invoke "as-convert-operand" (i32.const 1)) (i32.const 1)) (assert_invalid - (module (func $arity-0 (select (nop) (nop) (i32.const 1)))) + (module (func $arity-0-implicit (select (nop) (nop) (i32.const 1)))) "type mismatch" ) +(assert_invalid + (module (func $arity-0 (select (result) (nop) (nop) (i32.const 1)))) + "invalid result arity" +) +(assert_invalid + (module (func $arity-2 (result i32 i32) + (select (result i32 i32) + (i32.const 0) (i32.const 0) + (i32.const 0) (i32.const 0) + (i32.const 1) + ) + )) + "invalid result arity" +) -;; The first two operands should have the same type as each other (assert_invalid - (module (func $type-num-vs-num (select (i32.const 1) (i64.const 1) (i32.const 1)))) + (module (func $type-nullref-implicit + (drop (select (ref.null) (ref.null) (i32.const 1))) + )) + "type mismatch" +) +(assert_invalid + (module (func $type-anyref-implicit (param $r anyref) + (drop (select (local.get $r) (local.get $r) (i32.const 1))) + )) + "type mismatch" +) + +(assert_invalid + (module (func $type-num-vs-num + (drop (select (i32.const 1) (i64.const 1) (i32.const 1))) + )) "type mismatch" ) (assert_invalid - (module (func $type-num-vs-num (select (i32.const 1) (f32.const 1.0) (i32.const 1)))) + (module (func $type-num-vs-num + (drop (select (i32.const 1) (f32.const 1.0) (i32.const 1))) + )) "type mismatch" ) (assert_invalid - (module (func $type-num-vs-num (select (i32.const 1) (f64.const 1.0) (i32.const 1)))) + (module (func $type-num-vs-num + (drop (select (i32.const 1) (f64.const 1.0) (i32.const 1))) + )) "type mismatch" ) diff --git a/test/core/unreached-invalid.wast b/test/core/unreached-invalid.wast index 6ef4ac5520..3ddd77385f 100644 --- a/test/core/unreached-invalid.wast +++ b/test/core/unreached-invalid.wast @@ -535,20 +535,6 @@ )) "type mismatch" ) -(assert_invalid - (module (func $type-br_table-label-num-vs-label-num-after-unreachable - (block (result f64) - (block (result f32) - (unreachable) - (br_table 0 1 1 (i32.const 1)) - ) - (drop) - (f64.const 0) - ) - (drop) - )) - "type mismatch" -) (assert_invalid (module (func $type-block-value-nested-unreachable-num-vs-void From 6eb26a33a3ee7fdc22742b1ac762808b1ee6578c Mon Sep 17 00:00:00 2001 From: Andreas Rossberg Date: Mon, 13 May 2019 20:34:25 +0200 Subject: [PATCH 092/199] Slight simplifications to text format (#84) * Remove passive segment func ref shorthand * Drop passive keyword --- interpreter/text/arrange.ml | 2 +- interpreter/text/lexer.mll | 1 - interpreter/text/parser.mly | 11 +- test/core/bulk.wast | 14 +- test/core/memory_init.wast | 174 ++++++++++++------------- test/core/table_copy.wast | 94 +++++++++----- test/core/table_init.wast | 248 +++++++++++++++++++++--------------- 7 files changed, 307 insertions(+), 237 deletions(-) diff --git a/interpreter/text/arrange.ml b/interpreter/text/arrange.ml index c165adaa34..599347b791 100644 --- a/interpreter/text/arrange.ml +++ b/interpreter/text/arrange.ml @@ -300,7 +300,7 @@ let segment head active passive seg = match seg.it with | Active {index; offset; init} -> Node (head, atom var index :: Node ("offset", const offset) :: active init) - | Passive {etype; data} -> Node (head ^ " passive", passive etype data) + | Passive {etype; data} -> Node (head, passive etype data) let active_elem el = match el.it with diff --git a/interpreter/text/lexer.mll b/interpreter/text/lexer.mll index 75fa292faa..60902e2681 100644 --- a/interpreter/text/lexer.mll +++ b/interpreter/text/lexer.mll @@ -339,7 +339,6 @@ rule token = parse | "memory" { MEMORY } | "elem" { ELEM } | "data" { DATA } - | "passive" { PASSIVE } | "offset" { OFFSET } | "import" { IMPORT } | "export" { EXPORT } diff --git a/interpreter/text/parser.mly b/interpreter/text/parser.mly index 6066c6ffa3..9aee29a034 100644 --- a/interpreter/text/parser.mly +++ b/interpreter/text/parser.mly @@ -167,7 +167,7 @@ let inline_type_explicit (c : context) x ft at = %token CONST UNARY BINARY TEST COMPARE CONVERT %token REF_NULL REF_FUNC %token FUNC START TYPE PARAM RESULT LOCAL GLOBAL -%token TABLE ELEM MEMORY DATA PASSIVE OFFSET IMPORT EXPORT TABLE +%token TABLE ELEM MEMORY DATA OFFSET IMPORT EXPORT TABLE %token MODULE BIN QUOTE %token SCRIPT REGISTER INVOKE GET %token ASSERT_MALFORMED ASSERT_INVALID ASSERT_SOFT_INVALID ASSERT_UNLINKABLE @@ -573,7 +573,6 @@ offset : elemref : | LPAR REF_NULL RPAR { let at = at () in fun c -> ref_null @@ at } | LPAR REF_FUNC var RPAR { let at = at () in fun c -> ref_func ($3 c func) @@ at } - | var { let at = at () in fun c -> ref_func ($1 c func) @@ at } passive_elemref_list : | /* empty */ { fun c -> [] } @@ -585,10 +584,10 @@ active_elemref_list : fun c lookup -> List.map f ($1 c lookup) } elem : - | LPAR ELEM bind_var_opt PASSIVE elem_type passive_elemref_list RPAR + | LPAR ELEM bind_var_opt elem_type passive_elemref_list RPAR { let at = at () in fun c -> ignore ($3 c anon_elem bind_elem); - fun () -> Passive {etype = $5; data = $6 c} @@ at } + fun () -> Passive {etype = $4; data = $5 c} @@ at } | LPAR ELEM bind_var var offset active_elemref_list RPAR { let at = at () in fun c -> ignore (bind_elem c $3); @@ -631,10 +630,10 @@ table_fields : [], [] } data : - | LPAR DATA bind_var_opt PASSIVE string_list RPAR + | LPAR DATA bind_var_opt string_list RPAR { let at = at () in fun c -> ignore ($3 c anon_data bind_data); - fun () -> Passive {etype = (); data = $5} @@ at } + fun () -> Passive {etype = (); data = $4} @@ at } | LPAR DATA bind_var var offset string_list RPAR { let at = at () in fun c -> ignore (bind_data c $3); diff --git a/test/core/bulk.wast b/test/core/bulk.wast index bb71f493d6..0b32679986 100644 --- a/test/core/bulk.wast +++ b/test/core/bulk.wast @@ -1,11 +1,11 @@ -;; Passive segment syntax +;; segment syntax (module (memory 1) - (data passive "foo")) + (data "foo")) (module (table 3 funcref) - (elem passive funcref (ref.func 0) (ref.null) (ref.func 1)) + (elem funcref (ref.func 0) (ref.null) (ref.func 1)) (func) (func)) @@ -120,7 +120,7 @@ ;; memory.init (module (memory 1) - (data passive "\aa\bb\cc\dd") + (data "\aa\bb\cc\dd") (func (export "init") (param i32 i32 i32) (memory.init 0 @@ -159,7 +159,7 @@ ;; data.drop (module (memory 1) - (data $p passive "") + (data $p "") (data $a 0 (i32.const 0) "") (func (export "drop_passive") (data.drop $p)) @@ -182,7 +182,7 @@ ;; table.init (module (table 3 funcref) - (elem passive funcref + (elem funcref (ref.func $zero) (ref.func $one) (ref.func $zero) (ref.func $one)) (func $zero (result i32) (i32.const 0)) @@ -227,7 +227,7 @@ (module (table 1 funcref) (func $f) - (elem $p passive funcref (ref.func $f)) + (elem $p funcref (ref.func $f)) (elem $a 0 (i32.const 0) $f) (func (export "drop_passive") (elem.drop $p)) diff --git a/test/core/memory_init.wast b/test/core/memory_init.wast index 59c9fe8606..4f1a0430e9 100644 --- a/test/core/memory_init.wast +++ b/test/core/memory_init.wast @@ -5,9 +5,9 @@ (module (memory (export "memory0") 1 1) (data (i32.const 2) "\03\01\04\01") - (data passive "\02\07\01\08") + (data "\02\07\01\08") (data (i32.const 12) "\07\05\02\03\06") - (data passive "\05\09\02\07\06") + (data "\05\09\02\07\06") (func (export "test") (nop)) (func (export "load8_u") (param i32) (result i32) @@ -49,9 +49,9 @@ (module (memory (export "memory0") 1 1) (data (i32.const 2) "\03\01\04\01") - (data passive "\02\07\01\08") + (data "\02\07\01\08") (data (i32.const 12) "\07\05\02\03\06") - (data passive "\05\09\02\07\06") + (data "\05\09\02\07\06") (func (export "test") (memory.init 1 (i32.const 7) (i32.const 0) (i32.const 4))) (func (export "load8_u") (param i32) (result i32) @@ -93,9 +93,9 @@ (module (memory (export "memory0") 1 1) (data (i32.const 2) "\03\01\04\01") - (data passive "\02\07\01\08") + (data "\02\07\01\08") (data (i32.const 12) "\07\05\02\03\06") - (data passive "\05\09\02\07\06") + (data "\05\09\02\07\06") (func (export "test") (memory.init 3 (i32.const 15) (i32.const 1) (i32.const 3))) (func (export "load8_u") (param i32) (result i32) @@ -137,9 +137,9 @@ (module (memory (export "memory0") 1 1) (data (i32.const 2) "\03\01\04\01") - (data passive "\02\07\01\08") + (data "\02\07\01\08") (data (i32.const 12) "\07\05\02\03\06") - (data passive "\05\09\02\07\06") + (data "\05\09\02\07\06") (func (export "test") (memory.init 1 (i32.const 7) (i32.const 0) (i32.const 4)) (data.drop 1) @@ -194,14 +194,14 @@ (assert_invalid (module (memory 1) - (data passive "\37") + (data "\37") (func (export "test") (data.drop 4))) "unknown data segment") (module (memory 1) - (data passive "\37") + (data "\37") (func (export "test") (data.drop 0) (data.drop 0))) @@ -209,7 +209,7 @@ (module (memory 1) - (data passive "\37") + (data "\37") (func (export "test") (data.drop 0) (memory.init 0 (i32.const 1234) (i32.const 1) (i32.const 1)))) @@ -231,14 +231,14 @@ (assert_invalid (module (memory 1) - (data passive "\37") + (data "\37") (func (export "test") (memory.init 1 (i32.const 1234) (i32.const 1) (i32.const 1)))) "unknown data segment 1") (module (memory 1) - (data passive "\37") + (data "\37") (func (export "test") (memory.init 0 (i32.const 1) (i32.const 0) (i32.const 1)) (memory.init 0 (i32.const 1) (i32.const 0) (i32.const 1)))) @@ -246,35 +246,35 @@ (module (memory 1) - (data passive "\37") + (data "\37") (func (export "test") (memory.init 0 (i32.const 1234) (i32.const 0) (i32.const 5)))) (assert_trap (invoke "test") "out of bounds") (module (memory 1) - (data passive "\37") + (data "\37") (func (export "test") (memory.init 0 (i32.const 1234) (i32.const 2) (i32.const 3)))) (assert_trap (invoke "test") "out of bounds") (module (memory 1) - (data passive "\37") + (data "\37") (func (export "test") (memory.init 0 (i32.const 0xFFFE) (i32.const 1) (i32.const 3)))) (assert_trap (invoke "test") "out of bounds") (module (memory 1) - (data passive "\37") + (data "\37") (func (export "test") (memory.init 0 (i32.const 1234) (i32.const 4) (i32.const 0)))) (assert_trap (invoke "test") "out of bounds") (module (memory 1) - (data passive "\37") + (data "\37") (func (export "test") (memory.init 0 (i32.const 0x10000) (i32.const 2) (i32.const 0)))) (assert_trap (invoke "test") "out of bounds") @@ -282,7 +282,7 @@ (assert_invalid (module (memory 1) - (data passive "\37") + (data "\37") (func (export "test") (memory.init 0 (i32.const 1) (i32.const 1) (f32.const 1)))) "type mismatch") @@ -290,7 +290,7 @@ (assert_invalid (module (memory 1) - (data passive "\37") + (data "\37") (func (export "test") (memory.init 0 (i32.const 1) (i32.const 1) (i64.const 1)))) "type mismatch") @@ -298,7 +298,7 @@ (assert_invalid (module (memory 1) - (data passive "\37") + (data "\37") (func (export "test") (memory.init 0 (i32.const 1) (i32.const 1) (f64.const 1)))) "type mismatch") @@ -306,7 +306,7 @@ (assert_invalid (module (memory 1) - (data passive "\37") + (data "\37") (func (export "test") (memory.init 0 (i32.const 1) (f32.const 1) (i32.const 1)))) "type mismatch") @@ -314,7 +314,7 @@ (assert_invalid (module (memory 1) - (data passive "\37") + (data "\37") (func (export "test") (memory.init 0 (i32.const 1) (f32.const 1) (f32.const 1)))) "type mismatch") @@ -322,7 +322,7 @@ (assert_invalid (module (memory 1) - (data passive "\37") + (data "\37") (func (export "test") (memory.init 0 (i32.const 1) (f32.const 1) (i64.const 1)))) "type mismatch") @@ -330,7 +330,7 @@ (assert_invalid (module (memory 1) - (data passive "\37") + (data "\37") (func (export "test") (memory.init 0 (i32.const 1) (f32.const 1) (f64.const 1)))) "type mismatch") @@ -338,7 +338,7 @@ (assert_invalid (module (memory 1) - (data passive "\37") + (data "\37") (func (export "test") (memory.init 0 (i32.const 1) (i64.const 1) (i32.const 1)))) "type mismatch") @@ -346,7 +346,7 @@ (assert_invalid (module (memory 1) - (data passive "\37") + (data "\37") (func (export "test") (memory.init 0 (i32.const 1) (i64.const 1) (f32.const 1)))) "type mismatch") @@ -354,7 +354,7 @@ (assert_invalid (module (memory 1) - (data passive "\37") + (data "\37") (func (export "test") (memory.init 0 (i32.const 1) (i64.const 1) (i64.const 1)))) "type mismatch") @@ -362,7 +362,7 @@ (assert_invalid (module (memory 1) - (data passive "\37") + (data "\37") (func (export "test") (memory.init 0 (i32.const 1) (i64.const 1) (f64.const 1)))) "type mismatch") @@ -370,7 +370,7 @@ (assert_invalid (module (memory 1) - (data passive "\37") + (data "\37") (func (export "test") (memory.init 0 (i32.const 1) (f64.const 1) (i32.const 1)))) "type mismatch") @@ -378,7 +378,7 @@ (assert_invalid (module (memory 1) - (data passive "\37") + (data "\37") (func (export "test") (memory.init 0 (i32.const 1) (f64.const 1) (f32.const 1)))) "type mismatch") @@ -386,7 +386,7 @@ (assert_invalid (module (memory 1) - (data passive "\37") + (data "\37") (func (export "test") (memory.init 0 (i32.const 1) (f64.const 1) (i64.const 1)))) "type mismatch") @@ -394,7 +394,7 @@ (assert_invalid (module (memory 1) - (data passive "\37") + (data "\37") (func (export "test") (memory.init 0 (i32.const 1) (f64.const 1) (f64.const 1)))) "type mismatch") @@ -402,7 +402,7 @@ (assert_invalid (module (memory 1) - (data passive "\37") + (data "\37") (func (export "test") (memory.init 0 (f32.const 1) (i32.const 1) (i32.const 1)))) "type mismatch") @@ -410,7 +410,7 @@ (assert_invalid (module (memory 1) - (data passive "\37") + (data "\37") (func (export "test") (memory.init 0 (f32.const 1) (i32.const 1) (f32.const 1)))) "type mismatch") @@ -418,7 +418,7 @@ (assert_invalid (module (memory 1) - (data passive "\37") + (data "\37") (func (export "test") (memory.init 0 (f32.const 1) (i32.const 1) (i64.const 1)))) "type mismatch") @@ -426,7 +426,7 @@ (assert_invalid (module (memory 1) - (data passive "\37") + (data "\37") (func (export "test") (memory.init 0 (f32.const 1) (i32.const 1) (f64.const 1)))) "type mismatch") @@ -434,7 +434,7 @@ (assert_invalid (module (memory 1) - (data passive "\37") + (data "\37") (func (export "test") (memory.init 0 (f32.const 1) (f32.const 1) (i32.const 1)))) "type mismatch") @@ -442,7 +442,7 @@ (assert_invalid (module (memory 1) - (data passive "\37") + (data "\37") (func (export "test") (memory.init 0 (f32.const 1) (f32.const 1) (f32.const 1)))) "type mismatch") @@ -450,7 +450,7 @@ (assert_invalid (module (memory 1) - (data passive "\37") + (data "\37") (func (export "test") (memory.init 0 (f32.const 1) (f32.const 1) (i64.const 1)))) "type mismatch") @@ -458,7 +458,7 @@ (assert_invalid (module (memory 1) - (data passive "\37") + (data "\37") (func (export "test") (memory.init 0 (f32.const 1) (f32.const 1) (f64.const 1)))) "type mismatch") @@ -466,7 +466,7 @@ (assert_invalid (module (memory 1) - (data passive "\37") + (data "\37") (func (export "test") (memory.init 0 (f32.const 1) (i64.const 1) (i32.const 1)))) "type mismatch") @@ -474,7 +474,7 @@ (assert_invalid (module (memory 1) - (data passive "\37") + (data "\37") (func (export "test") (memory.init 0 (f32.const 1) (i64.const 1) (f32.const 1)))) "type mismatch") @@ -482,7 +482,7 @@ (assert_invalid (module (memory 1) - (data passive "\37") + (data "\37") (func (export "test") (memory.init 0 (f32.const 1) (i64.const 1) (i64.const 1)))) "type mismatch") @@ -490,7 +490,7 @@ (assert_invalid (module (memory 1) - (data passive "\37") + (data "\37") (func (export "test") (memory.init 0 (f32.const 1) (i64.const 1) (f64.const 1)))) "type mismatch") @@ -498,7 +498,7 @@ (assert_invalid (module (memory 1) - (data passive "\37") + (data "\37") (func (export "test") (memory.init 0 (f32.const 1) (f64.const 1) (i32.const 1)))) "type mismatch") @@ -506,7 +506,7 @@ (assert_invalid (module (memory 1) - (data passive "\37") + (data "\37") (func (export "test") (memory.init 0 (f32.const 1) (f64.const 1) (f32.const 1)))) "type mismatch") @@ -514,7 +514,7 @@ (assert_invalid (module (memory 1) - (data passive "\37") + (data "\37") (func (export "test") (memory.init 0 (f32.const 1) (f64.const 1) (i64.const 1)))) "type mismatch") @@ -522,7 +522,7 @@ (assert_invalid (module (memory 1) - (data passive "\37") + (data "\37") (func (export "test") (memory.init 0 (f32.const 1) (f64.const 1) (f64.const 1)))) "type mismatch") @@ -530,7 +530,7 @@ (assert_invalid (module (memory 1) - (data passive "\37") + (data "\37") (func (export "test") (memory.init 0 (i64.const 1) (i32.const 1) (i32.const 1)))) "type mismatch") @@ -538,7 +538,7 @@ (assert_invalid (module (memory 1) - (data passive "\37") + (data "\37") (func (export "test") (memory.init 0 (i64.const 1) (i32.const 1) (f32.const 1)))) "type mismatch") @@ -546,7 +546,7 @@ (assert_invalid (module (memory 1) - (data passive "\37") + (data "\37") (func (export "test") (memory.init 0 (i64.const 1) (i32.const 1) (i64.const 1)))) "type mismatch") @@ -554,7 +554,7 @@ (assert_invalid (module (memory 1) - (data passive "\37") + (data "\37") (func (export "test") (memory.init 0 (i64.const 1) (i32.const 1) (f64.const 1)))) "type mismatch") @@ -562,7 +562,7 @@ (assert_invalid (module (memory 1) - (data passive "\37") + (data "\37") (func (export "test") (memory.init 0 (i64.const 1) (f32.const 1) (i32.const 1)))) "type mismatch") @@ -570,7 +570,7 @@ (assert_invalid (module (memory 1) - (data passive "\37") + (data "\37") (func (export "test") (memory.init 0 (i64.const 1) (f32.const 1) (f32.const 1)))) "type mismatch") @@ -578,7 +578,7 @@ (assert_invalid (module (memory 1) - (data passive "\37") + (data "\37") (func (export "test") (memory.init 0 (i64.const 1) (f32.const 1) (i64.const 1)))) "type mismatch") @@ -586,7 +586,7 @@ (assert_invalid (module (memory 1) - (data passive "\37") + (data "\37") (func (export "test") (memory.init 0 (i64.const 1) (f32.const 1) (f64.const 1)))) "type mismatch") @@ -594,7 +594,7 @@ (assert_invalid (module (memory 1) - (data passive "\37") + (data "\37") (func (export "test") (memory.init 0 (i64.const 1) (i64.const 1) (i32.const 1)))) "type mismatch") @@ -602,7 +602,7 @@ (assert_invalid (module (memory 1) - (data passive "\37") + (data "\37") (func (export "test") (memory.init 0 (i64.const 1) (i64.const 1) (f32.const 1)))) "type mismatch") @@ -610,7 +610,7 @@ (assert_invalid (module (memory 1) - (data passive "\37") + (data "\37") (func (export "test") (memory.init 0 (i64.const 1) (i64.const 1) (i64.const 1)))) "type mismatch") @@ -618,7 +618,7 @@ (assert_invalid (module (memory 1) - (data passive "\37") + (data "\37") (func (export "test") (memory.init 0 (i64.const 1) (i64.const 1) (f64.const 1)))) "type mismatch") @@ -626,7 +626,7 @@ (assert_invalid (module (memory 1) - (data passive "\37") + (data "\37") (func (export "test") (memory.init 0 (i64.const 1) (f64.const 1) (i32.const 1)))) "type mismatch") @@ -634,7 +634,7 @@ (assert_invalid (module (memory 1) - (data passive "\37") + (data "\37") (func (export "test") (memory.init 0 (i64.const 1) (f64.const 1) (f32.const 1)))) "type mismatch") @@ -642,7 +642,7 @@ (assert_invalid (module (memory 1) - (data passive "\37") + (data "\37") (func (export "test") (memory.init 0 (i64.const 1) (f64.const 1) (i64.const 1)))) "type mismatch") @@ -650,7 +650,7 @@ (assert_invalid (module (memory 1) - (data passive "\37") + (data "\37") (func (export "test") (memory.init 0 (i64.const 1) (f64.const 1) (f64.const 1)))) "type mismatch") @@ -658,7 +658,7 @@ (assert_invalid (module (memory 1) - (data passive "\37") + (data "\37") (func (export "test") (memory.init 0 (f64.const 1) (i32.const 1) (i32.const 1)))) "type mismatch") @@ -666,7 +666,7 @@ (assert_invalid (module (memory 1) - (data passive "\37") + (data "\37") (func (export "test") (memory.init 0 (f64.const 1) (i32.const 1) (f32.const 1)))) "type mismatch") @@ -674,7 +674,7 @@ (assert_invalid (module (memory 1) - (data passive "\37") + (data "\37") (func (export "test") (memory.init 0 (f64.const 1) (i32.const 1) (i64.const 1)))) "type mismatch") @@ -682,7 +682,7 @@ (assert_invalid (module (memory 1) - (data passive "\37") + (data "\37") (func (export "test") (memory.init 0 (f64.const 1) (i32.const 1) (f64.const 1)))) "type mismatch") @@ -690,7 +690,7 @@ (assert_invalid (module (memory 1) - (data passive "\37") + (data "\37") (func (export "test") (memory.init 0 (f64.const 1) (f32.const 1) (i32.const 1)))) "type mismatch") @@ -698,7 +698,7 @@ (assert_invalid (module (memory 1) - (data passive "\37") + (data "\37") (func (export "test") (memory.init 0 (f64.const 1) (f32.const 1) (f32.const 1)))) "type mismatch") @@ -706,7 +706,7 @@ (assert_invalid (module (memory 1) - (data passive "\37") + (data "\37") (func (export "test") (memory.init 0 (f64.const 1) (f32.const 1) (i64.const 1)))) "type mismatch") @@ -714,7 +714,7 @@ (assert_invalid (module (memory 1) - (data passive "\37") + (data "\37") (func (export "test") (memory.init 0 (f64.const 1) (f32.const 1) (f64.const 1)))) "type mismatch") @@ -722,7 +722,7 @@ (assert_invalid (module (memory 1) - (data passive "\37") + (data "\37") (func (export "test") (memory.init 0 (f64.const 1) (i64.const 1) (i32.const 1)))) "type mismatch") @@ -730,7 +730,7 @@ (assert_invalid (module (memory 1) - (data passive "\37") + (data "\37") (func (export "test") (memory.init 0 (f64.const 1) (i64.const 1) (f32.const 1)))) "type mismatch") @@ -738,7 +738,7 @@ (assert_invalid (module (memory 1) - (data passive "\37") + (data "\37") (func (export "test") (memory.init 0 (f64.const 1) (i64.const 1) (i64.const 1)))) "type mismatch") @@ -746,7 +746,7 @@ (assert_invalid (module (memory 1) - (data passive "\37") + (data "\37") (func (export "test") (memory.init 0 (f64.const 1) (i64.const 1) (f64.const 1)))) "type mismatch") @@ -754,7 +754,7 @@ (assert_invalid (module (memory 1) - (data passive "\37") + (data "\37") (func (export "test") (memory.init 0 (f64.const 1) (f64.const 1) (i32.const 1)))) "type mismatch") @@ -762,7 +762,7 @@ (assert_invalid (module (memory 1) - (data passive "\37") + (data "\37") (func (export "test") (memory.init 0 (f64.const 1) (f64.const 1) (f32.const 1)))) "type mismatch") @@ -770,7 +770,7 @@ (assert_invalid (module (memory 1) - (data passive "\37") + (data "\37") (func (export "test") (memory.init 0 (f64.const 1) (f64.const 1) (i64.const 1)))) "type mismatch") @@ -778,14 +778,14 @@ (assert_invalid (module (memory 1) - (data passive "\37") + (data "\37") (func (export "test") (memory.init 0 (f64.const 1) (f64.const 1) (f64.const 1)))) "type mismatch") (module (memory 1 1 ) - (data passive "\42\42\42\42\42\42\42\42\42\42\42\42\42\42\42\42") + (data "\42\42\42\42\42\42\42\42\42\42\42\42\42\42\42\42") (func (export "checkRange") (param $from i32) (param $to i32) (param $expected i32) (result i32) (loop $cont @@ -812,7 +812,7 @@ (i32.const -1)) (module (memory 1 1 ) - (data passive "\42\42\42\42\42\42\42\42\42\42\42\42\42\42\42\42") + (data "\42\42\42\42\42\42\42\42\42\42\42\42\42\42\42\42") (func (export "checkRange") (param $from i32) (param $to i32) (param $expected i32) (result i32) (loop $cont @@ -839,7 +839,7 @@ (i32.const -1)) (module (memory 1 1 ) - (data passive "\42\42\42\42\42\42\42\42\42\42\42\42\42\42\42\42") + (data "\42\42\42\42\42\42\42\42\42\42\42\42\42\42\42\42") (func (export "checkRange") (param $from i32) (param $to i32) (param $expected i32) (result i32) (loop $cont @@ -866,7 +866,7 @@ (i32.const -1)) (module (memory 1 1 ) - (data passive "\42\42\42\42\42\42\42\42\42\42\42\42\42\42\42\42") + (data "\42\42\42\42\42\42\42\42\42\42\42\42\42\42\42\42") (func (export "checkRange") (param $from i32) (param $to i32) (param $expected i32) (result i32) (loop $cont @@ -893,7 +893,7 @@ (i32.const -1)) (module (memory 1 ) - (data passive "\42\42\42\42\42\42\42\42\42\42\42\42\42\42\42\42") + (data "\42\42\42\42\42\42\42\42\42\42\42\42\42\42\42\42") (func (export "checkRange") (param $from i32) (param $to i32) (param $expected i32) (result i32) (loop $cont @@ -920,7 +920,7 @@ (i32.const -1)) (module (memory 1 ) - (data passive "\42\42\42\42\42\42\42\42\42\42\42\42\42\42\42\42") + (data "\42\42\42\42\42\42\42\42\42\42\42\42\42\42\42\42") (func (export "checkRange") (param $from i32) (param $to i32) (param $expected i32) (result i32) (loop $cont diff --git a/test/core/table_copy.wast b/test/core/table_copy.wast index 51c4ae148b..69158060c5 100644 --- a/test/core/table_copy.wast +++ b/test/core/table_copy.wast @@ -1,7 +1,3 @@ -;; -;; Generated by ../meta/generate_table_copy.js -;; - (module (func (export "ef0") (result i32) (i32.const 0)) (func (export "ef1") (result i32) (i32.const 1)) @@ -20,9 +16,11 @@ (import "a" "ef4" (func (result i32))) ;; index 4 (table 30 30 funcref) (elem (i32.const 2) 3 1 4 1) - (elem passive funcref 2 7 1 8) + (elem funcref + (ref.func 2) (ref.func 7) (ref.func 1) (ref.func 8)) (elem (i32.const 12) 7 5 2 3 6) - (elem passive funcref 5 9 2 7 6) + (elem funcref + (ref.func 5) (ref.func 9) (ref.func 2) (ref.func 7) (ref.func 6)) (func (result i32) (i32.const 5)) ;; index 5 (func (result i32) (i32.const 6)) (func (result i32) (i32.const 7)) @@ -75,9 +73,11 @@ (import "a" "ef4" (func (result i32))) ;; index 4 (table 30 30 funcref) (elem (i32.const 2) 3 1 4 1) - (elem passive funcref 2 7 1 8) + (elem funcref + (ref.func 2) (ref.func 7) (ref.func 1) (ref.func 8)) (elem (i32.const 12) 7 5 2 3 6) - (elem passive funcref 5 9 2 7 6) + (elem funcref + (ref.func 5) (ref.func 9) (ref.func 2) (ref.func 7) (ref.func 6)) (func (result i32) (i32.const 5)) ;; index 5 (func (result i32) (i32.const 6)) (func (result i32) (i32.const 7)) @@ -130,9 +130,11 @@ (import "a" "ef4" (func (result i32))) ;; index 4 (table 30 30 funcref) (elem (i32.const 2) 3 1 4 1) - (elem passive funcref 2 7 1 8) + (elem funcref + (ref.func 2) (ref.func 7) (ref.func 1) (ref.func 8)) (elem (i32.const 12) 7 5 2 3 6) - (elem passive funcref 5 9 2 7 6) + (elem funcref + (ref.func 5) (ref.func 9) (ref.func 2) (ref.func 7) (ref.func 6)) (func (result i32) (i32.const 5)) ;; index 5 (func (result i32) (i32.const 6)) (func (result i32) (i32.const 7)) @@ -185,9 +187,11 @@ (import "a" "ef4" (func (result i32))) ;; index 4 (table 30 30 funcref) (elem (i32.const 2) 3 1 4 1) - (elem passive funcref 2 7 1 8) + (elem funcref + (ref.func 2) (ref.func 7) (ref.func 1) (ref.func 8)) (elem (i32.const 12) 7 5 2 3 6) - (elem passive funcref 5 9 2 7 6) + (elem funcref + (ref.func 5) (ref.func 9) (ref.func 2) (ref.func 7) (ref.func 6)) (func (result i32) (i32.const 5)) ;; index 5 (func (result i32) (i32.const 6)) (func (result i32) (i32.const 7)) @@ -240,9 +244,11 @@ (import "a" "ef4" (func (result i32))) ;; index 4 (table 30 30 funcref) (elem (i32.const 2) 3 1 4 1) - (elem passive funcref 2 7 1 8) + (elem funcref + (ref.func 2) (ref.func 7) (ref.func 1) (ref.func 8)) (elem (i32.const 12) 7 5 2 3 6) - (elem passive funcref 5 9 2 7 6) + (elem funcref + (ref.func 5) (ref.func 9) (ref.func 2) (ref.func 7) (ref.func 6)) (func (result i32) (i32.const 5)) ;; index 5 (func (result i32) (i32.const 6)) (func (result i32) (i32.const 7)) @@ -295,9 +301,11 @@ (import "a" "ef4" (func (result i32))) ;; index 4 (table 30 30 funcref) (elem (i32.const 2) 3 1 4 1) - (elem passive funcref 2 7 1 8) + (elem funcref + (ref.func 2) (ref.func 7) (ref.func 1) (ref.func 8)) (elem (i32.const 12) 7 5 2 3 6) - (elem passive funcref 5 9 2 7 6) + (elem funcref + (ref.func 5) (ref.func 9) (ref.func 2) (ref.func 7) (ref.func 6)) (func (result i32) (i32.const 5)) ;; index 5 (func (result i32) (i32.const 6)) (func (result i32) (i32.const 7)) @@ -350,9 +358,11 @@ (import "a" "ef4" (func (result i32))) ;; index 4 (table 30 30 funcref) (elem (i32.const 2) 3 1 4 1) - (elem passive funcref 2 7 1 8) + (elem funcref + (ref.func 2) (ref.func 7) (ref.func 1) (ref.func 8)) (elem (i32.const 12) 7 5 2 3 6) - (elem passive funcref 5 9 2 7 6) + (elem funcref + (ref.func 5) (ref.func 9) (ref.func 2) (ref.func 7) (ref.func 6)) (func (result i32) (i32.const 5)) ;; index 5 (func (result i32) (i32.const 6)) (func (result i32) (i32.const 7)) @@ -405,9 +415,11 @@ (import "a" "ef4" (func (result i32))) ;; index 4 (table 30 30 funcref) (elem (i32.const 2) 3 1 4 1) - (elem passive funcref 2 7 1 8) + (elem funcref + (ref.func 2) (ref.func 7) (ref.func 1) (ref.func 8)) (elem (i32.const 12) 7 5 2 3 6) - (elem passive funcref 5 9 2 7 6) + (elem funcref + (ref.func 5) (ref.func 9) (ref.func 2) (ref.func 7) (ref.func 6)) (func (result i32) (i32.const 5)) ;; index 5 (func (result i32) (i32.const 6)) (func (result i32) (i32.const 7)) @@ -454,9 +466,11 @@ (module (table 30 30 funcref) (elem (i32.const 2) 3 1 4 1) - (elem passive funcref 2 7 1 8) + (elem funcref + (ref.func 2) (ref.func 7) (ref.func 1) (ref.func 8)) (elem (i32.const 12) 7 5 2 3 6) - (elem passive funcref 5 9 2 7 6) + (elem funcref + (ref.func 5) (ref.func 9) (ref.func 2) (ref.func 7) (ref.func 6)) (func (result i32) (i32.const 0)) (func (result i32) (i32.const 1)) (func (result i32) (i32.const 2)) @@ -476,9 +490,11 @@ (module (table 30 30 funcref) (elem (i32.const 2) 3 1 4 1) - (elem passive funcref 2 7 1 8) + (elem funcref + (ref.func 2) (ref.func 7) (ref.func 1) (ref.func 8)) (elem (i32.const 12) 7 5 2 3 6) - (elem passive funcref 5 9 2 7 6) + (elem funcref + (ref.func 5) (ref.func 9) (ref.func 2) (ref.func 7) (ref.func 6)) (func (result i32) (i32.const 0)) (func (result i32) (i32.const 1)) (func (result i32) (i32.const 2)) @@ -498,9 +514,11 @@ (module (table 30 30 funcref) (elem (i32.const 2) 3 1 4 1) - (elem passive funcref 2 7 1 8) + (elem funcref + (ref.func 2) (ref.func 7) (ref.func 1) (ref.func 8)) (elem (i32.const 12) 7 5 2 3 6) - (elem passive funcref 5 9 2 7 6) + (elem funcref + (ref.func 5) (ref.func 9) (ref.func 2) (ref.func 7) (ref.func 6)) (func (result i32) (i32.const 0)) (func (result i32) (i32.const 1)) (func (result i32) (i32.const 2)) @@ -520,9 +538,11 @@ (module (table 30 30 funcref) (elem (i32.const 2) 3 1 4 1) - (elem passive funcref 2 7 1 8) + (elem funcref + (ref.func 2) (ref.func 7) (ref.func 1) (ref.func 8)) (elem (i32.const 12) 7 5 2 3 6) - (elem passive funcref 5 9 2 7 6) + (elem funcref + (ref.func 5) (ref.func 9) (ref.func 2) (ref.func 7) (ref.func 6)) (func (result i32) (i32.const 0)) (func (result i32) (i32.const 1)) (func (result i32) (i32.const 2)) @@ -542,9 +562,11 @@ (module (table 30 30 funcref) (elem (i32.const 2) 3 1 4 1) - (elem passive funcref 2 7 1 8) + (elem funcref + (ref.func 2) (ref.func 7) (ref.func 1) (ref.func 8)) (elem (i32.const 12) 7 5 2 3 6) - (elem passive funcref 5 9 2 7 6) + (elem funcref + (ref.func 5) (ref.func 9) (ref.func 2) (ref.func 7) (ref.func 6)) (func (result i32) (i32.const 0)) (func (result i32) (i32.const 1)) (func (result i32) (i32.const 2)) @@ -564,9 +586,11 @@ (module (table 30 30 funcref) (elem (i32.const 2) 3 1 4 1) - (elem passive funcref 2 7 1 8) + (elem funcref + (ref.func 2) (ref.func 7) (ref.func 1) (ref.func 8)) (elem (i32.const 12) 7 5 2 3 6) - (elem passive funcref 5 9 2 7 6) + (elem funcref + (ref.func 5) (ref.func 9) (ref.func 2) (ref.func 7) (ref.func 6)) (func (result i32) (i32.const 0)) (func (result i32) (i32.const 1)) (func (result i32) (i32.const 2)) @@ -586,9 +610,11 @@ (module (table 30 30 funcref) (elem (i32.const 2) 3 1 4 1) - (elem passive funcref 2 7 1 8) + (elem funcref + (ref.func 2) (ref.func 7) (ref.func 1) (ref.func 8)) (elem (i32.const 12) 7 5 2 3 6) - (elem passive funcref 5 9 2 7 6) + (elem funcref + (ref.func 5) (ref.func 9) (ref.func 2) (ref.func 7) (ref.func 6)) (func (result i32) (i32.const 0)) (func (result i32) (i32.const 1)) (func (result i32) (i32.const 2)) diff --git a/test/core/table_init.wast b/test/core/table_init.wast index 11012a317a..82dc63daa7 100644 --- a/test/core/table_init.wast +++ b/test/core/table_init.wast @@ -1,7 +1,3 @@ -;; -;; Generated by ../meta/generate_table_init.js -;; - (module (func (export "ef0") (result i32) (i32.const 0)) (func (export "ef1") (result i32) (i32.const 1)) @@ -20,9 +16,11 @@ (import "a" "ef4" (func (result i32))) ;; index 4 (table 30 30 funcref) (elem (i32.const 2) 3 1 4 1) - (elem passive funcref 2 7 1 8) + (elem funcref + (ref.func 2) (ref.func 7) (ref.func 1) (ref.func 8)) (elem (i32.const 12) 7 5 2 3 6) - (elem passive funcref 5 9 2 7 6) + (elem funcref + (ref.func 5) (ref.func 9) (ref.func 2) (ref.func 7) (ref.func 6)) (func (result i32) (i32.const 5)) ;; index 5 (func (result i32) (i32.const 6)) (func (result i32) (i32.const 7)) @@ -75,9 +73,11 @@ (import "a" "ef4" (func (result i32))) ;; index 4 (table 30 30 funcref) (elem (i32.const 2) 3 1 4 1) - (elem passive funcref 2 7 1 8) + (elem funcref + (ref.func 2) (ref.func 7) (ref.func 1) (ref.func 8)) (elem (i32.const 12) 7 5 2 3 6) - (elem passive funcref 5 9 2 7 6) + (elem funcref + (ref.func 5) (ref.func 9) (ref.func 2) (ref.func 7) (ref.func 6)) (func (result i32) (i32.const 5)) ;; index 5 (func (result i32) (i32.const 6)) (func (result i32) (i32.const 7)) @@ -130,9 +130,11 @@ (import "a" "ef4" (func (result i32))) ;; index 4 (table 30 30 funcref) (elem (i32.const 2) 3 1 4 1) - (elem passive funcref 2 7 1 8) + (elem funcref + (ref.func 2) (ref.func 7) (ref.func 1) (ref.func 8)) (elem (i32.const 12) 7 5 2 3 6) - (elem passive funcref 5 9 2 7 6) + (elem funcref + (ref.func 5) (ref.func 9) (ref.func 2) (ref.func 7) (ref.func 6)) (func (result i32) (i32.const 5)) ;; index 5 (func (result i32) (i32.const 6)) (func (result i32) (i32.const 7)) @@ -197,7 +199,7 @@ (assert_invalid (module - (elem passive funcref 0) + (elem funcref (ref.func 0)) (func (result i32) (i32.const 0)) (func (export "test") (elem.drop 4))) @@ -205,7 +207,7 @@ (assert_invalid (module - (elem passive funcref 0) + (elem funcref (ref.func 0)) (func (result i32) (i32.const 0)) (func (export "test") (table.init 4 (i32.const 12) (i32.const 1) (i32.const 1)))) @@ -215,9 +217,11 @@ (module (table 30 30 funcref) (elem (i32.const 2) 3 1 4 1) - (elem passive funcref 2 7 1 8) + (elem funcref + (ref.func 2) (ref.func 7) (ref.func 1) (ref.func 8)) (elem (i32.const 12) 7 5 2 3 6) - (elem passive funcref 5 9 2 7 6) + (elem funcref + (ref.func 5) (ref.func 9) (ref.func 2) (ref.func 7) (ref.func 6)) (func (result i32) (i32.const 0)) (func (result i32) (i32.const 1)) (func (result i32) (i32.const 2)) @@ -236,9 +240,11 @@ (module (table 30 30 funcref) (elem (i32.const 2) 3 1 4 1) - (elem passive funcref 2 7 1 8) + (elem funcref + (ref.func 2) (ref.func 7) (ref.func 1) (ref.func 8)) (elem (i32.const 12) 7 5 2 3 6) - (elem passive funcref 5 9 2 7 6) + (elem funcref + (ref.func 5) (ref.func 9) (ref.func 2) (ref.func 7) (ref.func 6)) (func (result i32) (i32.const 0)) (func (result i32) (i32.const 1)) (func (result i32) (i32.const 2)) @@ -257,9 +263,11 @@ (module (table 30 30 funcref) (elem (i32.const 2) 3 1 4 1) - (elem passive funcref 2 7 1 8) + (elem funcref + (ref.func 2) (ref.func 7) (ref.func 1) (ref.func 8)) (elem (i32.const 12) 7 5 2 3 6) - (elem passive funcref 5 9 2 7 6) + (elem funcref + (ref.func 5) (ref.func 9) (ref.func 2) (ref.func 7) (ref.func 6)) (func (result i32) (i32.const 0)) (func (result i32) (i32.const 1)) (func (result i32) (i32.const 2)) @@ -278,9 +286,11 @@ (module (table 30 30 funcref) (elem (i32.const 2) 3 1 4 1) - (elem passive funcref 2 7 1 8) + (elem funcref + (ref.func 2) (ref.func 7) (ref.func 1) (ref.func 8)) (elem (i32.const 12) 7 5 2 3 6) - (elem passive funcref 5 9 2 7 6) + (elem funcref + (ref.func 5) (ref.func 9) (ref.func 2) (ref.func 7) (ref.func 6)) (func (result i32) (i32.const 0)) (func (result i32) (i32.const 1)) (func (result i32) (i32.const 2)) @@ -299,9 +309,11 @@ (module (table 30 30 funcref) (elem (i32.const 2) 3 1 4 1) - (elem passive funcref 2 7 1 8) + (elem funcref + (ref.func 2) (ref.func 7) (ref.func 1) (ref.func 8)) (elem (i32.const 12) 7 5 2 3 6) - (elem passive funcref 5 9 2 7 6) + (elem funcref + (ref.func 5) (ref.func 9) (ref.func 2) (ref.func 7) (ref.func 6)) (func (result i32) (i32.const 0)) (func (result i32) (i32.const 1)) (func (result i32) (i32.const 2)) @@ -320,9 +332,11 @@ (module (table 30 30 funcref) (elem (i32.const 2) 3 1 4 1) - (elem passive funcref 2 7 1 8) + (elem funcref + (ref.func 2) (ref.func 7) (ref.func 1) (ref.func 8)) (elem (i32.const 12) 7 5 2 3 6) - (elem passive funcref 5 9 2 7 6) + (elem funcref + (ref.func 5) (ref.func 9) (ref.func 2) (ref.func 7) (ref.func 6)) (func (result i32) (i32.const 0)) (func (result i32) (i32.const 1)) (func (result i32) (i32.const 2)) @@ -341,9 +355,11 @@ (module (table 30 30 funcref) (elem (i32.const 2) 3 1 4 1) - (elem passive funcref 2 7 1 8) + (elem funcref + (ref.func 2) (ref.func 7) (ref.func 1) (ref.func 8)) (elem (i32.const 12) 7 5 2 3 6) - (elem passive funcref 5 9 2 7 6) + (elem funcref + (ref.func 5) (ref.func 9) (ref.func 2) (ref.func 7) (ref.func 6)) (func (result i32) (i32.const 0)) (func (result i32) (i32.const 1)) (func (result i32) (i32.const 2)) @@ -362,9 +378,11 @@ (module (table 30 30 funcref) (elem (i32.const 2) 3 1 4 1) - (elem passive funcref 2 7 1 8) + (elem funcref + (ref.func 2) (ref.func 7) (ref.func 1) (ref.func 8)) (elem (i32.const 12) 7 5 2 3 6) - (elem passive funcref 5 9 2 7 6) + (elem funcref + (ref.func 5) (ref.func 9) (ref.func 2) (ref.func 7) (ref.func 6)) (func (result i32) (i32.const 0)) (func (result i32) (i32.const 1)) (func (result i32) (i32.const 2)) @@ -383,9 +401,11 @@ (module (table 30 30 funcref) (elem (i32.const 2) 3 1 4 1) - (elem passive funcref 2 7 1 8) + (elem funcref + (ref.func 2) (ref.func 7) (ref.func 1) (ref.func 8)) (elem (i32.const 12) 7 5 2 3 6) - (elem passive funcref 5 9 2 7 6) + (elem funcref + (ref.func 5) (ref.func 9) (ref.func 2) (ref.func 7) (ref.func 6)) (func (result i32) (i32.const 0)) (func (result i32) (i32.const 1)) (func (result i32) (i32.const 2)) @@ -404,9 +424,11 @@ (module (table 30 30 funcref) (elem (i32.const 2) 3 1 4 1) - (elem passive funcref 2 7 1 8) + (elem funcref + (ref.func 2) (ref.func 7) (ref.func 1) (ref.func 8)) (elem (i32.const 12) 7 5 2 3 6) - (elem passive funcref 5 9 2 7 6) + (elem funcref + (ref.func 5) (ref.func 9) (ref.func 2) (ref.func 7) (ref.func 6)) (func (result i32) (i32.const 0)) (func (result i32) (i32.const 1)) (func (result i32) (i32.const 2)) @@ -425,7 +447,7 @@ (assert_invalid (module (table 10 funcref) - (elem passive funcref $f0 $f0 $f0) + (elem funcref (ref.func $f0) (ref.func $f0) (ref.func $f0)) (func $f0) (func (export "test") (table.init 0 (i32.const 1) (i32.const 1) (f32.const 1)))) @@ -434,7 +456,7 @@ (assert_invalid (module (table 10 funcref) - (elem passive funcref $f0 $f0 $f0) + (elem funcref (ref.func $f0) (ref.func $f0) (ref.func $f0)) (func $f0) (func (export "test") (table.init 0 (i32.const 1) (i32.const 1) (i64.const 1)))) @@ -443,7 +465,7 @@ (assert_invalid (module (table 10 funcref) - (elem passive funcref $f0 $f0 $f0) + (elem funcref (ref.func $f0) (ref.func $f0) (ref.func $f0)) (func $f0) (func (export "test") (table.init 0 (i32.const 1) (i32.const 1) (f64.const 1)))) @@ -452,7 +474,7 @@ (assert_invalid (module (table 10 funcref) - (elem passive funcref $f0 $f0 $f0) + (elem funcref (ref.func $f0) (ref.func $f0) (ref.func $f0)) (func $f0) (func (export "test") (table.init 0 (i32.const 1) (f32.const 1) (i32.const 1)))) @@ -461,7 +483,7 @@ (assert_invalid (module (table 10 funcref) - (elem passive funcref $f0 $f0 $f0) + (elem funcref (ref.func $f0) (ref.func $f0) (ref.func $f0)) (func $f0) (func (export "test") (table.init 0 (i32.const 1) (f32.const 1) (f32.const 1)))) @@ -470,7 +492,7 @@ (assert_invalid (module (table 10 funcref) - (elem passive funcref $f0 $f0 $f0) + (elem funcref (ref.func $f0) (ref.func $f0) (ref.func $f0)) (func $f0) (func (export "test") (table.init 0 (i32.const 1) (f32.const 1) (i64.const 1)))) @@ -479,7 +501,7 @@ (assert_invalid (module (table 10 funcref) - (elem passive funcref $f0 $f0 $f0) + (elem funcref (ref.func $f0) (ref.func $f0) (ref.func $f0)) (func $f0) (func (export "test") (table.init 0 (i32.const 1) (f32.const 1) (f64.const 1)))) @@ -488,7 +510,7 @@ (assert_invalid (module (table 10 funcref) - (elem passive funcref $f0 $f0 $f0) + (elem funcref (ref.func $f0) (ref.func $f0) (ref.func $f0)) (func $f0) (func (export "test") (table.init 0 (i32.const 1) (i64.const 1) (i32.const 1)))) @@ -497,7 +519,7 @@ (assert_invalid (module (table 10 funcref) - (elem passive funcref $f0 $f0 $f0) + (elem funcref (ref.func $f0) (ref.func $f0) (ref.func $f0)) (func $f0) (func (export "test") (table.init 0 (i32.const 1) (i64.const 1) (f32.const 1)))) @@ -506,7 +528,7 @@ (assert_invalid (module (table 10 funcref) - (elem passive funcref $f0 $f0 $f0) + (elem funcref (ref.func $f0) (ref.func $f0) (ref.func $f0)) (func $f0) (func (export "test") (table.init 0 (i32.const 1) (i64.const 1) (i64.const 1)))) @@ -515,7 +537,7 @@ (assert_invalid (module (table 10 funcref) - (elem passive funcref $f0 $f0 $f0) + (elem funcref (ref.func $f0) (ref.func $f0) (ref.func $f0)) (func $f0) (func (export "test") (table.init 0 (i32.const 1) (i64.const 1) (f64.const 1)))) @@ -524,7 +546,7 @@ (assert_invalid (module (table 10 funcref) - (elem passive funcref $f0 $f0 $f0) + (elem funcref (ref.func $f0) (ref.func $f0) (ref.func $f0)) (func $f0) (func (export "test") (table.init 0 (i32.const 1) (f64.const 1) (i32.const 1)))) @@ -533,7 +555,7 @@ (assert_invalid (module (table 10 funcref) - (elem passive funcref $f0 $f0 $f0) + (elem funcref (ref.func $f0) (ref.func $f0) (ref.func $f0)) (func $f0) (func (export "test") (table.init 0 (i32.const 1) (f64.const 1) (f32.const 1)))) @@ -542,7 +564,7 @@ (assert_invalid (module (table 10 funcref) - (elem passive funcref $f0 $f0 $f0) + (elem funcref (ref.func $f0) (ref.func $f0) (ref.func $f0)) (func $f0) (func (export "test") (table.init 0 (i32.const 1) (f64.const 1) (i64.const 1)))) @@ -551,7 +573,7 @@ (assert_invalid (module (table 10 funcref) - (elem passive funcref $f0 $f0 $f0) + (elem funcref (ref.func $f0) (ref.func $f0) (ref.func $f0)) (func $f0) (func (export "test") (table.init 0 (i32.const 1) (f64.const 1) (f64.const 1)))) @@ -560,7 +582,7 @@ (assert_invalid (module (table 10 funcref) - (elem passive funcref $f0 $f0 $f0) + (elem funcref (ref.func $f0) (ref.func $f0) (ref.func $f0)) (func $f0) (func (export "test") (table.init 0 (f32.const 1) (i32.const 1) (i32.const 1)))) @@ -569,7 +591,7 @@ (assert_invalid (module (table 10 funcref) - (elem passive funcref $f0 $f0 $f0) + (elem funcref (ref.func $f0) (ref.func $f0) (ref.func $f0)) (func $f0) (func (export "test") (table.init 0 (f32.const 1) (i32.const 1) (f32.const 1)))) @@ -578,7 +600,7 @@ (assert_invalid (module (table 10 funcref) - (elem passive funcref $f0 $f0 $f0) + (elem funcref (ref.func $f0) (ref.func $f0) (ref.func $f0)) (func $f0) (func (export "test") (table.init 0 (f32.const 1) (i32.const 1) (i64.const 1)))) @@ -587,7 +609,7 @@ (assert_invalid (module (table 10 funcref) - (elem passive funcref $f0 $f0 $f0) + (elem funcref (ref.func $f0) (ref.func $f0) (ref.func $f0)) (func $f0) (func (export "test") (table.init 0 (f32.const 1) (i32.const 1) (f64.const 1)))) @@ -596,7 +618,7 @@ (assert_invalid (module (table 10 funcref) - (elem passive funcref $f0 $f0 $f0) + (elem funcref (ref.func $f0) (ref.func $f0) (ref.func $f0)) (func $f0) (func (export "test") (table.init 0 (f32.const 1) (f32.const 1) (i32.const 1)))) @@ -605,7 +627,7 @@ (assert_invalid (module (table 10 funcref) - (elem passive funcref $f0 $f0 $f0) + (elem funcref (ref.func $f0) (ref.func $f0) (ref.func $f0)) (func $f0) (func (export "test") (table.init 0 (f32.const 1) (f32.const 1) (f32.const 1)))) @@ -614,7 +636,7 @@ (assert_invalid (module (table 10 funcref) - (elem passive funcref $f0 $f0 $f0) + (elem funcref (ref.func $f0) (ref.func $f0) (ref.func $f0)) (func $f0) (func (export "test") (table.init 0 (f32.const 1) (f32.const 1) (i64.const 1)))) @@ -623,7 +645,7 @@ (assert_invalid (module (table 10 funcref) - (elem passive funcref $f0 $f0 $f0) + (elem funcref (ref.func $f0) (ref.func $f0) (ref.func $f0)) (func $f0) (func (export "test") (table.init 0 (f32.const 1) (f32.const 1) (f64.const 1)))) @@ -632,7 +654,7 @@ (assert_invalid (module (table 10 funcref) - (elem passive funcref $f0 $f0 $f0) + (elem funcref (ref.func $f0) (ref.func $f0) (ref.func $f0)) (func $f0) (func (export "test") (table.init 0 (f32.const 1) (i64.const 1) (i32.const 1)))) @@ -641,7 +663,7 @@ (assert_invalid (module (table 10 funcref) - (elem passive funcref $f0 $f0 $f0) + (elem funcref (ref.func $f0) (ref.func $f0) (ref.func $f0)) (func $f0) (func (export "test") (table.init 0 (f32.const 1) (i64.const 1) (f32.const 1)))) @@ -650,7 +672,7 @@ (assert_invalid (module (table 10 funcref) - (elem passive funcref $f0 $f0 $f0) + (elem funcref (ref.func $f0) (ref.func $f0) (ref.func $f0)) (func $f0) (func (export "test") (table.init 0 (f32.const 1) (i64.const 1) (i64.const 1)))) @@ -659,7 +681,7 @@ (assert_invalid (module (table 10 funcref) - (elem passive funcref $f0 $f0 $f0) + (elem funcref (ref.func $f0) (ref.func $f0) (ref.func $f0)) (func $f0) (func (export "test") (table.init 0 (f32.const 1) (i64.const 1) (f64.const 1)))) @@ -668,7 +690,7 @@ (assert_invalid (module (table 10 funcref) - (elem passive funcref $f0 $f0 $f0) + (elem funcref (ref.func $f0) (ref.func $f0) (ref.func $f0)) (func $f0) (func (export "test") (table.init 0 (f32.const 1) (f64.const 1) (i32.const 1)))) @@ -677,7 +699,7 @@ (assert_invalid (module (table 10 funcref) - (elem passive funcref $f0 $f0 $f0) + (elem funcref (ref.func $f0) (ref.func $f0) (ref.func $f0)) (func $f0) (func (export "test") (table.init 0 (f32.const 1) (f64.const 1) (f32.const 1)))) @@ -686,7 +708,7 @@ (assert_invalid (module (table 10 funcref) - (elem passive funcref $f0 $f0 $f0) + (elem funcref (ref.func $f0) (ref.func $f0) (ref.func $f0)) (func $f0) (func (export "test") (table.init 0 (f32.const 1) (f64.const 1) (i64.const 1)))) @@ -695,7 +717,7 @@ (assert_invalid (module (table 10 funcref) - (elem passive funcref $f0 $f0 $f0) + (elem funcref (ref.func $f0) (ref.func $f0) (ref.func $f0)) (func $f0) (func (export "test") (table.init 0 (f32.const 1) (f64.const 1) (f64.const 1)))) @@ -704,7 +726,7 @@ (assert_invalid (module (table 10 funcref) - (elem passive funcref $f0 $f0 $f0) + (elem funcref (ref.func $f0) (ref.func $f0) (ref.func $f0)) (func $f0) (func (export "test") (table.init 0 (i64.const 1) (i32.const 1) (i32.const 1)))) @@ -713,7 +735,7 @@ (assert_invalid (module (table 10 funcref) - (elem passive funcref $f0 $f0 $f0) + (elem funcref (ref.func $f0) (ref.func $f0) (ref.func $f0)) (func $f0) (func (export "test") (table.init 0 (i64.const 1) (i32.const 1) (f32.const 1)))) @@ -722,7 +744,7 @@ (assert_invalid (module (table 10 funcref) - (elem passive funcref $f0 $f0 $f0) + (elem funcref (ref.func $f0) (ref.func $f0) (ref.func $f0)) (func $f0) (func (export "test") (table.init 0 (i64.const 1) (i32.const 1) (i64.const 1)))) @@ -731,7 +753,7 @@ (assert_invalid (module (table 10 funcref) - (elem passive funcref $f0 $f0 $f0) + (elem funcref (ref.func $f0) (ref.func $f0) (ref.func $f0)) (func $f0) (func (export "test") (table.init 0 (i64.const 1) (i32.const 1) (f64.const 1)))) @@ -740,7 +762,7 @@ (assert_invalid (module (table 10 funcref) - (elem passive funcref $f0 $f0 $f0) + (elem funcref (ref.func $f0) (ref.func $f0) (ref.func $f0)) (func $f0) (func (export "test") (table.init 0 (i64.const 1) (f32.const 1) (i32.const 1)))) @@ -749,7 +771,7 @@ (assert_invalid (module (table 10 funcref) - (elem passive funcref $f0 $f0 $f0) + (elem funcref (ref.func $f0) (ref.func $f0) (ref.func $f0)) (func $f0) (func (export "test") (table.init 0 (i64.const 1) (f32.const 1) (f32.const 1)))) @@ -758,7 +780,7 @@ (assert_invalid (module (table 10 funcref) - (elem passive funcref $f0 $f0 $f0) + (elem funcref (ref.func $f0) (ref.func $f0) (ref.func $f0)) (func $f0) (func (export "test") (table.init 0 (i64.const 1) (f32.const 1) (i64.const 1)))) @@ -767,7 +789,7 @@ (assert_invalid (module (table 10 funcref) - (elem passive funcref $f0 $f0 $f0) + (elem funcref (ref.func $f0) (ref.func $f0) (ref.func $f0)) (func $f0) (func (export "test") (table.init 0 (i64.const 1) (f32.const 1) (f64.const 1)))) @@ -776,7 +798,7 @@ (assert_invalid (module (table 10 funcref) - (elem passive funcref $f0 $f0 $f0) + (elem funcref (ref.func $f0) (ref.func $f0) (ref.func $f0)) (func $f0) (func (export "test") (table.init 0 (i64.const 1) (i64.const 1) (i32.const 1)))) @@ -785,7 +807,7 @@ (assert_invalid (module (table 10 funcref) - (elem passive funcref $f0 $f0 $f0) + (elem funcref (ref.func $f0) (ref.func $f0) (ref.func $f0)) (func $f0) (func (export "test") (table.init 0 (i64.const 1) (i64.const 1) (f32.const 1)))) @@ -794,7 +816,7 @@ (assert_invalid (module (table 10 funcref) - (elem passive funcref $f0 $f0 $f0) + (elem funcref (ref.func $f0) (ref.func $f0) (ref.func $f0)) (func $f0) (func (export "test") (table.init 0 (i64.const 1) (i64.const 1) (i64.const 1)))) @@ -803,7 +825,7 @@ (assert_invalid (module (table 10 funcref) - (elem passive funcref $f0 $f0 $f0) + (elem funcref (ref.func $f0) (ref.func $f0) (ref.func $f0)) (func $f0) (func (export "test") (table.init 0 (i64.const 1) (i64.const 1) (f64.const 1)))) @@ -812,7 +834,7 @@ (assert_invalid (module (table 10 funcref) - (elem passive funcref $f0 $f0 $f0) + (elem funcref (ref.func $f0) (ref.func $f0) (ref.func $f0)) (func $f0) (func (export "test") (table.init 0 (i64.const 1) (f64.const 1) (i32.const 1)))) @@ -821,7 +843,7 @@ (assert_invalid (module (table 10 funcref) - (elem passive funcref $f0 $f0 $f0) + (elem funcref (ref.func $f0) (ref.func $f0) (ref.func $f0)) (func $f0) (func (export "test") (table.init 0 (i64.const 1) (f64.const 1) (f32.const 1)))) @@ -830,7 +852,7 @@ (assert_invalid (module (table 10 funcref) - (elem passive funcref $f0 $f0 $f0) + (elem funcref (ref.func $f0) (ref.func $f0) (ref.func $f0)) (func $f0) (func (export "test") (table.init 0 (i64.const 1) (f64.const 1) (i64.const 1)))) @@ -839,7 +861,7 @@ (assert_invalid (module (table 10 funcref) - (elem passive funcref $f0 $f0 $f0) + (elem funcref (ref.func $f0) (ref.func $f0) (ref.func $f0)) (func $f0) (func (export "test") (table.init 0 (i64.const 1) (f64.const 1) (f64.const 1)))) @@ -848,7 +870,7 @@ (assert_invalid (module (table 10 funcref) - (elem passive funcref $f0 $f0 $f0) + (elem funcref (ref.func $f0) (ref.func $f0) (ref.func $f0)) (func $f0) (func (export "test") (table.init 0 (f64.const 1) (i32.const 1) (i32.const 1)))) @@ -857,7 +879,7 @@ (assert_invalid (module (table 10 funcref) - (elem passive funcref $f0 $f0 $f0) + (elem funcref (ref.func $f0) (ref.func $f0) (ref.func $f0)) (func $f0) (func (export "test") (table.init 0 (f64.const 1) (i32.const 1) (f32.const 1)))) @@ -866,7 +888,7 @@ (assert_invalid (module (table 10 funcref) - (elem passive funcref $f0 $f0 $f0) + (elem funcref (ref.func $f0) (ref.func $f0) (ref.func $f0)) (func $f0) (func (export "test") (table.init 0 (f64.const 1) (i32.const 1) (i64.const 1)))) @@ -875,7 +897,7 @@ (assert_invalid (module (table 10 funcref) - (elem passive funcref $f0 $f0 $f0) + (elem funcref (ref.func $f0) (ref.func $f0) (ref.func $f0)) (func $f0) (func (export "test") (table.init 0 (f64.const 1) (i32.const 1) (f64.const 1)))) @@ -884,7 +906,7 @@ (assert_invalid (module (table 10 funcref) - (elem passive funcref $f0 $f0 $f0) + (elem funcref (ref.func $f0) (ref.func $f0) (ref.func $f0)) (func $f0) (func (export "test") (table.init 0 (f64.const 1) (f32.const 1) (i32.const 1)))) @@ -893,7 +915,7 @@ (assert_invalid (module (table 10 funcref) - (elem passive funcref $f0 $f0 $f0) + (elem funcref (ref.func $f0) (ref.func $f0) (ref.func $f0)) (func $f0) (func (export "test") (table.init 0 (f64.const 1) (f32.const 1) (f32.const 1)))) @@ -902,7 +924,7 @@ (assert_invalid (module (table 10 funcref) - (elem passive funcref $f0 $f0 $f0) + (elem funcref (ref.func $f0) (ref.func $f0) (ref.func $f0)) (func $f0) (func (export "test") (table.init 0 (f64.const 1) (f32.const 1) (i64.const 1)))) @@ -911,7 +933,7 @@ (assert_invalid (module (table 10 funcref) - (elem passive funcref $f0 $f0 $f0) + (elem funcref (ref.func $f0) (ref.func $f0) (ref.func $f0)) (func $f0) (func (export "test") (table.init 0 (f64.const 1) (f32.const 1) (f64.const 1)))) @@ -920,7 +942,7 @@ (assert_invalid (module (table 10 funcref) - (elem passive funcref $f0 $f0 $f0) + (elem funcref (ref.func $f0) (ref.func $f0) (ref.func $f0)) (func $f0) (func (export "test") (table.init 0 (f64.const 1) (i64.const 1) (i32.const 1)))) @@ -929,7 +951,7 @@ (assert_invalid (module (table 10 funcref) - (elem passive funcref $f0 $f0 $f0) + (elem funcref (ref.func $f0) (ref.func $f0) (ref.func $f0)) (func $f0) (func (export "test") (table.init 0 (f64.const 1) (i64.const 1) (f32.const 1)))) @@ -938,7 +960,7 @@ (assert_invalid (module (table 10 funcref) - (elem passive funcref $f0 $f0 $f0) + (elem funcref (ref.func $f0) (ref.func $f0) (ref.func $f0)) (func $f0) (func (export "test") (table.init 0 (f64.const 1) (i64.const 1) (i64.const 1)))) @@ -947,7 +969,7 @@ (assert_invalid (module (table 10 funcref) - (elem passive funcref $f0 $f0 $f0) + (elem funcref (ref.func $f0) (ref.func $f0) (ref.func $f0)) (func $f0) (func (export "test") (table.init 0 (f64.const 1) (i64.const 1) (f64.const 1)))) @@ -956,7 +978,7 @@ (assert_invalid (module (table 10 funcref) - (elem passive funcref $f0 $f0 $f0) + (elem funcref (ref.func $f0) (ref.func $f0) (ref.func $f0)) (func $f0) (func (export "test") (table.init 0 (f64.const 1) (f64.const 1) (i32.const 1)))) @@ -965,7 +987,7 @@ (assert_invalid (module (table 10 funcref) - (elem passive funcref $f0 $f0 $f0) + (elem funcref (ref.func $f0) (ref.func $f0) (ref.func $f0)) (func $f0) (func (export "test") (table.init 0 (f64.const 1) (f64.const 1) (f32.const 1)))) @@ -974,7 +996,7 @@ (assert_invalid (module (table 10 funcref) - (elem passive funcref $f0 $f0 $f0) + (elem funcref (ref.func $f0) (ref.func $f0) (ref.func $f0)) (func $f0) (func (export "test") (table.init 0 (f64.const 1) (f64.const 1) (i64.const 1)))) @@ -983,7 +1005,7 @@ (assert_invalid (module (table 10 funcref) - (elem passive funcref $f0 $f0 $f0) + (elem funcref (ref.func $f0) (ref.func $f0) (ref.func $f0)) (func $f0) (func (export "test") (table.init 0 (f64.const 1) (f64.const 1) (f64.const 1)))) @@ -992,7 +1014,11 @@ (module (type (func (result i32))) (table 32 64 funcref) - (elem passive funcref $f0 $f1 $f2 $f3 $f4 $f5 $f6 $f7 $f8 $f9 $f10 $f11 $f12 $f13 $f14 $f15) + (elem funcref + (ref.func $f0) (ref.func $f1) (ref.func $f2) (ref.func $f3) + (ref.func $f4) (ref.func $f5) (ref.func $f6) (ref.func $f7) + (ref.func $f8) (ref.func $f9) (ref.func $f10) (ref.func $f11) + (ref.func $f12) (ref.func $f13) (ref.func $f14) (ref.func $f15)) (func $f0 (export "f0") (result i32) (i32.const 0)) (func $f1 (export "f1") (result i32) (i32.const 1)) (func $f2 (export "f2") (result i32) (i32.const 2)) @@ -1050,7 +1076,11 @@ (module (type (func (result i32))) (table 32 64 funcref) - (elem passive funcref $f0 $f1 $f2 $f3 $f4 $f5 $f6 $f7 $f8 $f9 $f10 $f11 $f12 $f13 $f14 $f15) + (elem funcref + (ref.func $f0) (ref.func $f1) (ref.func $f2) (ref.func $f3) + (ref.func $f4) (ref.func $f5) (ref.func $f6) (ref.func $f7) + (ref.func $f8) (ref.func $f9) (ref.func $f10) (ref.func $f11) + (ref.func $f12) (ref.func $f13) (ref.func $f14) (ref.func $f15)) (func $f0 (export "f0") (result i32) (i32.const 0)) (func $f1 (export "f1") (result i32) (i32.const 1)) (func $f2 (export "f2") (result i32) (i32.const 2)) @@ -1108,7 +1138,11 @@ (module (type (func (result i32))) (table 160 320 funcref) - (elem passive funcref $f0 $f1 $f2 $f3 $f4 $f5 $f6 $f7 $f8 $f9 $f10 $f11 $f12 $f13 $f14 $f15) + (elem funcref + (ref.func $f0) (ref.func $f1) (ref.func $f2) (ref.func $f3) + (ref.func $f4) (ref.func $f5) (ref.func $f6) (ref.func $f7) + (ref.func $f8) (ref.func $f9) (ref.func $f10) (ref.func $f11) + (ref.func $f12) (ref.func $f13) (ref.func $f14) (ref.func $f15)) (func $f0 (export "f0") (result i32) (i32.const 0)) (func $f1 (export "f1") (result i32) (i32.const 1)) (func $f2 (export "f2") (result i32) (i32.const 2)) @@ -1294,7 +1328,11 @@ (module (type (func (result i32))) (table 160 320 funcref) - (elem passive funcref $f0 $f1 $f2 $f3 $f4 $f5 $f6 $f7 $f8 $f9 $f10 $f11 $f12 $f13 $f14 $f15) + (elem funcref + (ref.func $f0) (ref.func $f1) (ref.func $f2) (ref.func $f3) + (ref.func $f4) (ref.func $f5) (ref.func $f6) (ref.func $f7) + (ref.func $f8) (ref.func $f9) (ref.func $f10) (ref.func $f11) + (ref.func $f12) (ref.func $f13) (ref.func $f14) (ref.func $f15)) (func $f0 (export "f0") (result i32) (i32.const 0)) (func $f1 (export "f1") (result i32) (i32.const 1)) (func $f2 (export "f2") (result i32) (i32.const 2)) @@ -1480,7 +1518,11 @@ (module (type (func (result i32))) (table 64 64 funcref) - (elem passive funcref $f0 $f1 $f2 $f3 $f4 $f5 $f6 $f7 $f8 $f9 $f10 $f11 $f12 $f13 $f14 $f15) + (elem funcref + (ref.func $f0) (ref.func $f1) (ref.func $f2) (ref.func $f3) + (ref.func $f4) (ref.func $f5) (ref.func $f6) (ref.func $f7) + (ref.func $f8) (ref.func $f9) (ref.func $f10) (ref.func $f11) + (ref.func $f12) (ref.func $f13) (ref.func $f14) (ref.func $f15)) (func $f0 (export "f0") (result i32) (i32.const 0)) (func $f1 (export "f1") (result i32) (i32.const 1)) (func $f2 (export "f2") (result i32) (i32.const 2)) @@ -1570,7 +1612,11 @@ (module (type (func (result i32))) (table 16 16 funcref) - (elem passive funcref $f0 $f1 $f2 $f3 $f4 $f5 $f6 $f7 $f8 $f9 $f10 $f11 $f12 $f13 $f14 $f15) + (elem funcref + (ref.func $f0) (ref.func $f1) (ref.func $f2) (ref.func $f3) + (ref.func $f4) (ref.func $f5) (ref.func $f6) (ref.func $f7) + (ref.func $f8) (ref.func $f9) (ref.func $f10) (ref.func $f11) + (ref.func $f12) (ref.func $f13) (ref.func $f14) (ref.func $f15)) (func $f0 (export "f0") (result i32) (i32.const 0)) (func $f1 (export "f1") (result i32) (i32.const 1)) (func $f2 (export "f2") (result i32) (i32.const 2)) From 08be05ad92808714c9c0ca994f7e09971aeb0abd Mon Sep 17 00:00:00 2001 From: Dan Gohman Date: Mon, 13 May 2019 11:42:24 -0700 Subject: [PATCH 093/199] Init/copy/fill with offsets at the end of the memory or table (#86) * Fix expected trap messages. The spec interpreter says "element segment dropped", rather than "elements segment dropped". * Fix "zero len, but dst offset out of bounds" test. Fix this test to test what it's comment says it's testing. * Add more tests for zero-length operations. * Update the Overview text to reflect the zero-length at-the-end semantics. --- proposals/bulk-memory-operations/Overview.md | 10 +-- test/core/memory_copy.wast | 18 ++++++ test/core/memory_fill.wast | 18 ++++++ test/core/memory_init.wast | 23 ++++++- test/core/table_copy.wast | 66 ++++++++++++++++++++ test/core/table_init.wast | 63 +++++++++++++++++++ test/meta/generate_memory_copy.js | 27 ++++++++ test/meta/generate_memory_fill.js | 9 +++ test/meta/generate_memory_init.js | 33 +++++++++- test/meta/generate_table_copy.js | 15 +++++ test/meta/generate_table_init.js | 23 +++++-- 11 files changed, 292 insertions(+), 13 deletions(-) diff --git a/proposals/bulk-memory-operations/Overview.md b/proposals/bulk-memory-operations/Overview.md index 8f2ff08fb9..2955afef31 100644 --- a/proposals/bulk-memory-operations/Overview.md +++ b/proposals/bulk-memory-operations/Overview.md @@ -277,8 +277,8 @@ A trap occurs if: active segments that were dropped after being copied into memory during module instantiation. * any of the accessed bytes lies outside the source data segment or the target memory -* the source offset is outside the source data segment -* the destination offset is outside the target memory +* the source offset is greater than the length of the source data segment +* the destination offset is greater than the length of the target memory Note that it is allowed to use `memory.init` on the same data segment more than once. @@ -342,8 +342,8 @@ The instruction has the signature `[i32 i32 i32] -> []`. The parameters are, in A trap occurs if: * any of the accessed bytes lies outside the source or target memory -* the source offset is outside the source memory -* the destination offset is outside the target memory +* the source offset is greater than the length of the source memory +* the destination offset is greater than the length of the target memory A trap resulting from an access outside the source or target region only occurs once the first byte that is outside the source or target @@ -367,7 +367,7 @@ The instruction has the signature `[i32 i32 i32] -> []`. The parameters are, in A trap occurs if: * any of the accessed bytes lies outside the target memory -* the destination offset is outside the target memory +* the destination offset is greater than the length of the target memory Filling takes place bytewise from lower addresses toward higher addresses. A trap resulting from an access outside the target memory diff --git a/test/core/memory_copy.wast b/test/core/memory_copy.wast index b5f25c009b..46b26a875c 100644 --- a/test/core/memory_copy.wast +++ b/test/core/memory_copy.wast @@ -4997,12 +4997,30 @@ (memory.copy (i32.const 0x10000) (i32.const 0x7000) (i32.const 0)))) (invoke "test") +(module + (memory 1 1) + (func (export "test") + (memory.copy (i32.const 0x20000) (i32.const 0x7000) (i32.const 0)))) +(assert_trap (invoke "test") "out of bounds") + (module (memory 1 1) (func (export "test") (memory.copy (i32.const 0x9000) (i32.const 0x10000) (i32.const 0)))) (invoke "test") +(module + (memory 1 1) + (func (export "test") + (memory.copy (i32.const 0x9000) (i32.const 0x20000) (i32.const 0)))) +(assert_trap (invoke "test") "out of bounds") + +(module + (memory 1 1) + (func (export "test") + (memory.copy (i32.const 0x10000) (i32.const 0x10000) (i32.const 0)))) +(invoke "test") + (module (memory 1 1) (func (export "test") diff --git a/test/core/memory_fill.wast b/test/core/memory_fill.wast index 8cc21af317..9af6b2459a 100644 --- a/test/core/memory_fill.wast +++ b/test/core/memory_fill.wast @@ -98,6 +98,24 @@ (memory.fill (i32.const 0x10000) (i32.const 0x55) (i32.const 0)))) (invoke "test") +(module + (memory 1 1) + + (func (export "checkRange") (param $from i32) (param $to i32) (param $expected i32) (result i32) + (loop $cont + (if (i32.eq (local.get $from) (local.get $to)) + (then + (return (i32.const -1)))) + (if (i32.eq (i32.load8_u (local.get $from)) (local.get $expected)) + (then + (local.set $from (i32.add (local.get $from) (i32.const 1))) + (br $cont)))) + (return (local.get $from))) + + (func (export "test") + (memory.fill (i32.const 0x20000) (i32.const 0x55) (i32.const 0)))) +(assert_trap (invoke "test") "out of bounds memory access") + (module (memory 1 1) diff --git a/test/core/memory_init.wast b/test/core/memory_init.wast index 4f1a0430e9..fb432a3da0 100644 --- a/test/core/memory_init.wast +++ b/test/core/memory_init.wast @@ -276,9 +276,30 @@ (memory 1) (data "\37") (func (export "test") - (memory.init 0 (i32.const 0x10000) (i32.const 2) (i32.const 0)))) + (memory.init 0 (i32.const 1234) (i32.const 1) (i32.const 0)))) +(invoke "test") + +(module + (memory 1) + (data passive "\37") + (func (export "test") + (memory.init 0 (i32.const 0x10001) (i32.const 0) (i32.const 0)))) (assert_trap (invoke "test") "out of bounds") +(module + (memory 1) + (data passive "\37") + (func (export "test") + (memory.init 0 (i32.const 0x10000) (i32.const 0) (i32.const 0)))) +(invoke "test") + +(module + (memory 1) + (data passive "\37") + (func (export "test") + (memory.init 0 (i32.const 0x10000) (i32.const 1) (i32.const 0)))) +(invoke "test") + (assert_invalid (module (memory 1) diff --git a/test/core/table_copy.wast b/test/core/table_copy.wast index 69158060c5..d8e66426a2 100644 --- a/test/core/table_copy.wast +++ b/test/core/table_copy.wast @@ -625,12 +625,78 @@ (func (result i32) (i32.const 7)) (func (result i32) (i32.const 8)) (func (result i32) (i32.const 9)) + (func (export "test") + (table.copy (i32.const 31) (i32.const 15) (i32.const 0)) + )) + +(assert_trap (invoke "test") "out of bounds") + +(module + (table 30 30 funcref) + (elem (i32.const 2) 3 1 4 1) + (elem passive funcref 2 7 1 8) + (elem (i32.const 12) 7 5 2 3 6) + (elem passive funcref 5 9 2 7 6) + (func (result i32) (i32.const 0)) + (func (result i32) (i32.const 1)) + (func (result i32) (i32.const 2)) + (func (result i32) (i32.const 3)) + (func (result i32) (i32.const 4)) + (func (result i32) (i32.const 5)) + (func (result i32) (i32.const 6)) + (func (result i32) (i32.const 7)) + (func (result i32) (i32.const 8)) + (func (result i32) (i32.const 9)) (func (export "test") (table.copy (i32.const 15) (i32.const 30) (i32.const 0)) )) (invoke "test") +(module + (table 30 30 funcref) + (elem (i32.const 2) 3 1 4 1) + (elem passive funcref 2 7 1 8) + (elem (i32.const 12) 7 5 2 3 6) + (elem passive funcref 5 9 2 7 6) + (func (result i32) (i32.const 0)) + (func (result i32) (i32.const 1)) + (func (result i32) (i32.const 2)) + (func (result i32) (i32.const 3)) + (func (result i32) (i32.const 4)) + (func (result i32) (i32.const 5)) + (func (result i32) (i32.const 6)) + (func (result i32) (i32.const 7)) + (func (result i32) (i32.const 8)) + (func (result i32) (i32.const 9)) + (func (export "test") + (table.copy (i32.const 15) (i32.const 31) (i32.const 0)) + )) + +(assert_trap (invoke "test") "out of bounds") + +(module + (table 30 30 funcref) + (elem (i32.const 2) 3 1 4 1) + (elem passive funcref 2 7 1 8) + (elem (i32.const 12) 7 5 2 3 6) + (elem passive funcref 5 9 2 7 6) + (func (result i32) (i32.const 0)) + (func (result i32) (i32.const 1)) + (func (result i32) (i32.const 2)) + (func (result i32) (i32.const 3)) + (func (result i32) (i32.const 4)) + (func (result i32) (i32.const 5)) + (func (result i32) (i32.const 6)) + (func (result i32) (i32.const 7)) + (func (result i32) (i32.const 8)) + (func (result i32) (i32.const 9)) + (func (export "test") + (table.copy (i32.const 30) (i32.const 30) (i32.const 0)) + )) + +(invoke "test") + (module (type (func (result i32))) (table 32 64 funcref) diff --git a/test/core/table_init.wast b/test/core/table_init.wast index 82dc63daa7..5e80a0a81f 100644 --- a/test/core/table_init.wast +++ b/test/core/table_init.wast @@ -439,11 +439,74 @@ (func (result i32) (i32.const 7)) (func (result i32) (i32.const 8)) (func (result i32) (i32.const 9)) + (func (export "test") + (table.init 1 (i32.const 12) (i32.const 5) (i32.const 0)) + )) +(assert_trap (invoke "test") "out of bounds") + +(module + (table 30 30 funcref) + (elem (i32.const 2) 3 1 4 1) + (elem passive funcref 2 7 1 8) + (elem (i32.const 12) 7 5 2 3 6) + (elem passive funcref 5 9 2 7 6) + (func (result i32) (i32.const 0)) + (func (result i32) (i32.const 1)) + (func (result i32) (i32.const 2)) + (func (result i32) (i32.const 3)) + (func (result i32) (i32.const 4)) + (func (result i32) (i32.const 5)) + (func (result i32) (i32.const 6)) + (func (result i32) (i32.const 7)) + (func (result i32) (i32.const 8)) + (func (result i32) (i32.const 9)) (func (export "test") (table.init 1 (i32.const 30) (i32.const 2) (i32.const 0)) )) (invoke "test") +(module + (table 30 30 funcref) + (elem (i32.const 2) 3 1 4 1) + (elem passive funcref 2 7 1 8) + (elem (i32.const 12) 7 5 2 3 6) + (elem passive funcref 5 9 2 7 6) + (func (result i32) (i32.const 0)) + (func (result i32) (i32.const 1)) + (func (result i32) (i32.const 2)) + (func (result i32) (i32.const 3)) + (func (result i32) (i32.const 4)) + (func (result i32) (i32.const 5)) + (func (result i32) (i32.const 6)) + (func (result i32) (i32.const 7)) + (func (result i32) (i32.const 8)) + (func (result i32) (i32.const 9)) + (func (export "test") + (table.init 1 (i32.const 31) (i32.const 2) (i32.const 0)) + )) +(assert_trap (invoke "test") "out of bounds") + +(module + (table 30 30 funcref) + (elem (i32.const 2) 3 1 4 1) + (elem passive funcref 2 7 1 8) + (elem (i32.const 12) 7 5 2 3 6) + (elem passive funcref 5 9 2 7 6) + (func (result i32) (i32.const 0)) + (func (result i32) (i32.const 1)) + (func (result i32) (i32.const 2)) + (func (result i32) (i32.const 3)) + (func (result i32) (i32.const 4)) + (func (result i32) (i32.const 5)) + (func (result i32) (i32.const 6)) + (func (result i32) (i32.const 7)) + (func (result i32) (i32.const 8)) + (func (result i32) (i32.const 9)) + (func (export "test") + (table.init 1 (i32.const 30) (i32.const 4) (i32.const 0)) + )) +(invoke "test") + (assert_invalid (module (table 10 funcref) diff --git a/test/meta/generate_memory_copy.js b/test/meta/generate_memory_copy.js index 1ccbc6545b..2cb26cd613 100644 --- a/test/meta/generate_memory_copy.js +++ b/test/meta/generate_memory_copy.js @@ -304,6 +304,15 @@ print( (invoke "test") `); +// Zero len with dest offset out-of-bounds past the end of memory is not allowed +print( +`(module + (memory 1 1) + (func (export "test") + (memory.copy (i32.const 0x20000) (i32.const 0x7000) (i32.const 0)))) +(assert_trap (invoke "test") "out of bounds") +`); + // Zero len with src offset out-of-bounds at the end of memory is allowed print( `(module @@ -313,6 +322,24 @@ print( (invoke "test") `); +// Zero len with src offset out-of-bounds past the end of memory is not allowed +print( +`(module + (memory 1 1) + (func (export "test") + (memory.copy (i32.const 0x9000) (i32.const 0x20000) (i32.const 0)))) +(assert_trap (invoke "test") "out of bounds") +`); + +// Zero len with both dest and src offsets out-of-bounds at the end of memory is allowed +print( +`(module + (memory 1 1) + (func (export "test") + (memory.copy (i32.const 0x10000) (i32.const 0x10000) (i32.const 0)))) +(invoke "test") +`); + // 100 random fills followed by 100 random copies, in a single-page buffer, // followed by verification of the (now heavily mashed-around) buffer. print( diff --git a/test/meta/generate_memory_fill.js b/test/meta/generate_memory_fill.js index 9ba90b2869..42c2e196e5 100644 --- a/test/meta/generate_memory_fill.js +++ b/test/meta/generate_memory_fill.js @@ -56,6 +56,15 @@ print( (invoke "test") `); +// Zero len with offset out-of-bounds past the end of memory is not allowed +print( +`(module + ${PREAMBLE} + (func (export "test") + (memory.fill (i32.const 0x20000) (i32.const 0x55) (i32.const 0)))) +(assert_trap (invoke "test") "out of bounds memory access") +`); + // Very large range print( `(module diff --git a/test/meta/generate_memory_init.js b/test/meta/generate_memory_init.js index a2e47315ee..ab6c7699b0 100644 --- a/test/meta/generate_memory_init.js +++ b/test/meta/generate_memory_init.js @@ -164,7 +164,7 @@ print( (assert_trap (invoke "test") "out of bounds") `); -// init: seg ix is valid passive, zero len, but src offset out of bounds +// init: seg ix is valid passive, zero len, but src offset past the end print( `(module ${PREAMBLE} @@ -173,15 +173,42 @@ print( (assert_trap (invoke "test") "out of bounds") `); -// init: seg ix is valid passive, zero len, but dst offset out of bounds +// init: seg ix is valid passive, zero len, src offset at the end print( `(module ${PREAMBLE} (func (export "test") - (memory.init 0 (i32.const 0x10000) (i32.const 2) (i32.const 0)))) + (memory.init 0 (i32.const 1234) (i32.const 1) (i32.const 0)))) +(invoke "test") +`); + +// init: seg ix is valid passive, zero len, but dst offset past the end +print( +`(module + ${PREAMBLE} + (func (export "test") + (memory.init 0 (i32.const 0x10001) (i32.const 0) (i32.const 0)))) (assert_trap (invoke "test") "out of bounds") `); +// init: seg ix is valid passive, zero len, but dst offset at the end +print( +`(module + ${PREAMBLE} + (func (export "test") + (memory.init 0 (i32.const 0x10000) (i32.const 0) (i32.const 0)))) +(invoke "test") +`); + +// init: seg ix is valid passive, zero len, dst and src offsets at the end +print( +`(module + ${PREAMBLE} + (func (export "test") + (memory.init 0 (i32.const 0x10000) (i32.const 1) (i32.const 0)))) +(invoke "test") +`); + // invalid argument types. TODO: can add anyfunc etc here. { const tys = ['i32', 'f32', 'i64', 'f64']; diff --git a/test/meta/generate_table_copy.js b/test/meta/generate_table_copy.js index 9058281b6d..e91d1d1e40 100644 --- a/test/meta/generate_table_copy.js +++ b/test/meta/generate_table_copy.js @@ -185,11 +185,26 @@ tab_test2("(table.copy (i32.const 30) (i32.const 15) (i32.const 0))", "", undefined); +// copy: zero length with dst offset out of bounds past the end of the table is not allowed +tab_test2("(table.copy (i32.const 31) (i32.const 15) (i32.const 0))", + "", + "out of bounds"); + // copy: zero length with src offset out of bounds at the end of the table is allowed tab_test2("(table.copy (i32.const 15) (i32.const 30) (i32.const 0))", "", undefined); +// copy: zero length with src offset out of bounds past the end of the table is not allowed +tab_test2("(table.copy (i32.const 15) (i32.const 31) (i32.const 0))", + "", + "out of bounds"); + +// copy: zero length with both dst and src offset out of bounds at the end of the table is allowed +tab_test2("(table.copy (i32.const 30) (i32.const 30) (i32.const 0))", + "", + undefined); + // table.copy: out of bounds of the table for the source or target, but should // perform the operation up to the appropriate bound. Major cases: // diff --git a/test/meta/generate_table_init.js b/test/meta/generate_table_init.js index bfac8ae5d2..2ce82c21ab 100644 --- a/test/meta/generate_table_init.js +++ b/test/meta/generate_table_init.js @@ -183,11 +183,11 @@ function tab_test_nofail(insn1, insn2) { // drop with elem seg ix indicating an active segment tab_test1("(elem.drop 2)", - "elements segment dropped"); + "element segment dropped"); // init with elem seg ix indicating an active segment tab_test1("(table.init 2 (i32.const 12) (i32.const 1) (i32.const 1))", - "elements segment dropped"); + "element segment dropped"); // init, using an elem seg ix more than once is OK tab_test_nofail( @@ -197,12 +197,12 @@ tab_test_nofail( // drop, then drop tab_test2("(elem.drop 1)", "(elem.drop 1)", - "elements segment dropped"); + "element segment dropped"); // drop, then init tab_test2("(elem.drop 1)", "(table.init 1 (i32.const 12) (i32.const 1) (i32.const 1))", - "elements segment dropped"); + "element segment dropped"); // init: seg ix is valid passive, but length to copy > len of seg tab_test1("(table.init 1 (i32.const 12) (i32.const 0) (i32.const 5))", @@ -221,11 +221,26 @@ tab_test1("(table.init 1 (i32.const 28) (i32.const 1) (i32.const 3))", tab_test1("(table.init 1 (i32.const 12) (i32.const 4) (i32.const 0))", undefined); +// init: seg ix is valid passive, zero len, and src offset out of bounds past the +// end of the table - this is not allowed +tab_test1("(table.init 1 (i32.const 12) (i32.const 5) (i32.const 0))", + "out of bounds"); + // init: seg ix is valid passive, zero len, and dst offset out of bounds at the // end of the table - this is allowed tab_test1("(table.init 1 (i32.const 30) (i32.const 2) (i32.const 0))", undefined); +// init: seg ix is valid passive, zero len, and dst offset out of bounds past the +// end of the table - this is not allowed +tab_test1("(table.init 1 (i32.const 31) (i32.const 2) (i32.const 0))", + "out of bounds"); + +// init: seg ix is valid passive, zero len, and dst and src offsets out of bounds +// at the end of the table - this is allowed +tab_test1("(table.init 1 (i32.const 30) (i32.const 4) (i32.const 0))", + undefined); + // invalid argument types { const tys = ['i32', 'f32', 'i64', 'f64']; From e2e3383a13150ac8432d3d0b392ca33b93dd81d4 Mon Sep 17 00:00:00 2001 From: Ben Smith Date: Mon, 13 May 2019 12:11:26 -0700 Subject: [PATCH 094/199] Fix merge conflicts introduced w/ PRs #84 and #86 (#87) Change the test generators to use `ref.func` and remove `passive`. At some point we'll want to remove the generators, but for let's try to maintain them. --- test/core/memory_init.wast | 6 +++--- test/core/table_copy.wast | 22 ++++++++++++++++------ test/core/table_init.wast | 22 ++++++++++++++++------ test/meta/generate_memory_init.js | 8 ++++---- test/meta/generate_table_copy.js | 12 ++++++++---- test/meta/generate_table_init.js | 24 ++++++++++++++++-------- 6 files changed, 63 insertions(+), 31 deletions(-) diff --git a/test/core/memory_init.wast b/test/core/memory_init.wast index fb432a3da0..ee2ed36e09 100644 --- a/test/core/memory_init.wast +++ b/test/core/memory_init.wast @@ -281,21 +281,21 @@ (module (memory 1) - (data passive "\37") + (data "\37") (func (export "test") (memory.init 0 (i32.const 0x10001) (i32.const 0) (i32.const 0)))) (assert_trap (invoke "test") "out of bounds") (module (memory 1) - (data passive "\37") + (data "\37") (func (export "test") (memory.init 0 (i32.const 0x10000) (i32.const 0) (i32.const 0)))) (invoke "test") (module (memory 1) - (data passive "\37") + (data "\37") (func (export "test") (memory.init 0 (i32.const 0x10000) (i32.const 1) (i32.const 0)))) (invoke "test") diff --git a/test/core/table_copy.wast b/test/core/table_copy.wast index d8e66426a2..a68c9c7893 100644 --- a/test/core/table_copy.wast +++ b/test/core/table_copy.wast @@ -1,3 +1,7 @@ +;; +;; Generated by ../meta/generate_table_copy.js +;; + (module (func (export "ef0") (result i32) (i32.const 0)) (func (export "ef1") (result i32) (i32.const 1)) @@ -634,9 +638,11 @@ (module (table 30 30 funcref) (elem (i32.const 2) 3 1 4 1) - (elem passive funcref 2 7 1 8) + (elem funcref + (ref.func 2) (ref.func 7) (ref.func 1) (ref.func 8)) (elem (i32.const 12) 7 5 2 3 6) - (elem passive funcref 5 9 2 7 6) + (elem funcref + (ref.func 5) (ref.func 9) (ref.func 2) (ref.func 7) (ref.func 6)) (func (result i32) (i32.const 0)) (func (result i32) (i32.const 1)) (func (result i32) (i32.const 2)) @@ -656,9 +662,11 @@ (module (table 30 30 funcref) (elem (i32.const 2) 3 1 4 1) - (elem passive funcref 2 7 1 8) + (elem funcref + (ref.func 2) (ref.func 7) (ref.func 1) (ref.func 8)) (elem (i32.const 12) 7 5 2 3 6) - (elem passive funcref 5 9 2 7 6) + (elem funcref + (ref.func 5) (ref.func 9) (ref.func 2) (ref.func 7) (ref.func 6)) (func (result i32) (i32.const 0)) (func (result i32) (i32.const 1)) (func (result i32) (i32.const 2)) @@ -678,9 +686,11 @@ (module (table 30 30 funcref) (elem (i32.const 2) 3 1 4 1) - (elem passive funcref 2 7 1 8) + (elem funcref + (ref.func 2) (ref.func 7) (ref.func 1) (ref.func 8)) (elem (i32.const 12) 7 5 2 3 6) - (elem passive funcref 5 9 2 7 6) + (elem funcref + (ref.func 5) (ref.func 9) (ref.func 2) (ref.func 7) (ref.func 6)) (func (result i32) (i32.const 0)) (func (result i32) (i32.const 1)) (func (result i32) (i32.const 2)) diff --git a/test/core/table_init.wast b/test/core/table_init.wast index 5e80a0a81f..36834d283c 100644 --- a/test/core/table_init.wast +++ b/test/core/table_init.wast @@ -1,3 +1,7 @@ +;; +;; Generated by ../meta/generate_table_init.js +;; + (module (func (export "ef0") (result i32) (i32.const 0)) (func (export "ef1") (result i32) (i32.const 1)) @@ -447,9 +451,11 @@ (module (table 30 30 funcref) (elem (i32.const 2) 3 1 4 1) - (elem passive funcref 2 7 1 8) + (elem funcref + (ref.func 2) (ref.func 7) (ref.func 1) (ref.func 8)) (elem (i32.const 12) 7 5 2 3 6) - (elem passive funcref 5 9 2 7 6) + (elem funcref + (ref.func 5) (ref.func 9) (ref.func 2) (ref.func 7) (ref.func 6)) (func (result i32) (i32.const 0)) (func (result i32) (i32.const 1)) (func (result i32) (i32.const 2)) @@ -468,9 +474,11 @@ (module (table 30 30 funcref) (elem (i32.const 2) 3 1 4 1) - (elem passive funcref 2 7 1 8) + (elem funcref + (ref.func 2) (ref.func 7) (ref.func 1) (ref.func 8)) (elem (i32.const 12) 7 5 2 3 6) - (elem passive funcref 5 9 2 7 6) + (elem funcref + (ref.func 5) (ref.func 9) (ref.func 2) (ref.func 7) (ref.func 6)) (func (result i32) (i32.const 0)) (func (result i32) (i32.const 1)) (func (result i32) (i32.const 2)) @@ -489,9 +497,11 @@ (module (table 30 30 funcref) (elem (i32.const 2) 3 1 4 1) - (elem passive funcref 2 7 1 8) + (elem funcref + (ref.func 2) (ref.func 7) (ref.func 1) (ref.func 8)) (elem (i32.const 12) 7 5 2 3 6) - (elem passive funcref 5 9 2 7 6) + (elem funcref + (ref.func 5) (ref.func 9) (ref.func 2) (ref.func 7) (ref.func 6)) (func (result i32) (i32.const 0)) (func (result i32) (i32.const 1)) (func (result i32) (i32.const 2)) diff --git a/test/meta/generate_memory_init.js b/test/meta/generate_memory_init.js index ab6c7699b0..c157d7d2e6 100644 --- a/test/meta/generate_memory_init.js +++ b/test/meta/generate_memory_init.js @@ -11,9 +11,9 @@ function mem_test(instruction, expected_result_vector) { (module (memory (export "memory0") 1 1) (data (i32.const 2) "\\03\\01\\04\\01") - (data passive "\\02\\07\\01\\08") + (data "\\02\\07\\01\\08") (data (i32.const 12) "\\07\\05\\02\\03\\06") - (data passive "\\05\\09\\02\\07\\06") + (data "\\05\\09\\02\\07\\06") (func (export "test") ${instruction}) (func (export "load8_u") (param i32) (result i32) @@ -57,7 +57,7 @@ mem_test(`(memory.init 1 (i32.const 7) (i32.const 0) (i32.const 4)) let PREAMBLE = `(memory 1) - (data passive "\\37")`; + (data "\\37")`; // drop with no memory print( @@ -242,7 +242,7 @@ function mem_init(min, max, shared, backup, write) { print( `(module (memory ${min} ${max} ${shared}) - (data passive "\\42\\42\\42\\42\\42\\42\\42\\42\\42\\42\\42\\42\\42\\42\\42\\42") + (data "\\42\\42\\42\\42\\42\\42\\42\\42\\42\\42\\42\\42\\42\\42\\42\\42") ${checkRangeCode()} (func (export "run") (param $offs i32) (param $len i32) (memory.init 0 (local.get $offs) (i32.const 0) (local.get $len)))) diff --git a/test/meta/generate_table_copy.js b/test/meta/generate_table_copy.js index e91d1d1e40..ba2636c4a1 100644 --- a/test/meta/generate_table_copy.js +++ b/test/meta/generate_table_copy.js @@ -38,9 +38,11 @@ function emit_b(insn) { (import "a" "ef4" (func (result i32))) ;; index 4 (table 30 30 funcref) (elem (i32.const 2) 3 1 4 1) - (elem passive funcref 2 7 1 8) + (elem funcref + (ref.func 2) (ref.func 7) (ref.func 1) (ref.func 8)) (elem (i32.const 12) 7 5 2 3 6) - (elem passive funcref 5 9 2 7 6) + (elem funcref + (ref.func 5) (ref.func 9) (ref.func 2) (ref.func 7) (ref.func 6)) (func (result i32) (i32.const 5)) ;; index 5 (func (result i32) (i32.const 6)) (func (result i32) (i32.const 7)) @@ -119,9 +121,11 @@ function do_test(insn1, insn2, errText) (module (table 30 30 funcref) (elem (i32.const 2) 3 1 4 1) - (elem passive funcref 2 7 1 8) + (elem funcref + (ref.func 2) (ref.func 7) (ref.func 1) (ref.func 8)) (elem (i32.const 12) 7 5 2 3 6) - (elem passive funcref 5 9 2 7 6) + (elem funcref + (ref.func 5) (ref.func 9) (ref.func 2) (ref.func 7) (ref.func 6)) (func (result i32) (i32.const 0)) (func (result i32) (i32.const 1)) (func (result i32) (i32.const 2)) diff --git a/test/meta/generate_table_init.js b/test/meta/generate_table_init.js index 2ce82c21ab..436dc1e755 100644 --- a/test/meta/generate_table_init.js +++ b/test/meta/generate_table_init.js @@ -38,9 +38,11 @@ function emit_b(insn) { (import "a" "ef4" (func (result i32))) ;; index 4 (table 30 30 funcref) (elem (i32.const 2) 3 1 4 1) - (elem passive funcref 2 7 1 8) + (elem funcref + (ref.func 2) (ref.func 7) (ref.func 1) (ref.func 8)) (elem (i32.const 12) 7 5 2 3 6) - (elem passive funcref 5 9 2 7 6) + (elem funcref + (ref.func 5) (ref.func 9) (ref.func 2) (ref.func 7) (ref.func 6)) (func (result i32) (i32.const 5)) ;; index 5 (func (result i32) (i32.const 6)) (func (result i32) (i32.const 7)) @@ -121,7 +123,7 @@ print( print( `(assert_invalid (module - (elem passive funcref 0) + (elem funcref (ref.func 0)) (func (result i32) (i32.const 0)) (func (export "test") (elem.drop 4))) @@ -132,7 +134,7 @@ print( print( `(assert_invalid (module - (elem passive funcref 0) + (elem funcref (ref.func 0)) (func (result i32) (i32.const 0)) (func (export "test") (table.init 4 (i32.const 12) (i32.const 1) (i32.const 1)))) @@ -145,9 +147,11 @@ function do_test(insn1, insn2, errText) (module (table 30 30 funcref) (elem (i32.const 2) 3 1 4 1) - (elem passive funcref 2 7 1 8) + (elem funcref + (ref.func 2) (ref.func 7) (ref.func 1) (ref.func 8)) (elem (i32.const 12) 7 5 2 3 6) - (elem passive funcref 5 9 2 7 6) + (elem funcref + (ref.func 5) (ref.func 9) (ref.func 2) (ref.func 7) (ref.func 6)) (func (result i32) (i32.const 0)) (func (result i32) (i32.const 1)) (func (result i32) (i32.const 2)) @@ -255,7 +259,7 @@ tab_test1("(table.init 1 (i32.const 30) (i32.const 4) (i32.const 0))", (assert_invalid (module (table 10 funcref) - (elem passive funcref $f0 $f0 $f0) + (elem funcref (ref.func $f0) (ref.func $f0) (ref.func $f0)) (func $f0) (func (export "test") (table.init 0 (${ty1}.const 1) (${ty2}.const 1) (${ty3}.const 1)))) @@ -278,7 +282,11 @@ function tbl_init(min, max, backup, write, segoffs=0) { (module (type (func (result i32))) (table ${min} ${max} funcref) - (elem passive funcref $f0 $f1 $f2 $f3 $f4 $f5 $f6 $f7 $f8 $f9 $f10 $f11 $f12 $f13 $f14 $f15) + (elem funcref + (ref.func $f0) (ref.func $f1) (ref.func $f2) (ref.func $f3) + (ref.func $f4) (ref.func $f5) (ref.func $f6) (ref.func $f7) + (ref.func $f8) (ref.func $f9) (ref.func $f10) (ref.func $f11) + (ref.func $f12) (ref.func $f13) (ref.func $f14) (ref.func $f15)) (func $f0 (export "f0") (result i32) (i32.const 0)) (func $f1 (export "f1") (result i32) (i32.const 1)) (func $f2 (export "f2") (result i32) (i32.const 2)) From e5cf99fe4a0247c1820f84f93795e75d4c1879e9 Mon Sep 17 00:00:00 2001 From: Andreas Rossberg Date: Wed, 15 May 2019 11:44:25 +0200 Subject: [PATCH 095/199] [spec] Fix oversight in elem typing rule --- document/core/exec/modules.rst | 133 -------------------------------- document/core/valid/modules.rst | 6 +- document/core/valid/types.rst | 133 ++++++++++++++++++++++++++++++++ 3 files changed, 137 insertions(+), 135 deletions(-) diff --git a/document/core/exec/modules.rst b/document/core/exec/modules.rst index ac6a2849e4..c69329fc81 100644 --- a/document/core/exec/modules.rst +++ b/document/core/exec/modules.rst @@ -149,139 +149,6 @@ The following auxiliary typing rules specify this typing relation relative to a } -.. index:: ! matching, external type -.. _exec-import: -.. _match: - -Import Matching -~~~~~~~~~~~~~~~ - -When :ref:`instantiating ` a module, -:ref:`external values ` must be provided whose :ref:`types ` are *matched* against the respective :ref:`external types ` classifying each import. -In some cases, this allows for a simple form of subtyping, as defined below. - - -.. index:: limits -.. _match-limits: - -Limits -...... - -:ref:`Limits ` :math:`\{ \LMIN~n_1, \LMAX~m_1^? \}` match limits :math:`\{ \LMIN~n_2, \LMAX~m_2^? \}` if and only if: - -* :math:`n_1` is larger than or equal to :math:`n_2`. - -* Either: - - * :math:`m_2^?` is empty. - -* Or: - - * Both :math:`m_1^?` and :math:`m_2^?` are non-empty. - - * :math:`m_1` is smaller than or equal to :math:`m_2`. - -.. math:: - ~\\[-1ex] - \frac{ - n_1 \geq n_2 - }{ - \vdashlimitsmatch \{ \LMIN~n_1, \LMAX~m_1^? \} \matcheslimits \{ \LMIN~n_2, \LMAX~\epsilon \} - } - \quad - \frac{ - n_1 \geq n_2 - \qquad - m_1 \leq m_2 - }{ - \vdashlimitsmatch \{ \LMIN~n_1, \LMAX~m_1 \} \matcheslimits \{ \LMIN~n_2, \LMAX~m_2 \} - } - - -.. _match-externtype: - -.. index:: function type -.. _match-functype: - -Functions -......... - -An :ref:`external type ` :math:`\ETFUNC~\functype_1` matches :math:`\ETFUNC~\functype_2` if and only if: - -* Both :math:`\functype_1` and :math:`\functype_2` are the same. - -.. math:: - ~\\[-1ex] - \frac{ - }{ - \vdashexterntypematch \ETFUNC~\functype \matchesexterntype \ETFUNC~\functype - } - - -.. index:: table type, limits, element type -.. _match-tabletype: - -Tables -...... - -An :ref:`external type ` :math:`\ETTABLE~(\limits_1~\reftype_1)` matches :math:`\ETTABLE~(\limits_2~\reftype_2)` if and only if: - -* Limits :math:`\limits_1` :ref:`match ` :math:`\limits_2`. - -* Both :math:`\reftype_1` and :math:`\reftype_2` are the same. - -.. math:: - \frac{ - \vdashlimitsmatch \limits_1 \matcheslimits \limits_2 - }{ - \vdashexterntypematch \ETTABLE~(\limits_1~\reftype) \matchesexterntype \ETTABLE~(\limits_2~\reftype) - } - - -.. index:: memory type, limits -.. _match-memtype: - -Memories -........ - -An :ref:`external type ` :math:`\ETMEM~\limits_1` matches :math:`\ETMEM~\limits_2` if and only if: - -* Limits :math:`\limits_1` :ref:`match ` :math:`\limits_2`. - -.. math:: - \frac{ - \vdashlimitsmatch \limits_1 \matcheslimits \limits_2 - }{ - \vdashexterntypematch \ETMEM~\limits_1 \matchesexterntype \ETMEM~\limits_2 - } - - -.. index:: global type, value type, mutability -.. _match-globaltype: - -Globals -....... - -An :ref:`external type ` :math:`\ETGLOBAL~(\mut_1~t_1)` matches :math:`\ETGLOBAL~(\mut_2~t_2)` if and only if: - -* Either both :math:`\mut_1` and :math:`\mut_2` are |MVAR| and :math:`t_1` and :math:`t_2` are the same. - -* Or both :math:`\mut_1` and :math:`\mut_2` are |MCONST| and :math:`t_1` :ref:`matches ` :math:`t_2`. - -.. math:: - ~\\[-1ex] - \frac{ - }{ - \vdashexterntypematch \ETGLOBAL~(\MVAR~t) \matchesexterntype \ETGLOBAL~(\MVAR~t) - } - \qquad - \frac{ - \vdashvaltypematch t_1 \matchesvaltype t_2 - }{ - \vdashexterntypematch \ETGLOBAL~(\MCONST~t_1) \matchesexterntype \ETGLOBAL~(\MCONST~t_2) - } - - .. index:: ! allocation, store, address .. _alloc: diff --git a/document/core/valid/modules.rst b/document/core/valid/modules.rst index 1c36a07948..041bf48ebc 100644 --- a/document/core/valid/modules.rst +++ b/document/core/valid/modules.rst @@ -154,7 +154,7 @@ Element segments :math:`\elem` are not classified by a type. * Let :math:`\limits~t` be the :ref:`table type ` :math:`C.\CTABLES[x]`. -* The :ref:`reference type ` :math:`t` must be |FUNCREF|. +* The :ref:`reference type ` |FUNCREF| must :ref:`match ` the reference type :math:`t`. * The expression :math:`\expr` must be :ref:`valid ` with :ref:`result type ` :math:`[\I32]`. @@ -168,7 +168,9 @@ Element segments :math:`\elem` are not classified by a type. .. math:: \frac{ - C.\CTABLES[x] = \limits~\FUNCREF + C.\CTABLES[x] = \limits~t + \qquad + \vdashreftypematch \FUNCREF \matchesvaltype t \qquad C \vdashexpr \expr : [\I32] \qquad diff --git a/document/core/valid/types.rst b/document/core/valid/types.rst index 37aa01ee35..f18a500f28 100644 --- a/document/core/valid/types.rst +++ b/document/core/valid/types.rst @@ -299,3 +299,136 @@ That is, a :ref:`result type ` :math:`[t_1^?]` matches a :ref }{ \vdashresulttypematch [t_1^?] \matchesresulttype [t_2^?] } + + +.. index:: ! matching, external type +.. _exec-import: +.. _match: + +Import Subtyping +~~~~~~~~~~~~~~~~ + +When :ref:`instantiating ` a module, +:ref:`external values ` must be provided whose :ref:`types ` are *matched* against the respective :ref:`external types ` classifying each import. +In some cases, this allows for a simple form of subtyping, as defined here. + + +.. index:: limits +.. _match-limits: + +Limits +...... + +:ref:`Limits ` :math:`\{ \LMIN~n_1, \LMAX~m_1^? \}` match limits :math:`\{ \LMIN~n_2, \LMAX~m_2^? \}` if and only if: + +* :math:`n_1` is larger than or equal to :math:`n_2`. + +* Either: + + * :math:`m_2^?` is empty. + +* Or: + + * Both :math:`m_1^?` and :math:`m_2^?` are non-empty. + + * :math:`m_1` is smaller than or equal to :math:`m_2`. + +.. math:: + ~\\[-1ex] + \frac{ + n_1 \geq n_2 + }{ + \vdashlimitsmatch \{ \LMIN~n_1, \LMAX~m_1^? \} \matcheslimits \{ \LMIN~n_2, \LMAX~\epsilon \} + } + \quad + \frac{ + n_1 \geq n_2 + \qquad + m_1 \leq m_2 + }{ + \vdashlimitsmatch \{ \LMIN~n_1, \LMAX~m_1 \} \matcheslimits \{ \LMIN~n_2, \LMAX~m_2 \} + } + + +.. _match-externtype: + +.. index:: function type +.. _match-functype: + +Functions +......... + +An :ref:`external type ` :math:`\ETFUNC~\functype_1` matches :math:`\ETFUNC~\functype_2` if and only if: + +* Both :math:`\functype_1` and :math:`\functype_2` are the same. + +.. math:: + ~\\[-1ex] + \frac{ + }{ + \vdashexterntypematch \ETFUNC~\functype \matchesexterntype \ETFUNC~\functype + } + + +.. index:: table type, limits, element type +.. _match-tabletype: + +Tables +...... + +An :ref:`external type ` :math:`\ETTABLE~(\limits_1~\reftype_1)` matches :math:`\ETTABLE~(\limits_2~\reftype_2)` if and only if: + +* Limits :math:`\limits_1` :ref:`match ` :math:`\limits_2`. + +* Both :math:`\reftype_1` and :math:`\reftype_2` are the same. + +.. math:: + \frac{ + \vdashlimitsmatch \limits_1 \matcheslimits \limits_2 + }{ + \vdashexterntypematch \ETTABLE~(\limits_1~\reftype) \matchesexterntype \ETTABLE~(\limits_2~\reftype) + } + + +.. index:: memory type, limits +.. _match-memtype: + +Memories +........ + +An :ref:`external type ` :math:`\ETMEM~\limits_1` matches :math:`\ETMEM~\limits_2` if and only if: + +* Limits :math:`\limits_1` :ref:`match ` :math:`\limits_2`. + +.. math:: + \frac{ + \vdashlimitsmatch \limits_1 \matcheslimits \limits_2 + }{ + \vdashexterntypematch \ETMEM~\limits_1 \matchesexterntype \ETMEM~\limits_2 + } + + +.. index:: global type, value type, mutability +.. _match-globaltype: + +Globals +....... + +An :ref:`external type ` :math:`\ETGLOBAL~(\mut_1~t_1)` matches :math:`\ETGLOBAL~(\mut_2~t_2)` if and only if: + +* Either both :math:`\mut_1` and :math:`\mut_2` are |MVAR| and :math:`t_1` and :math:`t_2` are the same. + +* Or both :math:`\mut_1` and :math:`\mut_2` are |MCONST| and :math:`t_1` :ref:`matches ` :math:`t_2`. + +.. math:: + ~\\[-1ex] + \frac{ + }{ + \vdashexterntypematch \ETGLOBAL~(\MVAR~t) \matchesexterntype \ETGLOBAL~(\MVAR~t) + } + \qquad + \frac{ + \vdashvaltypematch t_1 \matchesvaltype t_2 + }{ + \vdashexterntypematch \ETGLOBAL~(\MCONST~t_1) \matchesexterntype \ETGLOBAL~(\MCONST~t_2) + } From 82c9db12da98545a6a4ad1d6fce5a1e6fab2ceb6 Mon Sep 17 00:00:00 2001 From: Andreas Rossberg Date: Wed, 15 May 2019 12:17:15 +0200 Subject: [PATCH 096/199] [spec] Formatting nit --- document/core/valid/modules.rst | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/document/core/valid/modules.rst b/document/core/valid/modules.rst index 041bf48ebc..1a6f056505 100644 --- a/document/core/valid/modules.rst +++ b/document/core/valid/modules.rst @@ -168,15 +168,17 @@ Element segments :math:`\elem` are not classified by a type. .. math:: \frac{ + \begin{array}{@{}c@{}} C.\CTABLES[x] = \limits~t \qquad \vdashreftypematch \FUNCREF \matchesvaltype t - \qquad + \\ C \vdashexpr \expr : [\I32] \qquad C \vdashexprconst \expr \const \qquad (C.\CFUNCS[y] = \functype)^\ast + \end{array} }{ C \vdashelem \{ \ETABLE~x, \EOFFSET~\expr, \EINIT~y^\ast \} \ok } From eca021a3a9aaa3cca336ecdd5379e570023bbe3a Mon Sep 17 00:00:00 2001 From: Ben Smith Date: Thu, 16 May 2019 12:44:32 -0700 Subject: [PATCH 097/199] [spec] Add memory.fill to exec section (#88) --- document/core/exec/instructions.rst | 71 ++++++++++++++++++++++++++++ document/core/valid/instructions.rst | 4 +- 2 files changed, 73 insertions(+), 2 deletions(-) diff --git a/document/core/exec/instructions.rst b/document/core/exec/instructions.rst index 80b65c9aa2..16e0585148 100644 --- a/document/core/exec/instructions.rst +++ b/document/core/exec/instructions.rst @@ -618,6 +618,77 @@ Memory Instructions In practice, the choice depends on the :ref:`resources ` available to the :ref:`embedder `. +.. _exec-memory.fill: + +:math:`\MEMORYFILL` +................... + +1. Let :math:`F` be the :ref:`current ` :ref:`frame `. + +2. Assert: due to :ref:`validation `, :math:`F.\AMODULE.\MIMEMS[0]` exists. + +3. Let :math:`a` be the :ref:`memory address ` :math:`F.\AMODULE.\MIMEMS[0]`. + +4. Assert: due to :ref:`validation `, :math:`S.\SMEMS[a]` exists. + +5. Let :math:`\X{mem}` be the :ref:`memory instance ` :math:`S.\SMEMS[a]`. + +6. Assert: due to :ref:`validation `, a value of :ref:`value type ` |I32| is on the top of the stack. + +7. Pop the value :math:`\I32.\CONST~n` from the stack. + +8. Assert: due to :ref:`validation `, a value of :ref:`value type ` |I32| is on the top of the stack. + +9. Pop the value :math:`\val` from the stack. + +10. Assert: due to :ref:`validation `, a value of :ref:`value type ` |I32| is on the top of the stack. + +11. Pop the value :math:`\I32.\CONST~i` from the stack. + +12. If :math:`n` is :math:`0`, then: + + a. If :math:`i` is larger than the length of :math:`\X{mem}.\MIDATA`, then: + + i. Trap. + +13. Else: + + a. Push the value :math:`\I32.\CONST~i` to the stack. + + b. Push the value :math:`\val` to the stack. + + c. Execute the instruction :math:`\I32\K{.}\STORE\K{8}~\{ \OFFSET~0, \ALIGN~0 \}`. + + d. Push the value :math:`\I32.\CONST~(i+1)` to the stack. + + e. Push the value :math:`\val` to the stack. + + f. Push the value :math:`\I32.\CONST~(n-1)` to the stack. + + g. Execute the instruction :math:`\MEMORYFILL`. + +.. math:: + \begin{array}{l} + \begin{array}{lcl@{\qquad}l} + S; F; (\I32.\CONST~i)~\val~(\I32.\CONST~(n+1))~(\MEMORYFILL) &\stepto& S; F; + \begin{array}[t]{@{}l@{}} + (\I32.\CONST~i)~\val~(\I32\K{.}\STORE\K{8}~\{ \OFFSET~0, \ALIGN~0 \}) \\ + (\I32.\CONST~(i+1))~\val~(\I32.\CONST~n)~(\MEMORYFILL) \\ + \end{array} \\ + \end{array} \\ + \begin{array}{lcl@{\qquad}l} + S; F; (\I32.\CONST~i)~\val~(\I32.\CONST~0)~(\MEMORYFILL) &\stepto& S; F; \epsilon + \end{array} + \\ \qquad + (\iff i \leq |\SMEMS[F.\AMODULE.\MIMEMS[x]]|) \\ + \begin{array}{lcl@{\qquad}l} + S; F; (\I32.\CONST~i)~\val~(\I32.\CONST~0)~(\MEMORYFILL) &\stepto& S; F; \TRAP + \end{array} + \\ \qquad + (\otherwise) \\ + \end{array} + + .. index:: control instructions, structured control, label, block, branch, result type, label index, function index, type index, vector, address, table address, table instance, store, frame pair: execution; instruction single: abstract syntax; instruction diff --git a/document/core/valid/instructions.rst b/document/core/valid/instructions.rst index f383c18fc5..6aef34abbf 100644 --- a/document/core/valid/instructions.rst +++ b/document/core/valid/instructions.rst @@ -489,7 +489,7 @@ Memory Instructions .. _valid-memory.fill: :math:`\MEMORYFILL` -..................... +................... * The memory :math:`C.\CMEMS[0]` must be defined in the context. @@ -506,7 +506,7 @@ Memory Instructions .. _valid-memory.copy: :math:`\MEMORYCOPY` -..................... +................... * The memory :math:`C.\CMEMS[0]` must be defined in the context. From 4e1a09341569df02f5972974532c3facbb4917ca Mon Sep 17 00:00:00 2001 From: Ben Smith Date: Tue, 21 May 2019 13:43:18 -0700 Subject: [PATCH 098/199] [travis] Use a different deploy_key Deploy keys can't be shared between repositories, so we'll have to create a new one for each proposal. We may want to switch to the instructions described here instead at some point: https://docs.travis-ci.com/user/deployment/pages/ --- .travis.yml | 2 +- deploy_key.enc | Bin 3248 -> 3392 bytes 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 275b88e18c..4431c1886b 100644 --- a/.travis.yml +++ b/.travis.yml @@ -21,5 +21,5 @@ os: linux env: global: - - ENCRYPTION_LABEL: "304454be9d6c" + - ENCRYPTION_LABEL: "5d9ec396f41d" - COMMIT_AUTHOR_EMAIL: "noreply@webassembly.org" diff --git a/deploy_key.enc b/deploy_key.enc index b6d3e2f19771652a9711760b1712a77fe1b4e579..bc508e387eea50920c7cc404c8f6cf497c9fce9f 100644 GIT binary patch literal 3392 zcmV-G4Zre-1eU8xvN4;5I3;(DE@)0{e0SCBdLRQs8epBMI1_fo)FX|N>d+zrdiZ~> zx`Gd4>x7V^5Qt`|DC*MaEIHK<@j}L3aw=&nIr#lM-4=9OLRx8-K*Mv9{jWsUi^1Jw zB0$v$s{tXY^K|pmj-}{=(g(f~@LZ4b3v~yF4oYh4QM~&Ld~DIa10oMwRLeBr$hug= zTMm&yA6<8EmkG_yJsXhWn~#F)A2%xJ3Rx?SJ`Y~QU_mU1#wTUyF&L#O1hE6O`rM(U zsTG9Ca0fz#Y~53tYAAu-?O-T$P@9&AMiVP+SP-=TRI&{SUp&MH~Y0$G@`byHr9+LuELgDlt0%+D^Bu z2^d2JqkWB*MD{uI1nb5@G&Tje>=8@~FFtC9u3y0~u26O|I%~ns9sg}*{GjeRAVq!E zgJ@Xa5F{|2L7A)!Hp8HBoIDK{o`UzqlxtrTpPV zpaqUm&*uRPFNd7c86F)&H1^Zo)8a?n-?_Co9v4Cej&C2nG#kB1XB(QmA+PaB%L{W9 zU12y&!Md}DhSrGuX?w`WBhkiA8rhVSPa3X~3nNQ~gEc${9!dl-aGDn`k}C)eR9te( z5dtbId8TF0Dj|MIL9hzr!4Pq6&k(<{4n3driiKr(gN(@d3E9m5(a4ToRv5Vn8)&6= z-Kq2ZKv^O3ve2v&J44Qy8ApM-b2LsF8_W1#>$|9BLRvA2otB%cFkJ+fDoQnrYr%b# zZ=Y7!EDRkQum}D5Mqddm=`IXE50Bx9*gBCGo5UaDxXK?Np}gJ|?<4c8>cz)v3=`M^ zPBS_M@af>g>-e2wGMFRi4YCrDIDL8gM{2FVnX|+WQ^*JYWb&`b_CT=E&|fCM62={n zAAoZgJZ)+UfL}397h`BvmGe>j;#*PUqV@gWfQ^dFK5vq`F~}rPh1a1CzjSeMVv~mG zKPY)qrP5TXTMY{q7ZNqpRX;R!DjH?0JLmTXZXkcz z2_L(RC|vtGaJ?Gjy<0%Y-$c{n#S^ki3*Qx0Ox4sk9>0)fNc$(+J1&K=;GqpA0RnM- zxZlvp^zH9lN`Kin5YQC}O6EayqP%uwhjrQ=b;iD|SWKg;$Wwt{2Db%YQ31G3lmQCe z%Kgn}qIEqL5M14-B%sC1l3#6@>X6(IkjMWAZF-g4J9Nb=*Sj!ZDrr+A9o|LiSe-1l zJ4)nK$Y4bW4d}3EP{)>xS$Txs5pSwdztv6DRL}bdz{vS4fO^Y+l@ct~b5FdQ-z}Z; z!*Gz(?8V}6Jj8?Kzf>l?sR+p87_ijJ)+3yzn^}e0-0F%3Cy8bYlIB&I6G-ZsJsO?wV@Kffd?yu4h;)w;*CH?GSuI)=l9Y(Kr9(Sf<5aY( zV56=nDo6G7++ITu4V!2IL>+jp+;RUip$3~W=nY{lW!_@WtZ@u|fNzHvQCPP+$(_1? z#supPCUpBzF&iA8M5ZvxIqlZBg&8Y4?H^2+-j40wxbgaC4=0Lq`2~ z1=|Koz@4$>sqx>Y(L1AtGke5@Ll7b3Asau=Ld zI-|h>cX_%TG%u{9gyX8UO=l=Ii5y0>&!PlcLJnf(`TJ5H`YD|a|vs^B^AmweIoKj(vzV(jz99C-@7pbovPk| z;s?TR1>#aE!@(xtvt(iYQ4gZ1TrKhJ?c|w~a>veS3f4ElrEWxCzlF_c*!s>KAiCnK zh$z5r?IVT(n&hKjz!(?wPU1l5Uw>=<;*E_Pd>Cef@MNG*N-Ym^5~701fwZV zpq*bD2aW59j)=8b6;_0Et)-OjU$Fbsn1(^E(+l?FeQSh*(*TXR#J8#gN^31!#p-~? zHQ;5*$nQ1>i1v^kYyfdpJU>_Ysfxj|_8!xE-t!7FFqiz)%n$48GGAGUCn(zgWGAW( zG8ay#OfA~oOS5Dyjk65u1a@3p%sL#}L8@~xv|f{RBH(l1y}DAVXo@Rui!tvA@Z~Gu zl}+IhoLs41r)^@#Lze7N9TdJb2spiUk2dNC%n=YOr!vR;Yl0|yO09ds+-cH`D)vaE z1v!qxpoZppMyu>8Vpc@y6>Q7|%YhJXKh8T9K zhSRh=I1c$nP`nt^|K^utvTV4L^DTt<#6^JgSMhu& zdA|C{$E^Ko)v0FnhEv_CPzum~!Em$m2Jlwx`sA7g>umP-R|zU+))pg`PQeI7db=BE z$CI-s*=pZE7L%?tKPV*o;;ugBYrHB13NMPwZ>Vy;`UBB7ouqJ$fU*VD=^WjkXusYn zd+ppoN&DS~9t@!C<-|3oKDF5#;rmyE4Tc)cd6He9{mDOmEzM2wmcsQc1}QVBU4znN zP6`TKklseZdt=a2eFh_Jq?A3lq4MQUpF(*1uRT0q?V^p|eHlQgF*m2ja-UfPwO;vn z=-poco1^T_8Ee1s@=lDd3%fw5wyq=UjbL00Uh0K&2c^bNL#2Bqtgfh2{$KY22ctQ? ziz3X*<6V}TYM3rMep2t@$|m(cQMx338V#D1c8eXXaqkM}6ZyT@`8JOc#&bq}hO>|Q zmt9fU5Y|6ZU)Yz1*1`*#7!^ir0Mfj4Yd1dYYTN9=S@*8K?9D& z)p=b4$}NATK!y~?@X4cYX}*jq9C>t51$kFRI=WCCW|(k;Jdzb`+xI!ywFu3kuajsi zFQcE=c{BSs|CQ3vIO=^%l|}&0Z~X$&eQh72pO)s@Ydp-b!<9r@!hJMy`>Zk`@3wQO z-hc6!4Bz=Bg@S9YITy({RG>}Od{F!_0aHNNQ45(dwHjN~ zI>>EYkD^UYvtei^@+Eh?CRjxU6Fs-ghC=euQu$yKNYG*&!^hV21@e#7KmgpIWj#Fk ziY)6z!@)y%w^WH5$XwyAV1lvSN{^WuJX`Z{TuwHGET%lt%8GzP7C0#^+mYD(b&we^(}7uMiV5K>6N&)SV~t+-VL)v*-;G>yR{)mwSJEEpp-%yzUa{VlOoH5i76DKu z(R2rRi%cLSOM(xRiri_Ois7B#0Lf*i_T+C4!sK9qBC4 zJpyJEy|&o;+k6oKn8n{{f^G$+dzMHux@ z&{=k$F76t1_fVjtFp>xCA_bhTOxsA@+^xkQI-ilbK~Bt4m79C_i%?T9PaFwm^>tlY zp}Bg?=~i5~_nh}y7%=LxF0j=+7x@B_1ytkLyE(8hb`B;H3+e~;G4++&^6yiSj3t>% zdA>31Lvqaea1ITQZg-*A(Xi211Z=6TaETLefV_aT;iZr6cAtr7W7 zB5P8Vi<2x4TEErGY0wU|QImYlF@Q1QB8|LxppoK1r-yozGI^M0SFO*q79Z{U!G84F zsj533ewayE?A+gxVpXQkW8-hHT{Odd=oD6vAB9w;5b>NMG2^8%AG)HOJX903z1vdr zq^sudDd{_OuzV6R^`d(*h|O;`FtvfBLAEM3AHP0` zvA2&;LK-@4n+=Y9NK+Jo-;BV{2ol%626HoRa;fnhFCIrHWX80-J=bjjo!1y%fh}v? z@|zy4|IOoDa*q_uZ8bXBh{AKX#lz<2fig()ju#udilU5p<+wgBao_T&!ua{8Y#<|(CVbO6TJr-;79Ag-eBM!B~g(FTQ5ldW}>C6w#F z7?FSyFeYZ$v_V^lQFEF>+7k9B7m`7vS_SQ$;wWv|QOclL{NpaXb;g5ti(%WUt|3;5 z3CA#OrS)XS){2AUta7q}MSmhTJq zo{c?28()!ibPsqvTfOAA!4zOONU^F*gLcD(DrJbnNphXRZ3yC#LaPJi{CC$C(2A_7 zNaF$Iwo+ftMAzTpRFW1@B>=0mk{V^}DS!4rt3&v*?r8!}EfiTzY#jX?%ckauU9h@W zx(fD`Pk=~T7D1zi5Xgo-F3df<=bCbjU0(ZD&z`12ST)Xxn<2-%!cB^F0IoG~-*{lROB{l$8;> zQYD6uvZB!WjR97=Gm5k(nd?fS-skc&EK?_V8WnS+v(_4N1NbVfWy{T9c3+w+eKW@y z`gzb1V%Tr>ul(ay+I}7y2o4<>nNeC`_9<4dQwbaZcv=lR5j&@)QY$OIg__IEl?CzP zj*w)N-7!X;zax-wu2%HYpX17nK^l2cLppXhM>Q8<9AmF4V+?wF~S-rGWRU;<& zEfi}`>wt%Un_w@H!oNoZ>x+M|o6OWL0ZWAvCDS3ci~T8hKI0BHLyhmaX>a@YdQNK^9SJORstB zfvrm3TfM$`MMQQXp+4m=U~?Y#8>LXJEJKe+QT3ai?lI{90Zbd!SJdk4H(U1tebkQS zElH@QyluL-tMcF~ED_;l>!0Ijv*4gtnDwmLYV{a3@tjZ`D zFgG=OkZ90lfbv6>Fy&2v?b=c~Y_N9G zUi9};vfpk;9dPn4FMkaR{o~nn&h!a-?Sdb%SZ)!fI~GWnk~X{F~0*MZTR*=jmm-h1@t zDL!$f-TC0j9#3k6yGm=yVm`^%@wfi3bq#*03KSe>$d+&xjHOcMc8uJt8)hN2{SBal z4ob$b$`dj=o#p1YnW?UI^yZ;rkMjLI{F#<8G09bp2NC-f7?!MtUZ(JwIdFlSzu%EdX7u+as(dHl z58QQZ`uk&2UcuOD{=l^SW7lbUC)YQxLZoD(4yfjbALj)ocgYIM0ZYz?(TpdH^*N^lP&fD?>5S3l5d9vDe0MYX}=L@v0ac*d^h zMC3X&i8_TGc*nis1+Hbb@FGCYM0^b7+Ks%np4Yi`?%nMjTjK}kiD^peA^u+*e>(aKEP(B~>~mZq#KO^e z%~M*@SsY^h6(tY`GdMou`@})%F*bIbRNZ>mC~Kmlo-i?%UtfW#dT*z*RcdL zpk60TCgJqxKBvX~s$%Shh(AI%*I`@P2!X_@lhC_lv0_yIg6%&*TKAQRPZQNW>=_H-#1pBvjD+m{Zb}zcH8nbpNqr9whn4 zA=y)BHKQ-DrD~ATW$s5sLj-tJ#cf~=mO{+4YNwZc;4(}zeG0i5iXTW*#VVOL90%~C zVKMQHgk?j=XH43>K+-CeY3%JXI)VIB$Ad;DSsk-VJs=GfjP+|s{r){_ozCKbFDNi| zfEk3yUlIo}(x+SiFz(8%;%1%!B5`O|M9Tgg3bui&lu)v`(ydUn{aib=ktlW8MU&;r zQ+2LIr_4e3%GTLQ5?58orh7HmWd&Z&T0Uz!9~Ha`K^gp=fQ`FR=0~z|>MuzT4#e%& zBXJPHh`^tE;|zIgNiR(*kU@PB&}J%3Coh;M^QnC8vP7h%*_Gozd?$RZWr_#dXYF>u zT>^8L;b}KO+gPONfMBv1ae%Hy6R+;S^w+Ng{zo&nGB`o<^fxC>{v`=!WnoSACN9e? z!P}dgK-N^z=5p%- zjAkKdA-dFrZxs{<7wntcycPzJOC})W{%YX>7&0{p8S%XXI0{sJi2me-X!z#kb@^(L zIrTxbTFMXTi!+maqh2OdhC54A&#rQ{4~>UL|6E*af1FP^b#OX~#=VRt;}}z+FhX7& z(?0)PAKjGZ*g(dZNg81514!QK;bQWS0-qDq&xgnv8vdcEkLzW9YdU7Q`jSwWHd*~b zqQ?O;jM%iLY>Zw*$r*lZ~?dz)vtCi6GqzmKd+b z!(zZgpXf?*+wbzsxQ&XJ3)2p#3|IEa$pe0b>QbH=rr|j)yS-i=SFADE7tJ`oCmN@} zL{UA^mr)_ZWdcbz>BGLSKFnFY^oV4EXulUCv6iQUG?d~nuNbxQiWI`F1pbLxAfG^h iY#Pu|2q&8>`3}#6q-2Cz`ZEbT?K&=q;2asiqpF?e?>4gl From 822039b83105b99de226bb31d135f1f899c0402f Mon Sep 17 00:00:00 2001 From: Ben Smith Date: Tue, 21 May 2019 14:34:10 -0700 Subject: [PATCH 099/199] Copy bikeshed fix from spec repo See https://github.com/WebAssembly/spec/commit/27799cd9f08e18e5f83bc11822b910398fe466c9. --- document/core/index.bs | 2 +- document/core/util/mathjax2katex.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/document/core/index.bs b/document/core/index.bs index 2cbd5058ba..06357f6a4f 100644 --- a/document/core/index.bs +++ b/document/core/index.bs @@ -8,7 +8,7 @@ TR: https://www.w3.org/TR/wasm-core-1/ ED: https://webassembly.github.io/spec/core/bikeshed/ Editor: Andreas Rossberg (Dfinity Stiftung) Repository: WebAssembly/spec -Markup Shorthands: css no, markdown yes, algorithm no +Markup Shorthands: css no, markdown yes, algorithm no, idl no Abstract: This document describes version 1.0 of the core WebAssembly standard, a safe, portable, low-level code format designed for efficient execution and compact representation. Prepare For TR: true
    diff --git a/document/core/util/mathjax2katex.py b/document/core/util/mathjax2katex.py index 0b38ffdda0..b42fe3e1a7 100755 --- a/document/core/util/mathjax2katex.py +++ b/document/core/util/mathjax2katex.py @@ -233,7 +233,7 @@ def Worker(): fixed = ('class="' + cls_before + ' ' + cls_after + '">' + spans + ReplaceMath(cache, mth) + '<') done_fixups.append((start, end, fixed)) - except KeyboardInterrupt, AssertionError: + except Exception: sys.stderr.write('!!! Error processing fragment') q.task_done() From 0f7f930a9312ac66aff2bac418446d3842104083 Mon Sep 17 00:00:00 2001 From: gahaas Date: Thu, 23 May 2019 15:42:17 +0200 Subject: [PATCH 100/199] [test] JS-compatible module name (#45) --- test/core/linking.wast | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/test/core/linking.wast b/test/core/linking.wast index 9f8f9bd70d..ffd7285114 100644 --- a/test/core/linking.wast +++ b/test/core/linking.wast @@ -93,18 +93,18 @@ ) -(module $Mref-ex +(module $Mref_ex (global (export "g-const") funcref (ref.null)) (global (export "g-var") (mut funcref) (ref.null)) ) -(register "Mref-ex" $Mref-ex) +(register "Mref_ex" $Mref_ex) -(module $Mref-im - (global (import "Mref-ex" "g-const") anyref) +(module $Mref_im + (global (import "Mref_ex" "g-const") anyref) ) (assert_unlinkable - (module (global (import "Mref-ex" "g-var") (mut anyref))) + (module (global (import "Mref_ex" "g-var") (mut anyref))) "incompatible import type" ) From c3289d2fb0d9713727ac0856e1f2c7d5b892ec3c Mon Sep 17 00:00:00 2001 From: Ben Smith Date: Thu, 23 May 2019 16:06:13 -0700 Subject: [PATCH 101/199] [spec] Add element type to passive element segment (#90) This was accidentally omitted. --- document/core/binary/modules.rst | 4 ++-- document/core/syntax/modules.rst | 4 ++-- document/core/text/modules.rst | 4 ++-- document/core/util/macros.def | 1 + document/core/valid/modules.rst | 4 ++-- 5 files changed, 9 insertions(+), 8 deletions(-) diff --git a/document/core/binary/modules.rst b/document/core/binary/modules.rst index dbdc17c6d1..538d1fad12 100644 --- a/document/core/binary/modules.rst +++ b/document/core/binary/modules.rst @@ -329,8 +329,8 @@ It decodes into a vector of :ref:`element segments ` that represent \production{element segment} & \Belem &::=& \hex{00}~~e{:}\Bexpr~~y^\ast{:}\Bvec(\Bfuncidx) &\Rightarrow& \{ \ETABLE~0, \EOFFSET~e, \EINIT~((\REFFUNC~y)~\END)^\ast \} \\ &&|& - \hex{01}~~e^\ast{:}\Bvec(\Belemexpr) - &\Rightarrow& \{ \EINIT~e^\ast \} \\ &&|& + \hex{01}~~\X{et}:\Belemtype~e^\ast{:}\Bvec(\Belemexpr) + &\Rightarrow& \{ \ETYPE~et, \EINIT~e^\ast \} \\ &&|& \hex{02}~~x{:}\Btableidx~~e{:}\Bexpr~~y^\ast{:}\Bvec(\Bfuncidx) &\Rightarrow& \{ \ETABLE~x, \EOFFSET~e, \EINIT~((\REFFUNC~y)~\END)^\ast \} \\ \production{elemexpr} & \Belemexpr &::=& diff --git a/document/core/syntax/modules.rst b/document/core/syntax/modules.rst index 4aeff728e5..f1d12c20e3 100644 --- a/document/core/syntax/modules.rst +++ b/document/core/syntax/modules.rst @@ -256,13 +256,13 @@ The initial contents of a table is uninitialized. *Element segments* can be used Element segments can be :ref:`active ` or :ref:`passive `. An active element segment copies its elements into a table during :ref:`instantiation `. A passive element segment's elements can be copied using the |TABLEINIT| instruction. -The |MELEM| component of a module defines a vector of element segments. Each active element segment defines the |ETABLE| and the starting |EOFFSET| in that table to initialize. Each passive element segment only defines its contents. +The |MELEM| component of a module defines a vector of element segments. Each active element segment defines the |ETABLE| and the starting |EOFFSET| in that table to initialize. Each passive element segment defines its element type and contents. .. math:: \begin{array}{llll} \production{element segment} & \elem &::=& \{ \ETABLE~\tableidx, \EOFFSET~\expr, \EINIT~\vec(\elemexpr) \} \\&&|& - \{ \EINIT~\vec(\elemexpr) \} \\ + \{ \ETYPE~\elemtype, \EINIT~\vec(\elemexpr) \} \\ \production{elemexpr} & \elemexpr &::=& \REFNULL~\END \\&&|& (\REFFUNC~\funcidx)~\END \\ diff --git a/document/core/text/modules.rst b/document/core/text/modules.rst index bbe7c90e04..3208a0ff2e 100644 --- a/document/core/text/modules.rst +++ b/document/core/text/modules.rst @@ -485,8 +485,8 @@ Element segments allow for an optional :ref:`table index ` to ide \production{element segment} & \Telem_I &::=& \text{(}~\text{elem}~~\Tid^?~~x{:}\Ttableidx_I~~\text{(}~\text{offset}~~e{:}\Texpr_I~\text{)}~~y^\ast{:}\Tvec(\Tfuncidx_I)~\text{)} \\ &&& \qquad \Rightarrow\quad \{ \ETABLE~x, \EOFFSET~e, \EINIT~y^\ast \} \\ &&|& - \text{(}~\text{elem}~~\Tid^?~~\text{passive}~~y^\ast{:}\Tvec(\Tfuncidx_I)~\text{)} \\ &&& \qquad - \Rightarrow\quad \{ \EINIT~y^\ast \} \\ + \text{(}~\text{elem}~~\Tid^?~~et{:}\Telemtype~~y^\ast{:}\Tvec(\Tfuncidx_I)~\text{)} \\ &&& \qquad + \Rightarrow\quad \{ \ETYPE~et, \EINIT~y^\ast \} \\ \end{array} .. note:: diff --git a/document/core/util/macros.def b/document/core/util/macros.def index 82d89a12ff..a2db91bd9d 100644 --- a/document/core/util/macros.def +++ b/document/core/util/macros.def @@ -266,6 +266,7 @@ .. |ETABLE| mathdef:: \xref{syntax/modules}{syntax-elem}{\K{table}} .. |EOFFSET| mathdef:: \xref{syntax/modules}{syntax-elem}{\K{offset}} .. |EINIT| mathdef:: \xref{syntax/modules}{syntax-elem}{\K{init}} +.. |ETYPE| mathdef:: \xref{syntax/modules}{syntax-elem}{\K{type}} .. |REFNULL| mathdef:: \xref{syntax/modules}{syntax-elemexpr}{\K{ref.null}} .. |REFFUNC| mathdef:: \xref{syntax/modules}{syntax-elemexpr}{\K{ref.func}} diff --git a/document/core/valid/modules.rst b/document/core/valid/modules.rst index b24d6fa895..0a5046e1f8 100644 --- a/document/core/valid/modules.rst +++ b/document/core/valid/modules.rst @@ -181,7 +181,7 @@ Element segments :math:`\elem` are classified by :ref:`segment types Date: Thu, 23 May 2019 16:29:50 -0700 Subject: [PATCH 102/199] [spec] Fix title underline in valid/modules.rst --- document/core/valid/modules.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/document/core/valid/modules.rst b/document/core/valid/modules.rst index 0a5046e1f8..35323b4b25 100644 --- a/document/core/valid/modules.rst +++ b/document/core/valid/modules.rst @@ -182,7 +182,7 @@ Element segments :math:`\elem` are classified by :ref:`segment types Date: Mon, 27 May 2019 18:05:36 +0200 Subject: [PATCH 103/199] [spec] Adjust binary format of element segments (#46) --- document/core/binary/modules.rst | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/document/core/binary/modules.rst b/document/core/binary/modules.rst index 9c44b95c00..0d5e9a8420 100644 --- a/document/core/binary/modules.rst +++ b/document/core/binary/modules.rst @@ -319,7 +319,9 @@ It decodes into a vector of :ref:`element segments ` that represent \production{element section} & \Belemsec &::=& \X{seg}^\ast{:}\Bsection_9(\Bvec(\Belem)) &\Rightarrow& \X{seg} \\ \production{element segment} & \Belem &::=& - x{:}\Btableidx~~e{:}\Bexpr~~y^\ast{:}\Bvec(\Bfuncidx) + \hex{00}~~e{:}\Bexpr~~y^\ast{:}\Bvec(\Bfuncidx) + &\Rightarrow& \{ \ETABLE~0, \EOFFSET~e, \EINIT~y^\ast \} \\ &&|& + \hex{02}~~x{:}\Btableidx~~e{:}\Bexpr~~y^\ast{:}\Bvec(\Bfuncidx) &\Rightarrow& \{ \ETABLE~x, \EOFFSET~e, \EINIT~y^\ast \} \\ \end{array} From b2d34e0f9b133d386457a72dd800b50af175a34f Mon Sep 17 00:00:00 2001 From: gahaas Date: Tue, 28 May 2019 18:42:05 +0200 Subject: [PATCH 104/199] [test] Use more JS-compatible names (#47) --- test/core/linking.wast | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/test/core/linking.wast b/test/core/linking.wast index ffd7285114..be561e5110 100644 --- a/test/core/linking.wast +++ b/test/core/linking.wast @@ -109,14 +109,14 @@ ) -(module $Mglobal-ex +(module $Mglobal_ex (func $f) (global (export "g") anyref (ref.func $f)) ) -(register "Mglobal-ex" $Mglobal-ex) +(register "Mglobal_ex" $Mglobal_ex) (assert_unlinkable - (module (global (import "Mglobal-ex" "g") funcref)) + (module (global (import "Mglobal_ex" "g") funcref)) "incompatible import type" ) @@ -277,15 +277,15 @@ (assert_trap (invoke $Mt "call" (i32.const 7)) "uninitialized") -(module $Mtable-ex +(module $Mtable_ex (func $f) (table $t (export "t") 1 anyref) (elem (i32.const 0) $f) ) -(register "Mtable-ex" $Mtable-ex) +(register "Mtable_ex" $Mtable_ex) (assert_unlinkable - (module (table (import "Mtable-ex" "t") 1 funcref)) + (module (table (import "Mtable_ex" "t") 1 funcref)) "incompatible import type" ) From a976b820dd76436b6a2feacb4e9e8f5684179053 Mon Sep 17 00:00:00 2001 From: Ben Smith Date: Thu, 30 May 2019 17:47:09 -0700 Subject: [PATCH 105/199] [spec] Runtime format of element and data segments (#91) This is copied and modified from this closed PR: https://github.com/WebAssembly/bulk-memory-operations/pull/19 --- document/core/exec/modules.rst | 52 +++++++++++++++++++++++++++++ document/core/exec/runtime.rst | 60 +++++++++++++++++++++++++++++++--- document/core/util/macros.def | 16 +++++++-- 3 files changed, 121 insertions(+), 7 deletions(-) diff --git a/document/core/exec/modules.rst b/document/core/exec/modules.rst index 4d6e7b04c9..ce6eda189c 100644 --- a/document/core/exec/modules.rst +++ b/document/core/exec/modules.rst @@ -371,6 +371,58 @@ New instances of :ref:`functions `, :ref:`tables ` +......................................... + +1. Let :math:`\funcelem^\ast` be the vector of :ref:`function elements ` to allocate. + +2. Let :math:`a` be the first free :ref:`element address ` in :math:`S`. + +3. Let :math:`\eleminst` be the :ref:`element instance ` :math:`\{ \EIINIT~\funcelem^\ast \}`. + +4. Append :math:`\eleminst` to the |SELEM| of :math:`S`. + +5. Return :math:`a`. + +.. math:: + \begin{array}{rlll} + \allocelem(S, \funcelem^\ast) &=& S', \elemaddr \\[1ex] + \mbox{where:} \hfill \\ + \elemaddr &=& |S.\SELEM| \\ + \eleminst &=& \{ \EIINIT~\funcelem^\ast \} \\ + S' &=& S \compose \{\SELEM~\eleminst\} \\ + \end{array} + + +.. index:: data, data instance, data address +.. _alloc-data: + +:ref:`Data segments ` +...................................... + +1. Let :math:`\bytes` be the vector of :ref:`bytes ` to allocate. + +2. Let :math:`a` be the first free :ref:`data address ` in :math:`S`. + +3. Let :math:`\datainst` be the :ref:`data instance ` :math:`\{ \DIINIT~\bytes \}`. + +4. Append :math:`\datainst` to the |SDATA| of :math:`S`. + +5. Return :math:`a`. + +.. math:: + \begin{array}{rlll} + \allocdata(S, \bytes) &=& S', \dataaddr \\[1ex] + \mbox{where:} \hfill \\ + \dataaddr &=& |S.\SDATA| \\ + \datainst &=& \{ \DIINIT~\bytes \} \\ + S' &=& S \compose \{\SDATA~\datainst\} \\ + \end{array} + + .. index:: table, table instance, table address, grow, limits .. _grow-table: diff --git a/document/core/exec/runtime.rst b/document/core/exec/runtime.rst index c1375fe1eb..204b5fc589 100644 --- a/document/core/exec/runtime.rst +++ b/document/core/exec/runtime.rst @@ -60,7 +60,7 @@ Store ~~~~~ The *store* represents all global state that can be manipulated by WebAssembly programs. -It consists of the runtime representation of all *instances* of :ref:`functions `, :ref:`tables `, :ref:`memories `, and :ref:`globals ` that have been :ref:`allocated ` during the life time of the abstract machine. [#gc]_ +It consists of the runtime representation of all *instances* of :ref:`functions `, :ref:`tables `, :ref:`memories `, and :ref:`globals `, :ref:`element segments `, and :ref:`data segments ` that have been :ref:`allocated ` during the life time of the abstract machine. [#gc]_ Syntactically, the store is defined as a :ref:`record ` listing the existing instances of each category: @@ -71,7 +71,9 @@ Syntactically, the store is defined as a :ref:`record ` listing \SFUNCS & \funcinst^\ast, \\ \STABLES & \tableinst^\ast, \\ \SMEMS & \meminst^\ast, \\ - \SGLOBALS & \globalinst^\ast ~\} \\ + \SGLOBALS & \globalinst^\ast, \\ + \SELEM & (\eleminst^?)^\ast, \\ + \SDATA & (\datainst^?)^\ast ~\} \\ \end{array} \end{array} @@ -87,25 +89,31 @@ Convention * The meta variable :math:`S` ranges over stores where clear from context. -.. index:: ! address, store, function instance, table instance, memory instance, global instance, embedder +.. index:: ! address, store, function instance, table instance, memory instance, global instance, element instance, data instance, embedder pair: abstract syntax; function address pair: abstract syntax; table address pair: abstract syntax; memory address pair: abstract syntax; global address + pair: abstract syntax; element address + pair: abstract syntax; data address pair: function; address pair: table; address pair: memory; address pair: global; address + pair: element; address + pair: data; address .. _syntax-funcaddr: .. _syntax-tableaddr: .. _syntax-memaddr: .. _syntax-globaladdr: +.. _syntax-elemaddr: +.. _syntax-dataaddr: .. _syntax-addr: Addresses ~~~~~~~~~ -:ref:`Function instances `, :ref:`table instances `, :ref:`memory instances `, and :ref:`global instances ` in the :ref:`store ` are referenced with abstract *addresses*. +:ref:`Function instances `, :ref:`table instances `, :ref:`memory instances `, and :ref:`global instances `, :ref:`element instances `, and :ref:`data instances ` in the :ref:`store ` are referenced with abstract *addresses*. These are simply indices into the respective store component. .. math:: @@ -120,6 +128,10 @@ These are simply indices into the respective store component. \addr \\ \production{(global address)} & \globaladdr &::=& \addr \\ + \production{(element address)} & \elemaddr &::=& + \addr \\ + \production{(data address)} & \dataaddr &::=& + \addr \\ \end{array} An :ref:`embedder ` may assign identity to :ref:`exported ` store objects corresponding to their addresses, @@ -137,7 +149,7 @@ even where this identity is not observable from within WebAssembly code itself hence logical addresses can be arbitrarily large natural numbers. -.. index:: ! instance, function type, function instance, table instance, memory instance, global instance, export instance, table address, memory address, global address, index, name +.. index:: ! instance, function type, function instance, table instance, memory instance, global instance, element instance, data instance, export instance, table address, memory address, global address, element address, data address, index, name pair: abstract syntax; module instance pair: module; instance .. _syntax-moduleinst: @@ -158,6 +170,8 @@ and collects runtime representations of all entities that are imported, defined, \MITABLES & \tableaddr^\ast, \\ \MIMEMS & \memaddr^\ast, \\ \MIGLOBALS & \globaladdr^\ast, \\ + \MIELEMS & (\elemaddr^?)^\ast, \\ + \MIDATAS & (\dataaddr^?)^\ast, \\ \MIEXPORTS & \exportinst^\ast ~\} \\ \end{array} \end{array} @@ -275,6 +289,42 @@ It holds an individual :ref:`value ` and a flag indicating whether i The value of mutable globals can be mutated through :ref:`variable instructions ` or by external means provided by the :ref:`embedder `. +.. index:: ! element instance, element segment, embedder, element expression + pair: abstract syntax; element instance + pair: element; instance +.. _syntax-eleminst: + +Element Instances +~~~~~~~~~~~~~~~~~ + +An *element instance* is the runtime representation of an :ref:`element segment `. +Like table instances, an element instance holds a vector of function elements. + +.. math:: + \begin{array}{llll} + \production{(element instance)} & \eleminst &::=& + \{ \EIINIT~\vec(\funcelem) \} \\ + \end{array} + + +.. index:: ! data instance, data segment, embedder, byte + pair: abstract syntax; data instance + pair: data; instance +.. _syntax-datainst: + +Data Instances +~~~~~~~~~~~~~~ + +An *data instance* is the runtime representation of a :ref:`data segment `. +It holds a vector of :ref:`bytes `. + +.. math:: + \begin{array}{llll} + \production{(data instance)} & \datainst &::=& + \{ \DIINIT~\vec(\byte) \} \\ + \end{array} + + .. index:: ! export instance, export, name, external value pair: abstract syntax; export instance pair: export; instance diff --git a/document/core/util/macros.def b/document/core/util/macros.def index a2db91bd9d..d53e271595 100644 --- a/document/core/util/macros.def +++ b/document/core/util/macros.def @@ -806,6 +806,8 @@ .. |alloctable| mathdef:: \xref{exec/modules}{alloc-table}{\F{alloctable}} .. |allocmem| mathdef:: \xref{exec/modules}{alloc-mem}{\F{allocmem}} .. |allocglobal| mathdef:: \xref{exec/modules}{alloc-global}{\F{allocglobal}} +.. |allocelem| mathdef:: \xref{exec/modules}{alloc-elem}{\F{allocelem}} +.. |allocdata| mathdef:: \xref{exec/modules}{alloc-data}{\F{allocdata}} .. |allocmodule| mathdef:: \xref{exec/modules}{alloc-module}{\F{allocmodule}} .. |growtable| mathdef:: \xref{exec/modules}{grow-table}{\F{growtable}} @@ -819,7 +821,8 @@ .. |tableaddr| mathdef:: \xref{exec/runtime}{syntax-tableaddr}{\X{tableaddr}} .. |memaddr| mathdef:: \xref{exec/runtime}{syntax-memaddr}{\X{memaddr}} .. |globaladdr| mathdef:: \xref{exec/runtime}{syntax-globaladdr}{\X{globaladdr}} - +.. |elemaddr| mathdef:: \xref{exec/runtime}{syntax-elemaddr}{\X{elemaddr}} +.. |dataaddr| mathdef:: \xref{exec/runtime}{syntax-dataaddr}{\X{dataaddr}} .. Instances, terminals @@ -837,6 +840,10 @@ .. |GIVALUE| mathdef:: \xref{exec/runtime}{syntax-globalinst}{\K{value}} .. |GIMUT| mathdef:: \xref{exec/runtime}{syntax-globalinst}{\K{mut}} +.. |EIINIT| mathdef:: \xref{exec/runtime}{syntax-eleminst}{\K{init}} + +.. |DIINIT| mathdef:: \xref{exec/runtime}{syntax-datainst}{\K{init}} + .. |EINAME| mathdef:: \xref{exec/runtime}{syntax-exportinst}{\K{name}} .. |EIVALUE| mathdef:: \xref{exec/runtime}{syntax-exportinst}{\K{value}} @@ -850,6 +857,8 @@ .. |MITABLES| mathdef:: \xref{exec/runtime}{syntax-moduleinst}{\K{tableaddrs}} .. |MIMEMS| mathdef:: \xref{exec/runtime}{syntax-moduleinst}{\K{memaddrs}} .. |MIGLOBALS| mathdef:: \xref{exec/runtime}{syntax-moduleinst}{\K{globaladdrs}} +.. |MIELEMS| mathdef:: \xref{exec/runtime}{syntax-moduleinst}{\K{elemaddrs}} +.. |MIDATAS| mathdef:: \xref{exec/runtime}{syntax-moduleinst}{\K{dataaddrs}} .. |MIEXPORTS| mathdef:: \xref{exec/runtime}{syntax-moduleinst}{\K{exports}} @@ -863,6 +872,8 @@ .. |funcelem| mathdef:: \xref{exec/runtime}{syntax-funcelem}{\X{funcelem}} .. |meminst| mathdef:: \xref{exec/runtime}{syntax-meminst}{\X{meminst}} .. |globalinst| mathdef:: \xref{exec/runtime}{syntax-globalinst}{\X{globalinst}} +.. |eleminst| mathdef:: \xref{exec/runtime}{syntax-eleminst}{\X{eleminst}} +.. |datainst| mathdef:: \xref{exec/runtime}{syntax-datainst}{\X{datainst}} .. |exportinst| mathdef:: \xref{exec/runtime}{syntax-exportinst}{\X{exportinst}} .. |hostfunc| mathdef:: \xref{exec/runtime}{syntax-hostfunc}{\X{hostfunc}} @@ -882,7 +893,8 @@ .. |STABLES| mathdef:: \xref{exec/runtime}{syntax-store}{\K{tables}} .. |SMEMS| mathdef:: \xref{exec/runtime}{syntax-store}{\K{mems}} .. |SGLOBALS| mathdef:: \xref{exec/runtime}{syntax-store}{\K{globals}} - +.. |SELEM| mathdef:: \xref{exec/runtime}{syntax-store}{\K{elem}} +.. |SDATA| mathdef:: \xref{exec/runtime}{syntax-store}{\K{data}} .. Store, non-terminals From 0ee9e67138e4da6e73e5088e3dc8562c3538ff82 Mon Sep 17 00:00:00 2001 From: Ben Smith Date: Wed, 5 Jun 2019 13:31:03 -0700 Subject: [PATCH 106/199] [spec] Add memory.init and data.drop for exec (#92) --- document/core/exec/instructions.rst | 126 +++++++++++++++++++++++++++- document/core/exec/runtime.rst | 4 +- 2 files changed, 127 insertions(+), 3 deletions(-) diff --git a/document/core/exec/instructions.rst b/document/core/exec/instructions.rst index 16e0585148..185d001d06 100644 --- a/document/core/exec/instructions.rst +++ b/document/core/exec/instructions.rst @@ -680,7 +680,7 @@ Memory Instructions S; F; (\I32.\CONST~i)~\val~(\I32.\CONST~0)~(\MEMORYFILL) &\stepto& S; F; \epsilon \end{array} \\ \qquad - (\iff i \leq |\SMEMS[F.\AMODULE.\MIMEMS[x]]|) \\ + (\iff i \leq |\SMEMS[F.\AMODULE.\MIMEMS[0]]|) \\ \begin{array}{lcl@{\qquad}l} S; F; (\I32.\CONST~i)~\val~(\I32.\CONST~0)~(\MEMORYFILL) &\stepto& S; F; \TRAP \end{array} @@ -689,6 +689,130 @@ Memory Instructions \end{array} +.. _exec-memory.init: + +:math:`\MEMORYINIT~x` +..................... + +1. Let :math:`F` be the :ref:`current ` :ref:`frame `. + +2. Assert: due to :ref:`validation `, :math:`F.\AMODULE.\MIMEMS[0]` exists. + +3. Let :math:`\X{ma}` be the :ref:`memory address ` :math:`F.\AMODULE.\MIMEMS[0]`. + +4. Assert: due to :ref:`validation `, :math:`S.\SMEMS[\X{ma}]` exists. + +5. Let :math:`\X{mem}` be the :ref:`memory instance ` :math:`S.\SMEMS[\X{ma}]`. + +6. Assert: due to :ref:`validation `, :math:`F.\AMODULE.\MIDATAS[x]` exists. + +7. Let :math:`\X{da}^?` be the optional :ref:`data address ` :math:`F.\AMODULE.\MIDATAS[x]`. + +8. If :math:`\X{da}^? = \epsilon`, then: + + a. Trap. + +9. Let :math:`\X{data}` be the :ref:`data instance ` :math:`S.\SDATA[\X{da}]`. + +10. Assert: due to :ref:`validation `, a value of :ref:`value type ` |I32| is on the top of the stack. + +11. Pop the value :math:`\I32.\CONST~n` from the stack. + +12. Assert: due to :ref:`validation `, a value of :ref:`value type ` |I32| is on the top of the stack. + +13. Pop the value :math:`\I32.\CONST~s` from the stack. + +14. Assert: due to :ref:`validation `, a value of :ref:`value type ` |I32| is on the top of the stack. + +15. Pop the value :math:`\I32.\CONST~d` from the stack. + +16. If :math:`n` is :math:`0`, then: + + a. If :math:`d` is larger than the length of :math:`\X{mem}.\MIDATA`, then: + + i. Trap. + + b. If :math:`s` is larger than the length of :math:`\X{data}.\DIINIT`, then: + + i. Trap. + +17. Else: + + a. Push the value :math:`\I32.\CONST~d` to the stack. + + b. Let :math:`b` be the byte :math:`\X{data}.\DIINIT[s]`. + + c. Push the value :math:`\I32.\CONST~b` to the stack. + + d. Execute the instruction :math:`\I32\K{.}\STORE\K{8}~\{ \OFFSET~0, \ALIGN~0 \}`. + + e. Push the value :math:`\I32.\CONST~(d+1)` to the stack. + + f. Push the value :math:`\I32.\CONST~(s+1)` to the stack. + + g. Push the value :math:`\I32.\CONST~(n-1)` to the stack. + + h. Execute the instruction :math:`\MEMORYINIT~x`. + +.. math:: + \begin{array}{l} + \begin{array}{lcl@{\qquad}l} + S; F; (\I32.\CONST~d)~(\I32.\CONST~s)~(\I32.\CONST~(n+1))~(\MEMORYINIT~x) &\stepto& S; F; + \begin{array}[t]{@{}l@{}} + (\I32.\CONST~d)~(\I32.\CONST~b)~(\I32\K{.}\STORE\K{8}~\{ \OFFSET~0, \ALIGN~0 \}) \\ + (\I32.\CONST~(d+1))~(\I32.\CONST~(s+1))~(\I32.\CONST~n)~(\MEMORYINIT~x) \\ + \end{array} \\ + \end{array} \\ + \\ \qquad + \begin{array}[t]{@{}r@{~}l@{}} + (\iff & F.\AMODULE.\MIDATAS[x] \ne \epsilon \\ + \wedge & b = \SDATA[F.\AMODULE.\MIDATAS[x]].\DIINIT[s]) \\ + \end{array} + \\[1ex] + \begin{array}{lcl@{\qquad}l} + S; F; (\I32.\CONST~d)~(\I32.\CONST~(s)~(\I32.\CONST~0)~(\MEMORYINIT~x) &\stepto& S; F; \epsilon + \end{array} + \\ \qquad + \begin{array}[t]{@{}r@{~}l@{}} + (\iff & F.\AMODULE.\MIDATAS[x] \ne \epsilon \\ + \wedge & d \leq |\SMEMS[F.\AMODULE.\MIMEMS[0]]| \\ + \wedge & s \leq |\SDATA[F.\AMODULE.\MIDATAS[x]]|) \\ + \end{array} + \\[1ex] + \begin{array}{lcl@{\qquad}l} + S; F; (\I32.\CONST~d)~(\I32.\CONST~s)~(\I32.\CONST~n)~(\MEMORYINIT~x) &\stepto& S; F; \TRAP + \end{array} + \\ \qquad + (\otherwise) \\ + \end{array} + + +.. _exec-data.drop: + +:math:`\DATADROP~x` +................... + +1. Let :math:`F` be the :ref:`current ` :ref:`frame `. + +2. Assert: due to :ref:`validation `, :math:`F.\AMODULE.\MIDATAS[x]` exists. + +3. Let :math:`a^?` be the optional :ref:`data address ` :math:`F.\AMODULE.\MIDATAS[x]`. + +4. If :math:`a^? = \epsilon`, then: + + a. Trap. + +5. Replace :math:`F.\AMODULE.\MIDATAS[x]` with :math:`\epsilon`. + +.. math:: + \begin{array}{lcl@{\qquad}l} + F; (\DATADROP~x) &\stepto& F'; \epsilon + & (\iff F' = F \with \AMODULE.\MIDATAS[x] = \epsilon) \\ + F; (\DATADROP~x) &\stepto& F; \TRAP + & (\otherwise) \\ + \end{array} + + .. index:: control instructions, structured control, label, block, branch, result type, label index, function index, type index, vector, address, table address, table instance, store, frame pair: execution; instruction single: abstract syntax; instruction diff --git a/document/core/exec/runtime.rst b/document/core/exec/runtime.rst index 204b5fc589..c3044c35db 100644 --- a/document/core/exec/runtime.rst +++ b/document/core/exec/runtime.rst @@ -72,8 +72,8 @@ Syntactically, the store is defined as a :ref:`record ` listing \STABLES & \tableinst^\ast, \\ \SMEMS & \meminst^\ast, \\ \SGLOBALS & \globalinst^\ast, \\ - \SELEM & (\eleminst^?)^\ast, \\ - \SDATA & (\datainst^?)^\ast ~\} \\ + \SELEM & \eleminst^\ast, \\ + \SDATA & \datainst^\ast ~\} \\ \end{array} \end{array} From 80aea4a426ad3b5e81c2350886302ab9312eb370 Mon Sep 17 00:00:00 2001 From: Ben Smith Date: Sat, 8 Jun 2019 11:35:21 -0700 Subject: [PATCH 107/199] [spec] Use optional data instance, not data address (#93) data.drop must update the store, not the frame. There may be multiple copies of the frame, so any updates will only update once. We can make sure that all copies are updated by using an indirection through data addresses and updating the store instead. See discussion in PR #92. --- document/core/exec/instructions.rst | 69 ++++++++++++++++++----------- document/core/exec/runtime.rst | 11 +++-- 2 files changed, 50 insertions(+), 30 deletions(-) diff --git a/document/core/exec/instructions.rst b/document/core/exec/instructions.rst index 185d001d06..b55f637b01 100644 --- a/document/core/exec/instructions.rst +++ b/document/core/exec/instructions.rst @@ -704,29 +704,31 @@ Memory Instructions 5. Let :math:`\X{mem}` be the :ref:`memory instance ` :math:`S.\SMEMS[\X{ma}]`. -6. Assert: due to :ref:`validation `, :math:`F.\AMODULE.\MIDATAS[x]` exists. +6. Assert: due to :ref:`validation `, :math:`F.\AMODULE.\MIDATAS[x]` exists. -7. Let :math:`\X{da}^?` be the optional :ref:`data address ` :math:`F.\AMODULE.\MIDATAS[x]`. +7. Let :math:`\X{da}` be the :ref:`data address ` :math:`F.\AMODULE.\MIDATAS[x]`. -8. If :math:`\X{da}^? = \epsilon`, then: +8. Assert: due to :ref:`validation `, :math:`S.\SDATA[\X{da}]` exists. - a. Trap. +9. Let :math:`\X{data}^?` be the optional :ref:`data instance ` :math:`S.\SDATA[\X{da}]`. + +10. If :math:`\X{data}^? = \epsilon`, then: -9. Let :math:`\X{data}` be the :ref:`data instance ` :math:`S.\SDATA[\X{da}]`. + a. Trap. -10. Assert: due to :ref:`validation `, a value of :ref:`value type ` |I32| is on the top of the stack. +11. Assert: due to :ref:`validation `, a value of :ref:`value type ` |I32| is on the top of the stack. -11. Pop the value :math:`\I32.\CONST~n` from the stack. +12. Pop the value :math:`\I32.\CONST~n` from the stack. -12. Assert: due to :ref:`validation `, a value of :ref:`value type ` |I32| is on the top of the stack. +13. Assert: due to :ref:`validation `, a value of :ref:`value type ` |I32| is on the top of the stack. -13. Pop the value :math:`\I32.\CONST~s` from the stack. +14. Pop the value :math:`\I32.\CONST~s` from the stack. -14. Assert: due to :ref:`validation `, a value of :ref:`value type ` |I32| is on the top of the stack. +15. Assert: due to :ref:`validation `, a value of :ref:`value type ` |I32| is on the top of the stack. -15. Pop the value :math:`\I32.\CONST~d` from the stack. +16. Pop the value :math:`\I32.\CONST~d` from the stack. -16. If :math:`n` is :math:`0`, then: +17. If :math:`n` is :math:`0`, then: a. If :math:`d` is larger than the length of :math:`\X{mem}.\MIDATA`, then: @@ -736,7 +738,7 @@ Memory Instructions i. Trap. -17. Else: +18. Else: a. Push the value :math:`\I32.\CONST~d` to the stack. @@ -755,6 +757,7 @@ Memory Instructions h. Execute the instruction :math:`\MEMORYINIT~x`. .. math:: + ~\\[-1ex] \begin{array}{l} \begin{array}{lcl@{\qquad}l} S; F; (\I32.\CONST~d)~(\I32.\CONST~s)~(\I32.\CONST~(n+1))~(\MEMORYINIT~x) &\stepto& S; F; @@ -765,8 +768,8 @@ Memory Instructions \end{array} \\ \\ \qquad \begin{array}[t]{@{}r@{~}l@{}} - (\iff & F.\AMODULE.\MIDATAS[x] \ne \epsilon \\ - \wedge & b = \SDATA[F.\AMODULE.\MIDATAS[x]].\DIINIT[s]) \\ + (\iff & s < |S.\SDATA[F.\AMODULE.\MIDATAS[x]].\DIINIT| \\ + \wedge & b = S.\SDATA[F.\AMODULE.\MIDATAS[x]].\DIINIT[s]) \\ \end{array} \\[1ex] \begin{array}{lcl@{\qquad}l} @@ -774,9 +777,8 @@ Memory Instructions \end{array} \\ \qquad \begin{array}[t]{@{}r@{~}l@{}} - (\iff & F.\AMODULE.\MIDATAS[x] \ne \epsilon \\ - \wedge & d \leq |\SMEMS[F.\AMODULE.\MIMEMS[0]]| \\ - \wedge & s \leq |\SDATA[F.\AMODULE.\MIDATAS[x]]|) \\ + (\iff & d \leq |S.\SMEMS[F.\AMODULE.\MIMEMS[0]].\MIDATA| \\ + \wedge & s \leq |S.\SDATA[F.\AMODULE.\MIDATAS[x]].\DIINIT|) \\ \end{array} \\[1ex] \begin{array}{lcl@{\qquad}l} @@ -794,22 +796,37 @@ Memory Instructions 1. Let :math:`F` be the :ref:`current ` :ref:`frame `. -2. Assert: due to :ref:`validation `, :math:`F.\AMODULE.\MIDATAS[x]` exists. +2. Assert: due to :ref:`validation `, :math:`F.\AMODULE.\MIDATAS[x]` exists. + +3. Let :math:`a` be the :ref:`data address ` :math:`F.\AMODULE.\MIDATAS[x]`. -3. Let :math:`a^?` be the optional :ref:`data address ` :math:`F.\AMODULE.\MIDATAS[x]`. +4. Assert: due to :ref:`validation `, :math:`S.\SDATA[a]` exists. -4. If :math:`a^? = \epsilon`, then: +5. Let :math:`\X{data}^?` be the optional :ref:`data instance ` :math:`S.\SDATA[a]`. + +6. If :math:`\X{data}^? = \epsilon`, then: a. Trap. -5. Replace :math:`F.\AMODULE.\MIDATAS[x]` with :math:`\epsilon`. +7. Replace :math:`S.\SDATA[a]` with :math:`\epsilon`. .. math:: + ~\\[-1ex] + \begin{array}{l} \begin{array}{lcl@{\qquad}l} - F; (\DATADROP~x) &\stepto& F'; \epsilon - & (\iff F' = F \with \AMODULE.\MIDATAS[x] = \epsilon) \\ - F; (\DATADROP~x) &\stepto& F; \TRAP - & (\otherwise) \\ + S; F; (\DATADROP~x) &\stepto& S'; F; \epsilon + \end{array} + \\ \qquad + \begin{array}[t]{@{}r@{~}l@{}} + (\iff & S.\SDATA[F.\AMODULE.\MIDATAS[x]] \ne \epsilon \\ + \wedge & S' = S \with \SDATA[F.\AMODULE.\MIDATAS[x]] = \epsilon) \\ + \end{array} + \\[1ex] + \begin{array}{lcl@{\qquad}l} + S; F; (\DATADROP~x) &\stepto& S; F; \TRAP + \end{array} + \\ \qquad + (\otherwise) \end{array} diff --git a/document/core/exec/runtime.rst b/document/core/exec/runtime.rst index c3044c35db..60ee171601 100644 --- a/document/core/exec/runtime.rst +++ b/document/core/exec/runtime.rst @@ -62,6 +62,9 @@ Store The *store* represents all global state that can be manipulated by WebAssembly programs. It consists of the runtime representation of all *instances* of :ref:`functions `, :ref:`tables `, :ref:`memories `, and :ref:`globals `, :ref:`element segments `, and :ref:`data segments ` that have been :ref:`allocated ` during the life time of the abstract machine. [#gc]_ +Element and data segments can be dropped by the owning module, in which case the respective instances are replaced with :math:`\epsilon`. +It is an invariant of the semantics that no element or data instance is :ref:`addressed ` from anywhere else but the owning module instances. + Syntactically, the store is defined as a :ref:`record ` listing the existing instances of each category: .. math:: @@ -72,8 +75,8 @@ Syntactically, the store is defined as a :ref:`record ` listing \STABLES & \tableinst^\ast, \\ \SMEMS & \meminst^\ast, \\ \SGLOBALS & \globalinst^\ast, \\ - \SELEM & \eleminst^\ast, \\ - \SDATA & \datainst^\ast ~\} \\ + \SELEM & (\eleminst^?)^\ast, \\ + \SDATA & (\datainst^?)^\ast ~\} \\ \end{array} \end{array} @@ -170,8 +173,8 @@ and collects runtime representations of all entities that are imported, defined, \MITABLES & \tableaddr^\ast, \\ \MIMEMS & \memaddr^\ast, \\ \MIGLOBALS & \globaladdr^\ast, \\ - \MIELEMS & (\elemaddr^?)^\ast, \\ - \MIDATAS & (\dataaddr^?)^\ast, \\ + \MIELEMS & \elemaddr^\ast, \\ + \MIDATAS & \dataaddr^\ast, \\ \MIEXPORTS & \exportinst^\ast ~\} \\ \end{array} \end{array} From 983df68a7b65e3b4981d8618f7ccac0826d4245f Mon Sep 17 00:00:00 2001 From: Ben Smith Date: Thu, 27 Jun 2019 17:30:26 -0700 Subject: [PATCH 108/199] [spec] Add `table.init`, `elem.drop` exec text (#95) This also adds `table.set` and `table.get` administrative instructions. Only `table.set` is used for now, but `table.copy` will use both. --- document/core/exec/conventions.rst | 2 +- document/core/exec/instructions.rst | 239 ++++++++++++++++++++++++++++ document/core/exec/runtime.rst | 9 ++ document/core/util/macros.def | 2 + 4 files changed, 251 insertions(+), 1 deletion(-) diff --git a/document/core/exec/conventions.rst b/document/core/exec/conventions.rst index 807239b044..3e14d8e875 100644 --- a/document/core/exec/conventions.rst +++ b/document/core/exec/conventions.rst @@ -33,7 +33,7 @@ The following conventions are adopted in stating these rules. * The execution rules also assume the presence of an implicit :ref:`stack ` that is modified by *pushing* or *popping* - :ref:`values `, :ref:`labels `, and :ref:`frames `. + :ref:`values `, :ref:`function elements `, :ref:`labels `, and :ref:`frames `. * Certain rules require the stack to contain at least one frame. The most recent frame is referred to as the *current* frame. diff --git a/document/core/exec/instructions.rst b/document/core/exec/instructions.rst index b55f637b01..71d15d307b 100644 --- a/document/core/exec/instructions.rst +++ b/document/core/exec/instructions.rst @@ -830,6 +830,245 @@ Memory Instructions \end{array} +.. index:: table instruction, table index, store, frame, address, table address, table instance, function element, element address, element instance, value type + pair: execution; instruction + single: abstract syntax; instruction +.. _exec-instr-table: + +Table Instructions +~~~~~~~~~~~~~~~~~~ + +.. _exec-table.init: + +:math:`\TABLEINIT~x` +.................... + +1. Let :math:`F` be the :ref:`current ` :ref:`frame `. + +2. Assert: due to :ref:`validation `, :math:`F.\AMODULE.\MITABLES[0]` exists. + +3. Let :math:`\X{ta}` be the :ref:`table address ` :math:`F.\AMODULE.\MITABLES[0]`. + +4. Assert: due to :ref:`validation `, :math:`S.\STABLES[\X{ta}]` exists. + +5. Let :math:`\X{table}` be the :ref:`table instance ` :math:`S.\STABLES[\X{ta}]`. + +6. Assert: due to :ref:`validation `, :math:`F.\AMODULE.\MIELEMS[x]` exists. + +7. Let :math:`\X{ea}` be the :ref:`element address ` :math:`F.\AMODULE.\MIELEMS[x]`. + +8. Assert: due to :ref:`validation `, :math:`S.\SELEM[\X{ea}]` exists. + +9. Let :math:`\X{elem}^?` be the optional :ref:`element instance ` :math:`S.\SELEM[\X{ea}]`. + +10. If :math:`\X{elem}^? = \epsilon`, then: + + a. Trap. + +11. Assert: due to :ref:`validation `, a value of :ref:`value type ` |I32| is on the top of the stack. + +12. Pop the value :math:`\I32.\CONST~n` from the stack. + +13. Assert: due to :ref:`validation `, a value of :ref:`value type ` |I32| is on the top of the stack. + +14. Pop the value :math:`\I32.\CONST~s` from the stack. + +15. Assert: due to :ref:`validation `, a value of :ref:`value type ` |I32| is on the top of the stack. + +16. Pop the value :math:`\I32.\CONST~d` from the stack. + +17. If :math:`n` is :math:`0`, then: + + a. If :math:`d` is larger than the length of :math:`\X{table}.\TIELEM`, then: + + i. Trap. + + b. If :math:`s` is larger than the length of :math:`\X{elem}.\EIINIT`, then: + + i. Trap. + +18. Else: + + a. Push the value :math:`\I32.\CONST~d` to the stack. + + b. Let :math:`\funcelem` be the :ref:`function element ` :math:`\X{elem}.\EIINIT[s]`. + + d. Execute the instruction :math:`\TABLESET~\funcelem`. + + e. Push the value :math:`\I32.\CONST~(d+1)` to the stack. + + f. Push the value :math:`\I32.\CONST~(s+1)` to the stack. + + g. Push the value :math:`\I32.\CONST~(n-1)` to the stack. + + h. Execute the instruction :math:`\TABLEINIT~x`. + +.. math:: + ~\\[-1ex] + \begin{array}{l} + \begin{array}{lcl@{\qquad}l} + S; F; (\I32.\CONST~d)~(\I32.\CONST~s)~(\I32.\CONST~(n+1))~(\TABLEINIT~x) &\stepto& S; F; + \begin{array}[t]{@{}l@{}} + (\I32.\CONST~d)~\funcelem~\TABLESET \\ + (\I32.\CONST~(d+1))~(\I32.\CONST~(s+1))~(\I32.\CONST~n)~(\TABLEINIT~x) \\ + \end{array} \\ + \end{array} \\ + \\ \qquad + \begin{array}[t]{@{}r@{~}l@{}} + (\iff & s < |S.\SELEM[F.\AMODULE.\MIELEMS[x]].\EIINIT| \\ + \wedge & \funcelem = S.\SELEM[F.\AMODULE.\MIELEMS[x]].\EIINIT[s]) \\ + \end{array} + \\[1ex] + \begin{array}{lcl@{\qquad}l} + S; F; (\I32.\CONST~d)~(\I32.\CONST~(s)~(\I32.\CONST~0)~(\TABLEINIT~x) &\stepto& S; F; \epsilon + \end{array} + \\ \qquad + \begin{array}[t]{@{}r@{~}l@{}} + (\iff & d \leq |S.\STABLES[F.\AMODULE.\MITABLES[0]].\TIELEM| \\ + \wedge & s \leq |S.\SELEM[F.\AMODULE.\MIELEMS[x]].\EIINIT|) \\ + \end{array} + \\[1ex] + \begin{array}{lcl@{\qquad}l} + S; F; (\I32.\CONST~d)~(\I32.\CONST~s)~(\I32.\CONST~n)~(\TABLEINIT~x) &\stepto& S; F; \TRAP + \end{array} + \\ \qquad + (\otherwise) \\ + \end{array} + + +.. _exec-elem.drop: + +:math:`\ELEMDROP~x` +................... + +1. Let :math:`F` be the :ref:`current ` :ref:`frame `. + +2. Assert: due to :ref:`validation `, :math:`F.\AMODULE.\MIELEMS[x]` exists. + +3. Let :math:`a` be the :ref:`element address ` :math:`F.\AMODULE.\MIELEMS[x]`. + +4. Assert: due to :ref:`validation `, :math:`S.\SELEM[a]` exists. + +5. Let :math:`\X{elem}^?` be the optional :ref:`elem instance ` :math:`S.\SELEM[a]`. + +6. If :math:`\X{elem}^? = \epsilon`, then: + + a. Trap. + +7. Replace :math:`S.\SELEM[a]` with :math:`\epsilon`. + +.. math:: + ~\\[-1ex] + \begin{array}{l} + \begin{array}{lcl@{\qquad}l} + S; F; (\ELEMDROP~x) &\stepto& S'; F; \epsilon + \end{array} + \\ \qquad + \begin{array}[t]{@{}r@{~}l@{}} + (\iff & S.\SELEM[F.\AMODULE.\MIELEMS[x]] \ne \epsilon \\ + \wedge & S' = S \with \SELEM[F.\AMODULE.\MIELEMS[x]] = \epsilon) \\ + \end{array} + \\[1ex] + \begin{array}{lcl@{\qquad}l} + S; F; (\ELEMDROP~x) &\stepto& S; F; \TRAP + \end{array} + \\ \qquad + (\otherwise) + \end{array} + + +.. _exec-table.get: + +:math:`\TABLEGET` +................. + +1. Let :math:`F` be the :ref:`current ` :ref:`frame `. + +2. Assert: :math:`F.\AMODULE.\MITABLES[0]` exists. + +3. Let :math:`\X{ta}` be the :ref:`table address ` :math:`F.\AMODULE.\MITABLES[0]`. + +4. Assert: :math:`S.\STABLES[\X{ta}]` exists. + +5. Let :math:`\X{tab}` be the :ref:`table instance ` :math:`S.\STABLES[\X{ta}]`. + +6. Assert: a value of :ref:`value type ` |I32| is on the top of the stack. + +7. Pop the value :math:`\I32.\CONST~i` from the stack. + +8. If :math:`i` is not smaller than the length of :math:`\X{tab}.\TIELEM`, then: + + a. Trap. + +9. Push the :ref:`function element ` :math:`X{tab}.\TIELEM[i]` to the stack. + +.. math:: + ~\\[-1ex] + \begin{array}{l} + \begin{array}{lcl@{\qquad}l} + S; F; (\I32.\CONST~i)~\TABLEGET &\stepto& S; F; \funcelem + \end{array} + \\ \qquad + \begin{array}[t]{@{}r@{~}l@{}} + (\iff & \funcelem = S.\STABLES[F.\AMODULE.\MITABLES[0]].\TIELEM[i]) + \end{array} + \\[1ex] + \begin{array}{lcl@{\qquad}l} + S; F; (\I32.\CONST~i)~\TABLEGET &\stepto& S; F; \TRAP + \end{array} + \\ \qquad + (\otherwise) \\ + \end{array} + + +.. _exec-table.set: + +:math:`\TABLESET` +................. + +1. Let :math:`F` be the :ref:`current ` :ref:`frame `. + +2. Assert: :math:`F.\AMODULE.\MITABLES[0]` exists. + +3. Let :math:`\X{ta}` be the :ref:`table address ` :math:`F.\AMODULE.\MITABLES[0]`. + +4. Assert: :math:`S.\STABLES[\X{ta}]` exists. + +5. Let :math:`\X{tab}` be the :ref:`table instance ` :math:`S.\STABLES[\X{ta}]`. + +6. Assert: a :ref:`function element ` is on the top of the stack. + +7. Pop the function element :math:`\funcelem` from the stack. + +8. Assert: a value of :ref:`value type ` |I32| is on the top of the stack. + +9. Pop the value :math:`\I32.\CONST~i` from the stack. + +10. If :math:`i` is not smaller than the length of :math:`\X{tab}.\TIELEM`, then: + + a. Trap. + +11. Replace :math:`X{tab}.\TIELEM[i]` with :math:`\funcelem`. + +.. math:: + ~\\[-1ex] + \begin{array}{l} + \begin{array}{lcl@{\qquad}l} + S; F; (\I32.\CONST~i)~\funcelem~\TABLESET &\stepto& S'; F; \epsilon + \end{array} + \\ \qquad + \begin{array}[t]{@{}r@{~}l@{}} + (\iff & S' = S \with \STABLES[F.\AMODULE.\MITABLES[0]].\TIELEM[i] = \funcelem) + \end{array} + \\[1ex] + \begin{array}{lcl@{\qquad}l} + S; F; (\I32.\CONST~i)~\funcelem~\TABLESET &\stepto& S; F; \TRAP + \end{array} + \\ \qquad + (\otherwise) \\ + \end{array} + + .. index:: control instructions, structured control, label, block, branch, result type, label index, function index, type index, vector, address, table address, table instance, store, frame pair: execution; instruction single: abstract syntax; instruction diff --git a/document/core/exec/runtime.rst b/document/core/exec/runtime.rst index 60ee171601..f142122ca1 100644 --- a/document/core/exec/runtime.rst +++ b/document/core/exec/runtime.rst @@ -480,6 +480,8 @@ Conventions .. _syntax-invoke: .. _syntax-init_elem: .. _syntax-init_data: +.. _syntax-table_get: +.. _syntax-table_set: .. _syntax-instr-admin: Administrative Instructions @@ -498,6 +500,8 @@ In order to express the reduction of :ref:`traps `, :ref:`calls ` and :ref:`frames ` :ref:`"on the stack" `. Moreover, the administrative syntax maintains the nesting structure of the original :ref:`structured control instruction ` or :ref:`function body ` and their :ref:`instruction sequences ` with an |END| marker. That way, the end of the inner instruction sequence is known when part of an outer sequence. diff --git a/document/core/util/macros.def b/document/core/util/macros.def index d53e271595..50160af99b 100644 --- a/document/core/util/macros.def +++ b/document/core/util/macros.def @@ -922,6 +922,8 @@ .. |INVOKE| mathdef:: \xref{exec/runtime}{syntax-invoke}{\K{invoke}} .. |INITELEM| mathdef:: \xref{exec/runtime}{syntax-init_elem}{\K{init\_elem}} .. |INITDATA| mathdef:: \xref{exec/runtime}{syntax-init_data}{\K{init\_data}} +.. |TABLEGET| mathdef:: \xref{exec/runtime}{syntax-table_get}{\K{table.get} +.. |TABLESET| mathdef:: \xref{exec/runtime}{syntax-table_set}{\K{table.set} .. Values & Results, non-terminals From d976981cd42e4252246248f55fe703698f313b33 Mon Sep 17 00:00:00 2001 From: Ben Smith Date: Fri, 28 Jun 2019 10:16:18 -0700 Subject: [PATCH 109/199] Update overview for the zero-byte OOB case (#100) It's only a trap if a byte is accessed out-of-bounds, not if the destination or source index is out-of-bounds. This only makes a difference when the length is zero, in which case the previous behavior would trap, and the new behavior will be a no-op. --- proposals/bulk-memory-operations/Overview.md | 5 ----- 1 file changed, 5 deletions(-) diff --git a/proposals/bulk-memory-operations/Overview.md b/proposals/bulk-memory-operations/Overview.md index 2955afef31..c5d92eeb38 100644 --- a/proposals/bulk-memory-operations/Overview.md +++ b/proposals/bulk-memory-operations/Overview.md @@ -277,8 +277,6 @@ A trap occurs if: active segments that were dropped after being copied into memory during module instantiation. * any of the accessed bytes lies outside the source data segment or the target memory -* the source offset is greater than the length of the source data segment -* the destination offset is greater than the length of the target memory Note that it is allowed to use `memory.init` on the same data segment more than once. @@ -342,8 +340,6 @@ The instruction has the signature `[i32 i32 i32] -> []`. The parameters are, in A trap occurs if: * any of the accessed bytes lies outside the source or target memory -* the source offset is greater than the length of the source memory -* the destination offset is greater than the length of the target memory A trap resulting from an access outside the source or target region only occurs once the first byte that is outside the source or target @@ -367,7 +363,6 @@ The instruction has the signature `[i32 i32 i32] -> []`. The parameters are, in A trap occurs if: * any of the accessed bytes lies outside the target memory -* the destination offset is greater than the length of the target memory Filling takes place bytewise from lower addresses toward higher addresses. A trap resulting from an access outside the target memory From 8c6ea224d084e67e15efd2db79b1a605a28cc521 Mon Sep 17 00:00:00 2001 From: Ben Smith Date: Fri, 28 Jun 2019 11:37:28 -0700 Subject: [PATCH 110/199] [spec] Update text for zero-byte OOB case (#101) Also fix some typos from previous CL (see macros.def) --- document/core/exec/instructions.rst | 67 ++++++----------------------- document/core/util/macros.def | 4 +- 2 files changed, 14 insertions(+), 57 deletions(-) diff --git a/document/core/exec/instructions.rst b/document/core/exec/instructions.rst index 71d15d307b..5706ab5466 100644 --- a/document/core/exec/instructions.rst +++ b/document/core/exec/instructions.rst @@ -645,13 +645,7 @@ Memory Instructions 11. Pop the value :math:`\I32.\CONST~i` from the stack. -12. If :math:`n` is :math:`0`, then: - - a. If :math:`i` is larger than the length of :math:`\X{mem}.\MIDATA`, then: - - i. Trap. - -13. Else: +12. Else: a. Push the value :math:`\I32.\CONST~i` to the stack. @@ -678,14 +672,7 @@ Memory Instructions \end{array} \\ \begin{array}{lcl@{\qquad}l} S; F; (\I32.\CONST~i)~\val~(\I32.\CONST~0)~(\MEMORYFILL) &\stepto& S; F; \epsilon - \end{array} - \\ \qquad - (\iff i \leq |\SMEMS[F.\AMODULE.\MIMEMS[0]]|) \\ - \begin{array}{lcl@{\qquad}l} - S; F; (\I32.\CONST~i)~\val~(\I32.\CONST~0)~(\MEMORYFILL) &\stepto& S; F; \TRAP - \end{array} - \\ \qquad - (\otherwise) \\ + \end{array} \\ \end{array} @@ -728,17 +715,7 @@ Memory Instructions 16. Pop the value :math:`\I32.\CONST~d` from the stack. -17. If :math:`n` is :math:`0`, then: - - a. If :math:`d` is larger than the length of :math:`\X{mem}.\MIDATA`, then: - - i. Trap. - - b. If :math:`s` is larger than the length of :math:`\X{data}.\DIINIT`, then: - - i. Trap. - -18. Else: +17. Else: a. Push the value :math:`\I32.\CONST~d` to the stack. @@ -760,6 +737,10 @@ Memory Instructions ~\\[-1ex] \begin{array}{l} \begin{array}{lcl@{\qquad}l} + S; F; (\I32.\CONST~d)~(\I32.\CONST~s)~(\I32.\CONST~0)~(\MEMORYINIT~x) &\stepto& S; F; \epsilon + \end{array} + \\[1ex] + \begin{array}{lcl@{\qquad}l} S; F; (\I32.\CONST~d)~(\I32.\CONST~s)~(\I32.\CONST~(n+1))~(\MEMORYINIT~x) &\stepto& S; F; \begin{array}[t]{@{}l@{}} (\I32.\CONST~d)~(\I32.\CONST~b)~(\I32\K{.}\STORE\K{8}~\{ \OFFSET~0, \ALIGN~0 \}) \\ @@ -773,15 +754,6 @@ Memory Instructions \end{array} \\[1ex] \begin{array}{lcl@{\qquad}l} - S; F; (\I32.\CONST~d)~(\I32.\CONST~(s)~(\I32.\CONST~0)~(\MEMORYINIT~x) &\stepto& S; F; \epsilon - \end{array} - \\ \qquad - \begin{array}[t]{@{}r@{~}l@{}} - (\iff & d \leq |S.\SMEMS[F.\AMODULE.\MIMEMS[0]].\MIDATA| \\ - \wedge & s \leq |S.\SDATA[F.\AMODULE.\MIDATAS[x]].\DIINIT|) \\ - \end{array} - \\[1ex] - \begin{array}{lcl@{\qquad}l} S; F; (\I32.\CONST~d)~(\I32.\CONST~s)~(\I32.\CONST~n)~(\MEMORYINIT~x) &\stepto& S; F; \TRAP \end{array} \\ \qquad @@ -877,17 +849,7 @@ Table Instructions 16. Pop the value :math:`\I32.\CONST~d` from the stack. -17. If :math:`n` is :math:`0`, then: - - a. If :math:`d` is larger than the length of :math:`\X{table}.\TIELEM`, then: - - i. Trap. - - b. If :math:`s` is larger than the length of :math:`\X{elem}.\EIINIT`, then: - - i. Trap. - -18. Else: +17. Else: a. Push the value :math:`\I32.\CONST~d` to the stack. @@ -907,6 +869,10 @@ Table Instructions ~\\[-1ex] \begin{array}{l} \begin{array}{lcl@{\qquad}l} + S; F; (\I32.\CONST~d)~(\I32.\CONST~(s)~(\I32.\CONST~0)~(\TABLEINIT~x) &\stepto& S; F; \epsilon + \end{array} + \\[1ex] + \begin{array}{lcl@{\qquad}l} S; F; (\I32.\CONST~d)~(\I32.\CONST~s)~(\I32.\CONST~(n+1))~(\TABLEINIT~x) &\stepto& S; F; \begin{array}[t]{@{}l@{}} (\I32.\CONST~d)~\funcelem~\TABLESET \\ @@ -920,15 +886,6 @@ Table Instructions \end{array} \\[1ex] \begin{array}{lcl@{\qquad}l} - S; F; (\I32.\CONST~d)~(\I32.\CONST~(s)~(\I32.\CONST~0)~(\TABLEINIT~x) &\stepto& S; F; \epsilon - \end{array} - \\ \qquad - \begin{array}[t]{@{}r@{~}l@{}} - (\iff & d \leq |S.\STABLES[F.\AMODULE.\MITABLES[0]].\TIELEM| \\ - \wedge & s \leq |S.\SELEM[F.\AMODULE.\MIELEMS[x]].\EIINIT|) \\ - \end{array} - \\[1ex] - \begin{array}{lcl@{\qquad}l} S; F; (\I32.\CONST~d)~(\I32.\CONST~s)~(\I32.\CONST~n)~(\TABLEINIT~x) &\stepto& S; F; \TRAP \end{array} \\ \qquad diff --git a/document/core/util/macros.def b/document/core/util/macros.def index 50160af99b..be0829cfff 100644 --- a/document/core/util/macros.def +++ b/document/core/util/macros.def @@ -922,8 +922,8 @@ .. |INVOKE| mathdef:: \xref{exec/runtime}{syntax-invoke}{\K{invoke}} .. |INITELEM| mathdef:: \xref{exec/runtime}{syntax-init_elem}{\K{init\_elem}} .. |INITDATA| mathdef:: \xref{exec/runtime}{syntax-init_data}{\K{init\_data}} -.. |TABLEGET| mathdef:: \xref{exec/runtime}{syntax-table_get}{\K{table.get} -.. |TABLESET| mathdef:: \xref{exec/runtime}{syntax-table_set}{\K{table.set} +.. |TABLEGET| mathdef:: \xref{exec/runtime}{syntax-table_get}{\K{table.get}} +.. |TABLESET| mathdef:: \xref{exec/runtime}{syntax-table_set}{\K{table.set}} .. Values & Results, non-terminals From d18ec64a8abca947ef6f27ab9cac4a490a322da8 Mon Sep 17 00:00:00 2001 From: Ben Smith Date: Fri, 28 Jun 2019 15:15:47 -0700 Subject: [PATCH 111/199] [interp] Don't trap on zero-bytes out-of-bounds (#102) --- interpreter/runtime/memory.ml | 17 +++------------ interpreter/runtime/table.ml | 11 +++------- test/core/bulk.wast | 35 ++++++++++++------------------- test/core/data.wast | 19 +++++++---------- test/core/elem.wast | 10 ++++----- test/core/memory_copy.wast | 4 ++-- test/core/memory_fill.wast | 2 +- test/core/memory_init.wast | 4 ++-- test/core/table_copy.wast | 4 ++-- test/core/table_init.wast | 4 ++-- test/meta/generate_memory_copy.js | 8 +++---- test/meta/generate_memory_fill.js | 4 ++-- test/meta/generate_memory_init.js | 8 +++---- test/meta/generate_table_copy.js | 8 +++---- test/meta/generate_table_init.js | 8 +++---- 15 files changed, 57 insertions(+), 89 deletions(-) diff --git a/interpreter/runtime/memory.ml b/interpreter/runtime/memory.ml index 2df2efd6c1..6a0544764b 100644 --- a/interpreter/runtime/memory.ml +++ b/interpreter/runtime/memory.ml @@ -145,11 +145,6 @@ let store_packed sz mem a o v = | _ -> raise Type in storen mem a o n x -let check_str_bounds bs a = - if I64.gt_u a (Int64.of_int (String.length bs)) then raise Bounds - -let check_bounds mem a = if I64.gt_u a (bound mem) then raise Bounds - let init mem bs d s n = let load_str_byte a = try Char.code bs.[Int64.to_int a] @@ -159,10 +154,7 @@ let init mem bs d s n = store_byte mem d (load_str_byte s); loop (Int64.add d 1L) (Int64.add s 1L) (Int32.sub n 1l) end - in loop d s n; - let n' = I64_convert.extend_i32_u n in - check_bounds mem (Int64.add d n'); - check_str_bounds bs (Int64.add s n') + in loop d s n let copy mem d s n = let n' = I64_convert.extend_i32_u n in @@ -175,9 +167,7 @@ let copy mem d s n = in (if overlap && s < d then loop Int64.(add d (sub n' 1L)) Int64.(add s (sub n' 1L)) n (-1L) else - loop d s n 1L); - check_bounds mem (Int64.add d n'); - check_bounds mem (Int64.add s n') + loop d s n 1L) let fill mem a v n = let rec loop a n = @@ -185,5 +175,4 @@ let fill mem a v n = store_byte mem a v; loop (Int64.add a 1L) (Int32.sub n 1l) end - in loop a n; - check_bounds mem (Int64.add a (I64_convert.extend_i32_u n)) + in loop a n diff --git a/interpreter/runtime/table.ml b/interpreter/runtime/table.ml index b08a0e7188..109d7447ef 100644 --- a/interpreter/runtime/table.ml +++ b/interpreter/runtime/table.ml @@ -49,19 +49,16 @@ let load tab i = let store tab i v = try Lib.Array32.set tab.content i v with Invalid_argument _ -> raise Bounds -let check_bounds tab i = if I32.gt_u i (size tab) then raise Bounds - let init tab es d s n = let rec loop es d s n = match s, n, es with - | 0l, 0l, _ -> () + | s, 0l, _ -> () | 0l, n, e::es' -> store tab d e; loop es' (Int32.add d 1l) 0l (Int32.sub n 1l) | s, n, _::es' -> loop es' d (Int32.sub s 1l) n | _ -> raise Bounds - in loop es d s n; - check_bounds tab (Int32.add d n) + in loop es d s n let copy tab d s n = let overlap = I32.lt_u Int32.(abs (sub d s)) n in @@ -73,6 +70,4 @@ let copy tab d s n = in (if overlap && s < d then loop Int32.(add d (sub n 1l)) Int32.(add s (sub n 1l)) n (-1l) else - loop d s n 1l); - check_bounds tab (Int32.add d n); - check_bounds tab (Int32.add s n) + loop d s n 1l) diff --git a/test/core/bulk.wast b/test/core/bulk.wast index 0b32679986..e01908d244 100644 --- a/test/core/bulk.wast +++ b/test/core/bulk.wast @@ -48,9 +48,8 @@ ;; Succeed when writing 0 bytes at the end of the region. (invoke "fill" (i32.const 0x10000) (i32.const 0) (i32.const 0)) -;; Fail on out-of-bounds when writing 0 bytes outside of memory. -(assert_trap (invoke "fill" (i32.const 0x10001) (i32.const 0) (i32.const 0)) - "out of bounds memory access") +;; OK to write 0 bytes outside of memory. +(invoke "fill" (i32.const 0x10001) (i32.const 0) (i32.const 0)) ;; memory.copy @@ -110,11 +109,9 @@ (invoke "copy" (i32.const 0x10000) (i32.const 0) (i32.const 0)) (invoke "copy" (i32.const 0) (i32.const 0x10000) (i32.const 0)) -;; Fail on out-of-bounds when copying 0 bytes outside of memory. -(assert_trap (invoke "copy" (i32.const 0x10001) (i32.const 0) (i32.const 0)) - "out of bounds memory access") -(assert_trap (invoke "copy" (i32.const 0) (i32.const 0x10001) (i32.const 0)) - "out of bounds memory access") +;; OK to copy 0 bytes outside of memory. +(invoke "copy" (i32.const 0x10001) (i32.const 0) (i32.const 0)) +(invoke "copy" (i32.const 0) (i32.const 0x10001) (i32.const 0)) ;; memory.init @@ -150,11 +147,9 @@ (invoke "init" (i32.const 0x10000) (i32.const 0) (i32.const 0)) (invoke "init" (i32.const 0) (i32.const 4) (i32.const 0)) -;; Fail on out-of-bounds when writing 0 bytes outside of memory or segment. -(assert_trap (invoke "init" (i32.const 0x10001) (i32.const 0) (i32.const 0)) - "out of bounds memory access") -(assert_trap (invoke "init" (i32.const 0) (i32.const 5) (i32.const 0)) - "out of bounds memory access") +;; OK to write 0 bytes outside of memory or segment. +(invoke "init" (i32.const 0x10001) (i32.const 0) (i32.const 0)) +(invoke "init" (i32.const 0) (i32.const 5) (i32.const 0)) ;; data.drop (module @@ -216,11 +211,9 @@ (invoke "init" (i32.const 3) (i32.const 0) (i32.const 0)) (invoke "init" (i32.const 0) (i32.const 4) (i32.const 0)) -;; Fail on out-of-bounds when storing 0 elements outside of table or segment. -(assert_trap (invoke "init" (i32.const 4) (i32.const 0) (i32.const 0)) - "out of bounds table access") -(assert_trap (invoke "init" (i32.const 0) (i32.const 5) (i32.const 0)) - "out of bounds table access") +;; OK to storing 0 elements outside of table or segment. +(invoke "init" (i32.const 4) (i32.const 0) (i32.const 0)) +(invoke "init" (i32.const 0) (i32.const 5) (i32.const 0)) ;; elem.drop @@ -302,7 +295,5 @@ (invoke "copy" (i32.const 0) (i32.const 10) (i32.const 0)) ;; Fail on out-of-bounds when copying 0 elements outside of table. -(assert_trap (invoke "copy" (i32.const 11) (i32.const 0) (i32.const 0)) - "out of bounds table access") -(assert_trap (invoke "copy" (i32.const 0) (i32.const 11) (i32.const 0)) - "out of bounds table access") +(invoke "copy" (i32.const 11) (i32.const 0) (i32.const 0)) +(invoke "copy" (i32.const 0) (i32.const 11) (i32.const 0)) diff --git a/test/core/data.wast b/test/core/data.wast index 32d05f5e8d..bc94a8f217 100644 --- a/test/core/data.wast +++ b/test/core/data.wast @@ -182,20 +182,15 @@ "data segment does not fit" ) -(assert_unlinkable - (module - (memory 0) - (data (i32.const 1)) - ) - "data segment does not fit" +;; Writing 0 bytes outside of bounds is allowed now. +(module + (memory 0) + (data (i32.const 1)) ) -(assert_unlinkable - (module - (memory 0 1) - (data (i32.const 1)) - ) - "data segment does not fit" +(module + (memory 0 1) + (data (i32.const 1)) ) ;; This seems to cause a time-out on Travis. diff --git a/test/core/elem.wast b/test/core/elem.wast index 726a27fe22..3dac72655a 100644 --- a/test/core/elem.wast +++ b/test/core/elem.wast @@ -166,12 +166,10 @@ "elements segment does not fit" ) -(assert_unlinkable - (module - (table 0 funcref) - (elem (i32.const 1)) - ) - "elements segment does not fit" +;; Writing 0 elems outside of bounds is allowed now. +(module + (table 0 funcref) + (elem (i32.const 1)) ) (assert_unlinkable diff --git a/test/core/memory_copy.wast b/test/core/memory_copy.wast index 46b26a875c..6c2cab5ef7 100644 --- a/test/core/memory_copy.wast +++ b/test/core/memory_copy.wast @@ -5001,7 +5001,7 @@ (memory 1 1) (func (export "test") (memory.copy (i32.const 0x20000) (i32.const 0x7000) (i32.const 0)))) -(assert_trap (invoke "test") "out of bounds") +(invoke "test") (module (memory 1 1) @@ -5013,7 +5013,7 @@ (memory 1 1) (func (export "test") (memory.copy (i32.const 0x9000) (i32.const 0x20000) (i32.const 0)))) -(assert_trap (invoke "test") "out of bounds") +(invoke "test") (module (memory 1 1) diff --git a/test/core/memory_fill.wast b/test/core/memory_fill.wast index 9af6b2459a..bd4d598f9c 100644 --- a/test/core/memory_fill.wast +++ b/test/core/memory_fill.wast @@ -114,7 +114,7 @@ (func (export "test") (memory.fill (i32.const 0x20000) (i32.const 0x55) (i32.const 0)))) -(assert_trap (invoke "test") "out of bounds memory access") +(invoke "test") (module (memory 1 1) diff --git a/test/core/memory_init.wast b/test/core/memory_init.wast index ee2ed36e09..9a6fb7cd6c 100644 --- a/test/core/memory_init.wast +++ b/test/core/memory_init.wast @@ -270,7 +270,7 @@ (data "\37") (func (export "test") (memory.init 0 (i32.const 1234) (i32.const 4) (i32.const 0)))) -(assert_trap (invoke "test") "out of bounds") +(invoke "test") (module (memory 1) @@ -284,7 +284,7 @@ (data "\37") (func (export "test") (memory.init 0 (i32.const 0x10001) (i32.const 0) (i32.const 0)))) -(assert_trap (invoke "test") "out of bounds") +(invoke "test") (module (memory 1) diff --git a/test/core/table_copy.wast b/test/core/table_copy.wast index a68c9c7893..0c03f5bd47 100644 --- a/test/core/table_copy.wast +++ b/test/core/table_copy.wast @@ -633,7 +633,7 @@ (table.copy (i32.const 31) (i32.const 15) (i32.const 0)) )) -(assert_trap (invoke "test") "out of bounds") +(invoke "test") (module (table 30 30 funcref) @@ -681,7 +681,7 @@ (table.copy (i32.const 15) (i32.const 31) (i32.const 0)) )) -(assert_trap (invoke "test") "out of bounds") +(invoke "test") (module (table 30 30 funcref) diff --git a/test/core/table_init.wast b/test/core/table_init.wast index 36834d283c..6cee47156e 100644 --- a/test/core/table_init.wast +++ b/test/core/table_init.wast @@ -446,7 +446,7 @@ (func (export "test") (table.init 1 (i32.const 12) (i32.const 5) (i32.const 0)) )) -(assert_trap (invoke "test") "out of bounds") +(invoke "test") (module (table 30 30 funcref) @@ -492,7 +492,7 @@ (func (export "test") (table.init 1 (i32.const 31) (i32.const 2) (i32.const 0)) )) -(assert_trap (invoke "test") "out of bounds") +(invoke "test") (module (table 30 30 funcref) diff --git a/test/meta/generate_memory_copy.js b/test/meta/generate_memory_copy.js index 2cb26cd613..243fe65252 100644 --- a/test/meta/generate_memory_copy.js +++ b/test/meta/generate_memory_copy.js @@ -304,13 +304,13 @@ print( (invoke "test") `); -// Zero len with dest offset out-of-bounds past the end of memory is not allowed +// Zero len with dest offset out-of-bounds past the end of memory is allowed print( `(module (memory 1 1) (func (export "test") (memory.copy (i32.const 0x20000) (i32.const 0x7000) (i32.const 0)))) -(assert_trap (invoke "test") "out of bounds") +(invoke "test") `); // Zero len with src offset out-of-bounds at the end of memory is allowed @@ -322,13 +322,13 @@ print( (invoke "test") `); -// Zero len with src offset out-of-bounds past the end of memory is not allowed +// Zero len with src offset out-of-bounds past the end of memory is allowed print( `(module (memory 1 1) (func (export "test") (memory.copy (i32.const 0x9000) (i32.const 0x20000) (i32.const 0)))) -(assert_trap (invoke "test") "out of bounds") +(invoke "test") `); // Zero len with both dest and src offsets out-of-bounds at the end of memory is allowed diff --git a/test/meta/generate_memory_fill.js b/test/meta/generate_memory_fill.js index 42c2e196e5..dc94382598 100644 --- a/test/meta/generate_memory_fill.js +++ b/test/meta/generate_memory_fill.js @@ -56,13 +56,13 @@ print( (invoke "test") `); -// Zero len with offset out-of-bounds past the end of memory is not allowed +// Zero len with offset out-of-bounds past the end of memory is allowed print( `(module ${PREAMBLE} (func (export "test") (memory.fill (i32.const 0x20000) (i32.const 0x55) (i32.const 0)))) -(assert_trap (invoke "test") "out of bounds memory access") +(invoke "test") `); // Very large range diff --git a/test/meta/generate_memory_init.js b/test/meta/generate_memory_init.js index c157d7d2e6..e06055476c 100644 --- a/test/meta/generate_memory_init.js +++ b/test/meta/generate_memory_init.js @@ -164,13 +164,13 @@ print( (assert_trap (invoke "test") "out of bounds") `); -// init: seg ix is valid passive, zero len, but src offset past the end +// init: seg ix is valid passive, src offset past the end, zero len is always valid print( `(module ${PREAMBLE} (func (export "test") (memory.init 0 (i32.const 1234) (i32.const 4) (i32.const 0)))) -(assert_trap (invoke "test") "out of bounds") +(invoke "test") `); // init: seg ix is valid passive, zero len, src offset at the end @@ -182,13 +182,13 @@ print( (invoke "test") `); -// init: seg ix is valid passive, zero len, but dst offset past the end +// init: seg ix is valid passive, dst offset past the end, zero len is always valid print( `(module ${PREAMBLE} (func (export "test") (memory.init 0 (i32.const 0x10001) (i32.const 0) (i32.const 0)))) -(assert_trap (invoke "test") "out of bounds") +(invoke "test") `); // init: seg ix is valid passive, zero len, but dst offset at the end diff --git a/test/meta/generate_table_copy.js b/test/meta/generate_table_copy.js index ba2636c4a1..852999afdf 100644 --- a/test/meta/generate_table_copy.js +++ b/test/meta/generate_table_copy.js @@ -189,20 +189,20 @@ tab_test2("(table.copy (i32.const 30) (i32.const 15) (i32.const 0))", "", undefined); -// copy: zero length with dst offset out of bounds past the end of the table is not allowed +// copy: zero length with dst offset out of bounds past the end of the table is allowed tab_test2("(table.copy (i32.const 31) (i32.const 15) (i32.const 0))", "", - "out of bounds"); + undefined); // copy: zero length with src offset out of bounds at the end of the table is allowed tab_test2("(table.copy (i32.const 15) (i32.const 30) (i32.const 0))", "", undefined); -// copy: zero length with src offset out of bounds past the end of the table is not allowed +// copy: zero length with src offset out of bounds past the end of the table is allowed tab_test2("(table.copy (i32.const 15) (i32.const 31) (i32.const 0))", "", - "out of bounds"); + undefined); // copy: zero length with both dst and src offset out of bounds at the end of the table is allowed tab_test2("(table.copy (i32.const 30) (i32.const 30) (i32.const 0))", diff --git a/test/meta/generate_table_init.js b/test/meta/generate_table_init.js index 436dc1e755..8366d19ec7 100644 --- a/test/meta/generate_table_init.js +++ b/test/meta/generate_table_init.js @@ -226,9 +226,9 @@ tab_test1("(table.init 1 (i32.const 12) (i32.const 4) (i32.const 0))", undefined); // init: seg ix is valid passive, zero len, and src offset out of bounds past the -// end of the table - this is not allowed +// end of the table - this is allowed tab_test1("(table.init 1 (i32.const 12) (i32.const 5) (i32.const 0))", - "out of bounds"); + undefined); // init: seg ix is valid passive, zero len, and dst offset out of bounds at the // end of the table - this is allowed @@ -236,9 +236,9 @@ tab_test1("(table.init 1 (i32.const 30) (i32.const 2) (i32.const 0))", undefined); // init: seg ix is valid passive, zero len, and dst offset out of bounds past the -// end of the table - this is not allowed +// end of the table - this is allowed tab_test1("(table.init 1 (i32.const 31) (i32.const 2) (i32.const 0))", - "out of bounds"); + undefined); // init: seg ix is valid passive, zero len, and dst and src offsets out of bounds // at the end of the table - this is allowed From 07c57f16ff67b29e30719e1a692aad486f582021 Mon Sep 17 00:00:00 2001 From: Ben Smith Date: Sat, 6 Jul 2019 15:21:00 -0700 Subject: [PATCH 112/199] [interp] Remove overlap check from *.copy instr (#103) --- interpreter/runtime/memory.ml | 3 +- interpreter/runtime/table.ml | 3 +- proposals/bulk-memory-operations/Overview.md | 14 +++---- test/core/bulk.wast | 12 ------ test/core/memory_copy.wast | 41 -------------------- test/core/table_copy.wast | 34 ++++++++-------- test/meta/generate_memory_copy.js | 9 +++-- test/meta/generate_table_copy.js | 9 +++-- 8 files changed, 35 insertions(+), 90 deletions(-) diff --git a/interpreter/runtime/memory.ml b/interpreter/runtime/memory.ml index 6a0544764b..27a8e6a52d 100644 --- a/interpreter/runtime/memory.ml +++ b/interpreter/runtime/memory.ml @@ -158,13 +158,12 @@ let init mem bs d s n = let copy mem d s n = let n' = I64_convert.extend_i32_u n in - let overlap = I64.lt_u Int64.(abs (sub d s)) n' in let rec loop d s n dx = if I32.gt_u n 0l then begin store_byte mem d (load_byte mem s); loop (Int64.add d dx) (Int64.add s dx) (Int32.sub n 1l) dx end - in (if overlap && s < d then + in (if s < d then loop Int64.(add d (sub n' 1L)) Int64.(add s (sub n' 1L)) n (-1L) else loop d s n 1L) diff --git a/interpreter/runtime/table.ml b/interpreter/runtime/table.ml index 109d7447ef..8e5b0b72f6 100644 --- a/interpreter/runtime/table.ml +++ b/interpreter/runtime/table.ml @@ -61,13 +61,12 @@ let init tab es d s n = in loop es d s n let copy tab d s n = - let overlap = I32.lt_u Int32.(abs (sub d s)) n in let rec loop d s n dx = if I32.gt_u n 0l then begin store tab d (load tab s); loop (Int32.add d dx) (Int32.add s dx) (Int32.sub n 1l) dx end - in (if overlap && s < d then + in (if s < d then loop Int32.(add d (sub n 1l)) Int32.(add s (sub n 1l)) n (-1l) else loop d s n 1l) diff --git a/proposals/bulk-memory-operations/Overview.md b/proposals/bulk-memory-operations/Overview.md index c5d92eeb38..6500b8a807 100644 --- a/proposals/bulk-memory-operations/Overview.md +++ b/proposals/bulk-memory-operations/Overview.md @@ -319,14 +319,12 @@ written (by the copy operation) in the other region. This instruction has two immediate arguments: the source and destination memory indices. They currently both must be zero. -If the regions overlap, and the source region starts at a lower -address than the target region, then the copy takes place as if from -higher to lower addresses: the highest source address is read first -and the value is written to the highest target address, then the next -highest, and so on. Otherwise, the copy takes place as if from lower -to higher addresses: the lowest source address is read first and the -value is written to the lowest target address, then the next lowest, -and so on. +If the source region starts at a lower address than the target region, then the +copy takes place as if from higher to lower addresses: the highest source +address is read first and the value is written to the highest target address, +then the next highest, and so on. Otherwise, the copy takes place as if from +lower to higher addresses: the lowest source address is read first and the +value is written to the lowest target address, then the next lowest, and so on. (The direction of the copy is defined in order to future-proof `memory.copy` for shared memory and a memory read/write protection diff --git a/test/core/bulk.wast b/test/core/bulk.wast index e01908d244..f7c44e5432 100644 --- a/test/core/bulk.wast +++ b/test/core/bulk.wast @@ -99,12 +99,6 @@ (invoke "copy" (i32.const 0xff00) (i32.const 0) (i32.const 0x100)) (invoke "copy" (i32.const 0xfe00) (i32.const 0xff00) (i32.const 0x100)) -;; Out-of-bounds writes trap, but all previous writes succeed. -(assert_trap (invoke "copy" (i32.const 0xfffe) (i32.const 0) (i32.const 3)) - "out of bounds memory access") -(assert_return (invoke "load8_u" (i32.const 0xfffe)) (i32.const 0xaa)) -(assert_return (invoke "load8_u" (i32.const 0xffff)) (i32.const 0xbb)) - ;; Succeed when copying 0 bytes at the end of the region. (invoke "copy" (i32.const 0x10000) (i32.const 0) (i32.const 0)) (invoke "copy" (i32.const 0) (i32.const 0x10000) (i32.const 0)) @@ -284,12 +278,6 @@ (invoke "copy" (i32.const 6) (i32.const 8) (i32.const 2)) (invoke "copy" (i32.const 8) (i32.const 6) (i32.const 2)) -;; Out-of-bounds writes trap, but all previous writes succeed. -(assert_trap (invoke "call" (i32.const 9)) "uninitialized element") -(assert_trap (invoke "copy" (i32.const 9) (i32.const 0) (i32.const 2)) - "out of bounds table access") -(assert_return (invoke "call" (i32.const 9)) (i32.const 1)) - ;; Succeed when copying 0 elements at the end of the region. (invoke "copy" (i32.const 10) (i32.const 0) (i32.const 0)) (invoke "copy" (i32.const 0) (i32.const 10) (i32.const 0)) diff --git a/test/core/memory_copy.wast b/test/core/memory_copy.wast index 6c2cab5ef7..55bbaf9c0b 100644 --- a/test/core/memory_copy.wast +++ b/test/core/memory_copy.wast @@ -698,26 +698,6 @@ (assert_return (invoke "load8_u" (i32.const 65092)) (i32.const 0)) (assert_return (invoke "load8_u" (i32.const 65291)) (i32.const 0)) (assert_return (invoke "load8_u" (i32.const 65490)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 65516)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 65517)) (i32.const 1)) -(assert_return (invoke "load8_u" (i32.const 65518)) (i32.const 2)) -(assert_return (invoke "load8_u" (i32.const 65519)) (i32.const 3)) -(assert_return (invoke "load8_u" (i32.const 65520)) (i32.const 4)) -(assert_return (invoke "load8_u" (i32.const 65521)) (i32.const 5)) -(assert_return (invoke "load8_u" (i32.const 65522)) (i32.const 6)) -(assert_return (invoke "load8_u" (i32.const 65523)) (i32.const 7)) -(assert_return (invoke "load8_u" (i32.const 65524)) (i32.const 8)) -(assert_return (invoke "load8_u" (i32.const 65525)) (i32.const 9)) -(assert_return (invoke "load8_u" (i32.const 65526)) (i32.const 10)) -(assert_return (invoke "load8_u" (i32.const 65527)) (i32.const 11)) -(assert_return (invoke "load8_u" (i32.const 65528)) (i32.const 12)) -(assert_return (invoke "load8_u" (i32.const 65529)) (i32.const 13)) -(assert_return (invoke "load8_u" (i32.const 65530)) (i32.const 14)) -(assert_return (invoke "load8_u" (i32.const 65531)) (i32.const 15)) -(assert_return (invoke "load8_u" (i32.const 65532)) (i32.const 16)) -(assert_return (invoke "load8_u" (i32.const 65533)) (i32.const 17)) -(assert_return (invoke "load8_u" (i32.const 65534)) (i32.const 18)) -(assert_return (invoke "load8_u" (i32.const 65535)) (i32.const 19)) (module (memory (export "mem") 1 1 ) @@ -1080,27 +1060,6 @@ (assert_return (invoke "load8_u" (i32.const 65093)) (i32.const 0)) (assert_return (invoke "load8_u" (i32.const 65292)) (i32.const 0)) (assert_return (invoke "load8_u" (i32.const 65491)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 65515)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 65516)) (i32.const 1)) -(assert_return (invoke "load8_u" (i32.const 65517)) (i32.const 2)) -(assert_return (invoke "load8_u" (i32.const 65518)) (i32.const 3)) -(assert_return (invoke "load8_u" (i32.const 65519)) (i32.const 4)) -(assert_return (invoke "load8_u" (i32.const 65520)) (i32.const 5)) -(assert_return (invoke "load8_u" (i32.const 65521)) (i32.const 6)) -(assert_return (invoke "load8_u" (i32.const 65522)) (i32.const 7)) -(assert_return (invoke "load8_u" (i32.const 65523)) (i32.const 8)) -(assert_return (invoke "load8_u" (i32.const 65524)) (i32.const 9)) -(assert_return (invoke "load8_u" (i32.const 65525)) (i32.const 10)) -(assert_return (invoke "load8_u" (i32.const 65526)) (i32.const 11)) -(assert_return (invoke "load8_u" (i32.const 65527)) (i32.const 12)) -(assert_return (invoke "load8_u" (i32.const 65528)) (i32.const 13)) -(assert_return (invoke "load8_u" (i32.const 65529)) (i32.const 14)) -(assert_return (invoke "load8_u" (i32.const 65530)) (i32.const 15)) -(assert_return (invoke "load8_u" (i32.const 65531)) (i32.const 16)) -(assert_return (invoke "load8_u" (i32.const 65532)) (i32.const 17)) -(assert_return (invoke "load8_u" (i32.const 65533)) (i32.const 18)) -(assert_return (invoke "load8_u" (i32.const 65534)) (i32.const 19)) -(assert_return (invoke "load8_u" (i32.const 65535)) (i32.const 20)) (module (memory (export "mem") 1 1 ) diff --git a/test/core/table_copy.wast b/test/core/table_copy.wast index 0c03f5bd47..2d0fb78039 100644 --- a/test/core/table_copy.wast +++ b/test/core/table_copy.wast @@ -759,14 +759,14 @@ (assert_trap (invoke "test" (i32.const 21)) "uninitialized element") (assert_trap (invoke "test" (i32.const 22)) "uninitialized element") (assert_trap (invoke "test" (i32.const 23)) "uninitialized element") -(assert_return (invoke "test" (i32.const 24)) (i32.const 0)) -(assert_return (invoke "test" (i32.const 25)) (i32.const 1)) -(assert_return (invoke "test" (i32.const 26)) (i32.const 2)) -(assert_return (invoke "test" (i32.const 27)) (i32.const 3)) -(assert_return (invoke "test" (i32.const 28)) (i32.const 4)) -(assert_return (invoke "test" (i32.const 29)) (i32.const 5)) -(assert_return (invoke "test" (i32.const 30)) (i32.const 6)) -(assert_return (invoke "test" (i32.const 31)) (i32.const 7)) +(assert_trap (invoke "test" (i32.const 24)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 25)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 26)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 27)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 28)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 29)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 30)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 31)) "uninitialized element") (module (type (func (result i32))) @@ -819,15 +819,15 @@ (assert_trap (invoke "test" (i32.const 20)) "uninitialized element") (assert_trap (invoke "test" (i32.const 21)) "uninitialized element") (assert_trap (invoke "test" (i32.const 22)) "uninitialized element") -(assert_return (invoke "test" (i32.const 23)) (i32.const 0)) -(assert_return (invoke "test" (i32.const 24)) (i32.const 1)) -(assert_return (invoke "test" (i32.const 25)) (i32.const 2)) -(assert_return (invoke "test" (i32.const 26)) (i32.const 3)) -(assert_return (invoke "test" (i32.const 27)) (i32.const 4)) -(assert_return (invoke "test" (i32.const 28)) (i32.const 5)) -(assert_return (invoke "test" (i32.const 29)) (i32.const 6)) -(assert_return (invoke "test" (i32.const 30)) (i32.const 7)) -(assert_return (invoke "test" (i32.const 31)) (i32.const 8)) +(assert_trap (invoke "test" (i32.const 23)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 24)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 25)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 26)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 27)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 28)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 29)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 30)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 31)) "uninitialized element") (module (type (func (result i32))) diff --git a/test/meta/generate_memory_copy.js b/test/meta/generate_memory_copy.js index 243fe65252..775b6dddb7 100644 --- a/test/meta/generate_memory_copy.js +++ b/test/meta/generate_memory_copy.js @@ -84,7 +84,8 @@ function initializers(count, startingAt) { return s; } -function mem_copy(min, max, shared, srcOffs, targetOffs, len, copyDown=false) { +function mem_copy(min, max, shared, srcOffs, targetOffs, len) { + let copyDown = srcOffs < targetOffs; let memLength = min * PAGESIZE; let targetAvail = memLength - targetOffs; let srcAvail = memLength - srcOffs; @@ -165,13 +166,13 @@ if (WITH_SHARED_MEMORY) { } // OOB target address, overlapping, src < target -mem_copy(1, 1, "", PAGESIZE-50, PAGESIZE-20, 40, true); +mem_copy(1, 1, "", PAGESIZE-50, PAGESIZE-20, 40); // OOB source address, overlapping, target < src mem_copy(1, 1, "", PAGESIZE-20, PAGESIZE-50, 40); // OOB both, overlapping, including target == src -mem_copy(1, 1, "", PAGESIZE-30, PAGESIZE-20, 40, true); +mem_copy(1, 1, "", PAGESIZE-30, PAGESIZE-20, 40); mem_copy(1, 1, "", PAGESIZE-20, PAGESIZE-30, 40); mem_copy(1, 1, "", PAGESIZE-20, PAGESIZE-20, 40); @@ -179,7 +180,7 @@ mem_copy(1, 1, "", PAGESIZE-20, PAGESIZE-20, 40); mem_copy(1, "", "", PAGESIZE-20, 0, 0xFFFFF000); // Arithmetic overflow on target adddress is an overlapping case. -mem_copy(1, 1, "", PAGESIZE-0x1000, PAGESIZE-20, 0xFFFFFF00, true); +mem_copy(1, 1, "", PAGESIZE-0x1000, PAGESIZE-20, 0xFFFFFF00); // Sundry compilation failures. diff --git a/test/meta/generate_table_copy.js b/test/meta/generate_table_copy.js index 852999afdf..a14c59f825 100644 --- a/test/meta/generate_table_copy.js +++ b/test/meta/generate_table_copy.js @@ -227,7 +227,8 @@ tab_test2("(table.copy (i32.const 30) (i32.const 30) (i32.const 0))", const tbl_copy_len = 16; -function tbl_copy(min, max, srcOffs, targetOffs, len, copyDown=false) { +function tbl_copy(min, max, srcOffs, targetOffs, len) { + let copyDown = srcOffs < targetOffs; let tblLength = min; let targetAvail = tblLength - targetOffs; @@ -319,13 +320,13 @@ tbl_copy(tbl_copy_len*2, tbl_copy_len*4, Math.floor(1.5*tbl_copy_len), 0, tbl_co tbl_copy(tbl_copy_len*2, tbl_copy_len*4, Math.floor(1.5*tbl_copy_len)-1, 0, tbl_copy_len-1); // OOB target address, overlapping, src < target -tbl_copy(tbl_copy_len*2, tbl_copy_len*4, tbl_copy_len-5, Math.floor(1.5*tbl_copy_len), tbl_copy_len, true); +tbl_copy(tbl_copy_len*2, tbl_copy_len*4, tbl_copy_len-5, Math.floor(1.5*tbl_copy_len), tbl_copy_len); // OOB source address, overlapping, target < src tbl_copy(tbl_copy_len*2, tbl_copy_len*4, Math.floor(1.5*tbl_copy_len), tbl_copy_len-5, tbl_copy_len); // OOB both, overlapping, including src == target -tbl_copy(tbl_copy_len*2, tbl_copy_len*4, tbl_copy_len+5, Math.floor(1.5*tbl_copy_len), tbl_copy_len, true); +tbl_copy(tbl_copy_len*2, tbl_copy_len*4, tbl_copy_len+5, Math.floor(1.5*tbl_copy_len), tbl_copy_len); tbl_copy(tbl_copy_len*2, tbl_copy_len*4, Math.floor(1.5*tbl_copy_len), tbl_copy_len+5, tbl_copy_len); tbl_copy(tbl_copy_len*2, tbl_copy_len*4, tbl_copy_len+5, tbl_copy_len+5, tbl_copy_len); @@ -333,4 +334,4 @@ tbl_copy(tbl_copy_len*2, tbl_copy_len*4, tbl_copy_len+5, tbl_copy_len+5, tbl_cop tbl_copy(tbl_copy_len*8, tbl_copy_len*8, tbl_copy_len*7, 0, 0xFFFFFFE0); // Arithmetic overflow on target adddress is an overlapping case. -tbl_copy(tbl_copy_len*8, tbl_copy_len*8, 0, tbl_copy_len*7, 0xFFFFFFE0, true); +tbl_copy(tbl_copy_len*8, tbl_copy_len*8, 0, tbl_copy_len*7, 0xFFFFFFE0); From 600c52410d4e6465edc5ba646b7ff39c919018c9 Mon Sep 17 00:00:00 2001 From: gahaas Date: Thu, 11 Jul 2019 19:15:07 +0200 Subject: [PATCH 113/199] [spec] Add `table.copy` exec text (#105) * [spec] Add exec text * Update document/core/exec/instructions.rst Co-Authored-By: Andreas Rossberg * Update document/core/exec/instructions.rst Co-Authored-By: Andreas Rossberg * Update document/core/exec/instructions.rst Co-Authored-By: Andreas Rossberg * Apply suggestions from code review Co-Authored-By: Andreas Rossberg --- document/core/exec/instructions.rst | 90 +++++++++++++++++++++++++++++ 1 file changed, 90 insertions(+) diff --git a/document/core/exec/instructions.rst b/document/core/exec/instructions.rst index 5706ab5466..b387682199 100644 --- a/document/core/exec/instructions.rst +++ b/document/core/exec/instructions.rst @@ -810,6 +810,96 @@ Memory Instructions Table Instructions ~~~~~~~~~~~~~~~~~~ +.. _exec-table.copy: + +:math:`\TABLECOPY` +................... + +1. Let :math:`F` be the :ref:`current ` :ref:`frame `. + +2. Assert: due to :ref:`validation `, :math:`F.\AMODULE.\MITABLES[0]` exists. + +3. Let :math:`\X{ta}` be the :ref:`table address ` :math:`F.\AMODULE.\MITABLES[0]`. + +4. Assert: due to :ref:`validation `, a value of :ref:`value type ` |I32| is on the top of the stack. + +5. Pop the value :math:`\I32.\CONST~cnt` from the stack. + +6. Assert: due to :ref:`validation `, a value of :ref:`value type ` |I32| is on the top of the stack. + +7. Pop the value :math:`\I32.\CONST~src` from the stack. + +8. Assert: due to :ref:`validation `, a value of :ref:`value type ` |I32| is on the top of the stack. + +9. Pop the value :math:`\I32.\CONST~dst` from the stack. + +10. If :math:`cnt = 0`, then: + + a. Return. + +11. If :math:`dst < src`, then: + + a. Push the value :math:`\I32.\CONST~dst` to the stack. + + b. Push the value :math:`\I32.\CONST~src` to the stack. + + c. Execute the instruction :math:`\TABLEGET`. + + d. Execute the instruction :math:`\TABLESET`. + + e. Push the value :math:`\I32.\CONST~(dst+1)` to the stack. + + f. Push the value :math:`\I32.\CONST~(src+1)` to the stack. + +12. Else: + + a. Push the value :math:`\I32.\CONST~(dst+cnt-1)` to the stack. + + b. Push the value :math:`\I32.\CONST~(src+cnt-1)` to the stack. + + c. Execute the instruction :math:`\TABLEGET`. + + d. Execute the instruction :math:`\TABLESET`. + + e. Push the value :math:`\I32.\CONST~dst` to the stack. + + f. Push the value :math:`\I32.\CONST~src` to the stack. + +13. Push the value :math:`\I32.\CONST~(cnt-1)` to the stack. + +14. Execute the instruction :math:`\TABLECOPY`. + +.. math:: + ~\\[-1ex] + \begin{array}{l} + \begin{array}{lcl@{\qquad}l} + S; F; (\I32.\CONST~dst)~(\I32.\CONST~src)~(\I32.\CONST~0)~\TABLECOPY &\stepto& S'; F; \epsilon + \end{array} + \\[1ex] + \begin{array}{lcl@{\qquad}l} + S; F; (\I32.\CONST~dst)~(\I32.\CONST~src)~(\I32.\CONST~(cnt+1))~\TABLECOPY &\stepto& S; F; + \begin{array}[t]{@{}l@{}} + (\I32.\CONST~dst)~((\I32.\CONST~src)~\TABLEGET)~\TABLESET \\ + (\I32.\CONST~(dst+1))~(\I32.\CONST~(src+1))~(\I32.\CONST~cnt)~\TABLECOPY \\ + \end{array} \\ + \end{array} \\ + \\ \qquad + \begin{array}[t]{@{}r@{~}l@{}} + (\iff & dst < src) + \end{array} + \\[1ex] + \begin{array}{lcl@{\qquad}l} + S; F; (\I32.\CONST~dst)~(\I32.\CONST~src)~(\I32.\CONST~(cnt+1))~\TABLECOPY &\stepto& S; F; + \begin{array}[t]{@{}l@{}} + (\I32.\CONST~(dst+cnt-1))~((\I32.\CONST~(src+cnt-1))~\TABLEGET)~\TABLESET \\ + (\I32.\CONST~dst)~(\I32.\CONST~src)~(\I32.\CONST~cnt)~\TABLECOPY \\ + \end{array} \\ + \end{array} \\ + \\ \qquad + (\otherwise) \\ + \end{array} + + .. _exec-table.init: :math:`\TABLEINIT~x` From fd480808130f275fed75600773e12fcc3f421075 Mon Sep 17 00:00:00 2001 From: gahaas Date: Thu, 11 Jul 2019 19:17:34 +0200 Subject: [PATCH 114/199] Polish table.init exec spec (#104) * Polish table.init exec spec * table.set and table.init don't have the same imm. * Update document/core/exec/instructions.rst Co-Authored-By: Andreas Rossberg --- document/core/exec/instructions.rst | 50 +++++++++++++++++------------ 1 file changed, 29 insertions(+), 21 deletions(-) diff --git a/document/core/exec/instructions.rst b/document/core/exec/instructions.rst index b387682199..db1cc88e1b 100644 --- a/document/core/exec/instructions.rst +++ b/document/core/exec/instructions.rst @@ -913,7 +913,7 @@ Table Instructions 4. Assert: due to :ref:`validation `, :math:`S.\STABLES[\X{ta}]` exists. -5. Let :math:`\X{table}` be the :ref:`table instance ` :math:`S.\STABLES[\X{ta}]`. +5. Let :math:`\X{tab}` be the :ref:`table instance ` :math:`S.\STABLES[\X{ta}]`. 6. Assert: due to :ref:`validation `, :math:`F.\AMODULE.\MIELEMS[x]` exists. @@ -925,58 +925,66 @@ Table Instructions 10. If :math:`\X{elem}^? = \epsilon`, then: - a. Trap. + a. Trap. 11. Assert: due to :ref:`validation `, a value of :ref:`value type ` |I32| is on the top of the stack. -12. Pop the value :math:`\I32.\CONST~n` from the stack. +12. Pop the value :math:`\I32.\CONST~cnt` from the stack. 13. Assert: due to :ref:`validation `, a value of :ref:`value type ` |I32| is on the top of the stack. -14. Pop the value :math:`\I32.\CONST~s` from the stack. +14. Pop the value :math:`\I32.\CONST~src` from the stack. 15. Assert: due to :ref:`validation `, a value of :ref:`value type ` |I32| is on the top of the stack. -16. Pop the value :math:`\I32.\CONST~d` from the stack. +16. Pop the value :math:`\I32.\CONST~dst` from the stack. -17. Else: +17. If :math:`cnt = 0`, then: - a. Push the value :math:`\I32.\CONST~d` to the stack. + a. Return. - b. Let :math:`\funcelem` be the :ref:`function element ` :math:`\X{elem}.\EIINIT[s]`. +18. If `src` is larger than the length of :math:`\X{elem}.\EIINIT`, then: - d. Execute the instruction :math:`\TABLESET~\funcelem`. + a. Trap. - e. Push the value :math:`\I32.\CONST~(d+1)` to the stack. +19. Let :math:`\funcelem` be the :ref:`function element ` :math:`\X{elem}.\EIINIT[src]`. - f. Push the value :math:`\I32.\CONST~(s+1)` to the stack. +20. Push the value :math:`\I32.\CONST~dst` to the stack. - g. Push the value :math:`\I32.\CONST~(n-1)` to the stack. +21. Push the value :math:`\funcelem` to the stack. + +22. Execute the instruction :math:`\TABLESET`. + +23. Push the value :math:`\I32.\CONST~(dst+1)` to the stack. - h. Execute the instruction :math:`\TABLEINIT~x`. +24. Push the value :math:`\I32.\CONST~(src+1)` to the stack. + +25. Push the value :math:`\I32.\CONST~(cnt-1)` to the stack. + +26. Execute the instruction :math:`\TABLEINIT~x`. .. math:: ~\\[-1ex] \begin{array}{l} \begin{array}{lcl@{\qquad}l} - S; F; (\I32.\CONST~d)~(\I32.\CONST~(s)~(\I32.\CONST~0)~(\TABLEINIT~x) &\stepto& S; F; \epsilon + S; F; (\I32.\CONST~dst)~(\I32.\CONST~src)~(\I32.\CONST~0)~(\TABLEINIT~x) &\stepto& S'; F; \epsilon \end{array} \\[1ex] \begin{array}{lcl@{\qquad}l} - S; F; (\I32.\CONST~d)~(\I32.\CONST~s)~(\I32.\CONST~(n+1))~(\TABLEINIT~x) &\stepto& S; F; + S; F; (\I32.\CONST~dst)~(\I32.\CONST~src)~(\I32.\CONST~(cnt+1))~(\TABLEINIT~x) &\stepto& S'; F; \begin{array}[t]{@{}l@{}} - (\I32.\CONST~d)~\funcelem~\TABLESET \\ - (\I32.\CONST~(d+1))~(\I32.\CONST~(s+1))~(\I32.\CONST~n)~(\TABLEINIT~x) \\ + (\I32.\CONST~dst)~\funcelem~(\TABLESET~x) \\ + (\I32.\CONST~(dst+1))~(\I32.\CONST~(src+1))~(\I32.\CONST~cnt)~(\TABLEINIT~x) \\ \end{array} \\ \end{array} \\ \\ \qquad \begin{array}[t]{@{}r@{~}l@{}} - (\iff & s < |S.\SELEM[F.\AMODULE.\MIELEMS[x]].\EIINIT| \\ - \wedge & \funcelem = S.\SELEM[F.\AMODULE.\MIELEMS[x]].\EIINIT[s]) \\ + (\iff & src < |S.\SELEM[F.\AMODULE.\MIELEMS[x]].\EIINIT| \\ + \wedge & \funcelem = S.\SELEM[F.\AMODULE.\MIELEMS[x]].\EIINIT[src]) \\ \end{array} \\[1ex] \begin{array}{lcl@{\qquad}l} - S; F; (\I32.\CONST~d)~(\I32.\CONST~s)~(\I32.\CONST~n)~(\TABLEINIT~x) &\stepto& S; F; \TRAP + S; F; (\I32.\CONST~dst)~(\I32.\CONST~src)~(\I32.\CONST~(cnt+1))~(\TABLEINIT~x) &\stepto& S; F; \TRAP \end{array} \\ \qquad (\otherwise) \\ @@ -1093,7 +1101,7 @@ Table Instructions 10. If :math:`i` is not smaller than the length of :math:`\X{tab}.\TIELEM`, then: - a. Trap. + a. Trap. 11. Replace :math:`X{tab}.\TIELEM[i]` with :math:`\funcelem`. From 820bd120f88bbf97c1bd7a0dd7c2df8f5972dade Mon Sep 17 00:00:00 2001 From: Ben Smith Date: Tue, 23 Jul 2019 14:23:13 -0700 Subject: [PATCH 115/199] [spec] Add `memory.copy` exec text (#106) Also clean up some `table.copy` text. * WIP on fixes; checkpoint to avoid working over ssh * Address comments and other fixes * Add missing `if n=0` case to `memory.fill` and `memory.init` * Move `n=0` case to the top in `memory.fill` * Use `\vconst` to ensure constants are well-formed * Use 3 spaces instead of 4 in `memory.copy` and `table.copy` to prevent double-spaced numeric list * Add `_t` subscript to '`\vconst` * Add cnt=1 case * Make prose match formal --- document/core/exec/instructions.rst | 354 +++++++++++++++++++++------- document/core/exec/runtime.rst | 15 +- document/core/util/macros.def | 1 + 3 files changed, 279 insertions(+), 91 deletions(-) diff --git a/document/core/exec/instructions.rst b/document/core/exec/instructions.rst index db1cc88e1b..d9371dad49 100644 --- a/document/core/exec/instructions.rst +++ b/document/core/exec/instructions.rst @@ -645,7 +645,11 @@ Memory Instructions 11. Pop the value :math:`\I32.\CONST~i` from the stack. -12. Else: +12. If :math:`n = 0`, then: + + a. Return. + +13. If :math:`n = 1`, then: a. Push the value :math:`\I32.\CONST~i` to the stack. @@ -653,26 +657,42 @@ Memory Instructions c. Execute the instruction :math:`\I32\K{.}\STORE\K{8}~\{ \OFFSET~0, \ALIGN~0 \}`. - d. Push the value :math:`\I32.\CONST~(i+1)` to the stack. + d. Return. + +14. Push the value :math:`\I32.\CONST~i` to the stack. + +15. Push the value :math:`\val` to the stack. - e. Push the value :math:`\val` to the stack. +16. Push the value :math:`\I32.\CONST~1` to the stack. - f. Push the value :math:`\I32.\CONST~(n-1)` to the stack. +17. Execute the instruction :math:`\MEMORYFILL`. - g. Execute the instruction :math:`\MEMORYFILL`. +18. Push the value :math:`\vconst_\I32(i+1)` to the stack. + +19. Push the value :math:`\val` to the stack. + +20. Push the value :math:`\I32.\CONST~(n-1)` to the stack. + +21. Execute the instruction :math:`\MEMORYFILL`. .. math:: \begin{array}{l} \begin{array}{lcl@{\qquad}l} - S; F; (\I32.\CONST~i)~\val~(\I32.\CONST~(n+1))~(\MEMORYFILL) &\stepto& S; F; - \begin{array}[t]{@{}l@{}} - (\I32.\CONST~i)~\val~(\I32\K{.}\STORE\K{8}~\{ \OFFSET~0, \ALIGN~0 \}) \\ - (\I32.\CONST~(i+1))~\val~(\I32.\CONST~n)~(\MEMORYFILL) \\ - \end{array} \\ + S; F; (\I32.\CONST~i)~\val~(\I32.\CONST~0)~(\MEMORYFILL) &\stepto& S; F; \epsilon \end{array} \\ \begin{array}{lcl@{\qquad}l} - S; F; (\I32.\CONST~i)~\val~(\I32.\CONST~0)~(\MEMORYFILL) &\stepto& S; F; \epsilon + S; F; (\I32.\CONST~i)~\val~(\I32.\CONST~1)~(\MEMORYFILL) &\stepto& S; F; + (\I32.\CONST~i)~\val~(\I32\K{.}\STORE\K{8}~\{ \OFFSET~0, \ALIGN~0 \}) \\ \end{array} \\ + \begin{array}{lcl@{\qquad}l} + S; F; (\I32.\CONST~i)~\val~(\I32.\CONST~n)~(\MEMORYFILL) &\stepto& S; F; + \begin{array}[t]{@{}l@{}} + (\I32.\CONST~i)~\val~(\I32.\CONST~1)~(\MEMORYFILL) \\ + (\vconst_\I32(i+1))~\val~(\I32.\CONST~(n-1))~(\MEMORYFILL) \\ + \end{array} \\ + \end{array} + \\ \qquad + (\iff n > 1) \\ \end{array} @@ -705,56 +725,81 @@ Memory Instructions 11. Assert: due to :ref:`validation `, a value of :ref:`value type ` |I32| is on the top of the stack. -12. Pop the value :math:`\I32.\CONST~n` from the stack. +12. Pop the value :math:`\I32.\CONST~cnt` from the stack. 13. Assert: due to :ref:`validation `, a value of :ref:`value type ` |I32| is on the top of the stack. -14. Pop the value :math:`\I32.\CONST~s` from the stack. +14. Pop the value :math:`\I32.\CONST~src` from the stack. 15. Assert: due to :ref:`validation `, a value of :ref:`value type ` |I32| is on the top of the stack. -16. Pop the value :math:`\I32.\CONST~d` from the stack. +16. Pop the value :math:`\I32.\CONST~dst` from the stack. -17. Else: +17. If :math:`cnt = 0`, then: - a. Push the value :math:`\I32.\CONST~d` to the stack. + a. Return. + +18. If :math:`cnt = 1`, then: + + a. Push the value :math:`\I32.\CONST~dst` to the stack. - b. Let :math:`b` be the byte :math:`\X{data}.\DIINIT[s]`. + b. If `src` is larger than the length of :math:`\X{data}.\DIINIT`, then: - c. Push the value :math:`\I32.\CONST~b` to the stack. + i. Trap. - d. Execute the instruction :math:`\I32\K{.}\STORE\K{8}~\{ \OFFSET~0, \ALIGN~0 \}`. + c. Let :math:`b` be the byte :math:`\X{data}.\DIINIT[src]`. - e. Push the value :math:`\I32.\CONST~(d+1)` to the stack. + d. Push the value :math:`\I32.\CONST~b` to the stack. - f. Push the value :math:`\I32.\CONST~(s+1)` to the stack. + e. Execute the instruction :math:`\I32\K{.}\STORE\K{8}~\{ \OFFSET~0, \ALIGN~0 \}`. - g. Push the value :math:`\I32.\CONST~(n-1)` to the stack. + f. Return. + +19. Push the value :math:`\I32.\CONST~dst` to the stack. + +20. Push the value :math:`\I32.\CONST~src` to the stack. + +21. Push the value :math:`\I32.\CONST~1` to the stack. + +22. Execute the instruction :math:`\MEMORYINIT~x`. + +23. Push the value :math:`\vconst_\I32(dst+1)` to the stack. + +24. Push the value :math:`\vconst_\I32(src+1)` to the stack. + +25. Push the value :math:`\I32.\CONST~(cnt-1)` to the stack. - h. Execute the instruction :math:`\MEMORYINIT~x`. +26. Execute the instruction :math:`\MEMORYINIT~x`. .. math:: ~\\[-1ex] \begin{array}{l} \begin{array}{lcl@{\qquad}l} - S; F; (\I32.\CONST~d)~(\I32.\CONST~s)~(\I32.\CONST~0)~(\MEMORYINIT~x) &\stepto& S; F; \epsilon + S; F; (\I32.\CONST~dst)~(\I32.\CONST~src)~(\I32.\CONST~0)~(\MEMORYINIT~x) &\stepto& S; F; \epsilon \end{array} \\[1ex] \begin{array}{lcl@{\qquad}l} - S; F; (\I32.\CONST~d)~(\I32.\CONST~s)~(\I32.\CONST~(n+1))~(\MEMORYINIT~x) &\stepto& S; F; - \begin{array}[t]{@{}l@{}} - (\I32.\CONST~d)~(\I32.\CONST~b)~(\I32\K{.}\STORE\K{8}~\{ \OFFSET~0, \ALIGN~0 \}) \\ - (\I32.\CONST~(d+1))~(\I32.\CONST~(s+1))~(\I32.\CONST~n)~(\MEMORYINIT~x) \\ - \end{array} \\ - \end{array} \\ + S; F; (\I32.\CONST~dst)~(\I32.\CONST~src)~(\I32.\CONST~1)~(\MEMORYINIT~x) &\stepto& S; F; + (\I32.\CONST~dst)~(\I32.\CONST~b)~(\I32\K{.}\STORE\K{8}~\{ \OFFSET~0, \ALIGN~0 \}) \\ + \end{array} \\ \qquad \begin{array}[t]{@{}r@{~}l@{}} - (\iff & s < |S.\SDATA[F.\AMODULE.\MIDATAS[x]].\DIINIT| \\ - \wedge & b = S.\SDATA[F.\AMODULE.\MIDATAS[x]].\DIINIT[s]) \\ + (\iff & src < |S.\SDATA[F.\AMODULE.\MIDATAS[x]].\DIINIT| \\ + \wedge & b = S.\SDATA[F.\AMODULE.\MIDATAS[x]].\DIINIT[src]) \\ \end{array} \\[1ex] \begin{array}{lcl@{\qquad}l} - S; F; (\I32.\CONST~d)~(\I32.\CONST~s)~(\I32.\CONST~n)~(\MEMORYINIT~x) &\stepto& S; F; \TRAP + S; F; (\I32.\CONST~dst)~(\I32.\CONST~src)~(\I32.\CONST~cnt))~(\MEMORYINIT~x) &\stepto& S; F; + \begin{array}[t]{@{}l@{}} + (\I32.\CONST~dst)~(\I32.\CONST~src)~(\I32.\CONST~1)~(\MEMORYINIT~x) \\ + (\vconst_\I32(dst+1))~(\vconst_\I32(src+1))~(\I32.\CONST~(cnt-1))~(\MEMORYINIT~x) \\ + \end{array} \\ + \end{array} + \\ \qquad + (\iff cnt > 1) + \\[1ex] + \begin{array}{lcl@{\qquad}l} + S; F; (\I32.\CONST~dst)~(\I32.\CONST~src)~(\I32.\CONST~cnt)~(\MEMORYINIT~x) &\stepto& S; F; \TRAP \end{array} \\ \qquad (\otherwise) \\ @@ -802,6 +847,109 @@ Memory Instructions \end{array} +.. _exec-memory.copy: + +:math:`\MEMORYCOPY` +................... + +1. Assert: due to :ref:`validation `, a value of :ref:`value type ` |I32| is on the top of the stack. + +2. Pop the value :math:`\I32.\CONST~cnt` from the stack. + +3. Assert: due to :ref:`validation `, a value of :ref:`value type ` |I32| is on the top of the stack. + +4. Pop the value :math:`\I32.\CONST~src` from the stack. + +5. Assert: due to :ref:`validation `, a value of :ref:`value type ` |I32| is on the top of the stack. + +6. Pop the value :math:`\I32.\CONST~dst` from the stack. + +7. If :math:`cnt = 0`, then: + + a. Return. + +8. If :math:`cnt = 1`, then: + + a. Push the value :math:`\I32.\CONST~dst` to the stack. + + b. Push the value :math:`\I32.\CONST~src` to the stack. + + c. Execute the instruction :math:`\I32\K{.}\LOAD\K{8\_u}~\{ \OFFSET~0, \ALIGN~0 \}`. + + d. Execute the instruction :math:`\I32\K{.}\STORE\K{8}~\{ \OFFSET~0, \ALIGN~0 \}`. + + e. Return. + +9. If :math:`dst <= src`, then: + + a. Push the value :math:`\I32.\CONST~dst` to the stack. + + b. Push the value :math:`\I32.\CONST~src` to the stack. + + c. Push the value :math:`\I32.\CONST~1` to the stack. + + d. Execute the instruction :math:`\MEMORYCOPY`. + + e. Push the value :math:`\vconst_\I32(dst+1)` to the stack. + + f. Push the value :math:`\vconst_\I32(src+1)` to the stack. + +10. Else: + + a. Push the value :math:`\vconst_\I32(dst+cnt-1)` to the stack. + + b. Push the value :math:`\vconst_\I32(src+cnt-1)` to the stack. + + c. Push the value :math:`\I32.\CONST~1` to the stack. + + d. Execute the instruction :math:`\MEMORYCOPY`. + + e. Push the value :math:`\I32.\CONST~dst` to the stack. + + f. Push the value :math:`\I32.\CONST~src` to the stack. + +11. Push the value :math:`\I32.\CONST~(cnt-1)` to the stack. + +12. Execute the instruction :math:`\MEMORYCOPY`. + +.. math:: + ~\\[-1ex] + \begin{array}{l} + \begin{array}{lcl@{\qquad}l} + S; F; (\I32.\CONST~dst)~(\I32.\CONST~src)~(\I32.\CONST~0)~\MEMORYCOPY &\stepto& S; F; \epsilon + \end{array} + \\[1ex] + \begin{array}{lcl@{\qquad}l} + S; F; (\I32.\CONST~dst)~(\I32.\CONST~src)~(\I32.\CONST~1)~\MEMORYCOPY &\stepto& S; F; + \begin{array}[t]{@{}l@{}} + (\I32.\CONST~dst) \\ + (\I32.\CONST~src)~(\I32\K{.}\LOAD\K{8\_u}~\{ \OFFSET~0, \ALIGN~0 \}) \\ + (\I32\K{.}\STORE\K{8}~\{ \OFFSET~0, \ALIGN~0 \}) \\ + \end{array} \\ + \end{array} + \\[1ex] + \begin{array}{lcl@{\qquad}l} + S; F; (\I32.\CONST~dst)~(\I32.\CONST~src)~(\I32.\CONST~cnt)~\MEMORYCOPY &\stepto& S; F; + \begin{array}[t]{@{}l@{}} + (\I32.\CONST~dst)~(\I32.\CONST~src)~(\I32.\CONST~1)~\MEMORYCOPY \\ + (\vconst_\I32(dst+1))~(\vconst_\I32(src+1))~(\I32.\CONST~(cnt-1))~\MEMORYCOPY \\ + \end{array} \\ + \end{array} + \\ \qquad + (\iff dst <= src \wedge cnt > 1) + \\[1ex] + \begin{array}{lcl@{\qquad}l} + S; F; (\I32.\CONST~dst)~(\I32.\CONST~src)~(\I32.\CONST~cnt)~\MEMORYCOPY &\stepto& S; F; + \begin{array}[t]{@{}l@{}} + (\I32.\CONST~(dst+cnt-1))~(\I32.\CONST~(src+cnt-1))~(\I32.\CONST~1)~\MEMORYCOPY \\ + (\I32.\CONST~dst)~(\I32.\CONST~src)~(\I32.\CONST~(cnt-1))~\MEMORYCOPY \\ + \end{array} \\ + \end{array} + \\ \qquad + (\iff dst > src \wedge cnt > 1) \\ + \end{array} + + .. index:: table instruction, table index, store, frame, address, table address, table instance, function element, element address, element instance, value type pair: execution; instruction single: abstract syntax; instruction @@ -813,90 +961,99 @@ Table Instructions .. _exec-table.copy: :math:`\TABLECOPY` -................... +.................. -1. Let :math:`F` be the :ref:`current ` :ref:`frame `. +1. Assert: due to :ref:`validation `, a value of :ref:`value type ` |I32| is on the top of the stack. -2. Assert: due to :ref:`validation `, :math:`F.\AMODULE.\MITABLES[0]` exists. +2. Pop the value :math:`\I32.\CONST~cnt` from the stack. -3. Let :math:`\X{ta}` be the :ref:`table address ` :math:`F.\AMODULE.\MITABLES[0]`. +3. Assert: due to :ref:`validation `, a value of :ref:`value type ` |I32| is on the top of the stack. -4. Assert: due to :ref:`validation `, a value of :ref:`value type ` |I32| is on the top of the stack. +4. Pop the value :math:`\I32.\CONST~src` from the stack. -5. Pop the value :math:`\I32.\CONST~cnt` from the stack. +5. Assert: due to :ref:`validation `, a value of :ref:`value type ` |I32| is on the top of the stack. -6. Assert: due to :ref:`validation `, a value of :ref:`value type ` |I32| is on the top of the stack. +6. Pop the value :math:`\I32.\CONST~dst` from the stack. -7. Pop the value :math:`\I32.\CONST~src` from the stack. +7. If :math:`cnt = 0`, then: -8. Assert: due to :ref:`validation `, a value of :ref:`value type ` |I32| is on the top of the stack. + a. Return. -9. Pop the value :math:`\I32.\CONST~dst` from the stack. +8. If :math:`cnt = 1`, then: -10. If :math:`cnt = 0`, then: + a. Push the value :math:`\I32.\CONST~dst` to the stack. - a. Return. + b. Push the value :math:`\I32.\CONST~src` to the stack. -11. If :math:`dst < src`, then: + c. Execute the instruction :math:`\TABLEGET`. - a. Push the value :math:`\I32.\CONST~dst` to the stack. + d. Execute the instruction :math:`\TABLESET`. + + e. Return. + +9. If :math:`dst <= src`, then: - b. Push the value :math:`\I32.\CONST~src` to the stack. + a. Push the value :math:`\I32.\CONST~dst` to the stack. - c. Execute the instruction :math:`\TABLEGET`. + b. Push the value :math:`\I32.\CONST~src` to the stack. - d. Execute the instruction :math:`\TABLESET`. + c. Push the value :math:`\I32.\CONST~1` to the stack. - e. Push the value :math:`\I32.\CONST~(dst+1)` to the stack. + d. Execute the instruction :math:`\TABLECOPY`. - f. Push the value :math:`\I32.\CONST~(src+1)` to the stack. + e. Push the value :math:`\vconst_\I32(dst+1)` to the stack. -12. Else: + f. Push the value :math:`\vconst_\I32(src+1)` to the stack. - a. Push the value :math:`\I32.\CONST~(dst+cnt-1)` to the stack. +10. Else: - b. Push the value :math:`\I32.\CONST~(src+cnt-1)` to the stack. + a. Push the value :math:`\vconst_\I32(dst+cnt-1)` to the stack. - c. Execute the instruction :math:`\TABLEGET`. + b. Push the value :math:`\vconst_\I32(src+cnt-1)` to the stack. - d. Execute the instruction :math:`\TABLESET`. + c. Push the value :math:`\I32.\CONST~1` to the stack. - e. Push the value :math:`\I32.\CONST~dst` to the stack. + d. Execute the instruction :math:`\TABLECOPY`. - f. Push the value :math:`\I32.\CONST~src` to the stack. + e. Push the value :math:`\I32.\CONST~dst` to the stack. -13. Push the value :math:`\I32.\CONST~(cnt-1)` to the stack. + f. Push the value :math:`\I32.\CONST~src` to the stack. -14. Execute the instruction :math:`\TABLECOPY`. +11. Push the value :math:`\I32.\CONST~(cnt-1)` to the stack. + +12. Execute the instruction :math:`\TABLECOPY`. .. math:: ~\\[-1ex] \begin{array}{l} \begin{array}{lcl@{\qquad}l} - S; F; (\I32.\CONST~dst)~(\I32.\CONST~src)~(\I32.\CONST~0)~\TABLECOPY &\stepto& S'; F; \epsilon + S; F; (\I32.\CONST~dst)~(\I32.\CONST~src)~(\I32.\CONST~0)~\TABLECOPY &\stepto& S; F; \epsilon + \end{array} + \\[1ex] + \begin{array}{lcl@{\qquad}l} + S; F; (\I32.\CONST~dst)~(\I32.\CONST~src)~(\I32.\CONST~1)~\TABLECOPY &\stepto& S; F; + (\I32.\CONST~dst)~(\I32.\CONST~src)~\TABLEGET~\TABLESET \\ \end{array} \\[1ex] \begin{array}{lcl@{\qquad}l} - S; F; (\I32.\CONST~dst)~(\I32.\CONST~src)~(\I32.\CONST~(cnt+1))~\TABLECOPY &\stepto& S; F; + S; F; (\I32.\CONST~dst)~(\I32.\CONST~src)~(\I32.\CONST~cnt)~\TABLECOPY &\stepto& S; F; \begin{array}[t]{@{}l@{}} - (\I32.\CONST~dst)~((\I32.\CONST~src)~\TABLEGET)~\TABLESET \\ - (\I32.\CONST~(dst+1))~(\I32.\CONST~(src+1))~(\I32.\CONST~cnt)~\TABLECOPY \\ + (\I32.\CONST~dst)~(\I32.\CONST~src)~(\I32.\CONST~1)~\TABLECOPY \\ + (\vconst_\I32(dst+1))~(\vconst_\I32(src+1))~(\I32.\CONST~(cnt-1))~\TABLECOPY \\ \end{array} \\ - \end{array} \\ + \end{array} \\ \qquad - \begin{array}[t]{@{}r@{~}l@{}} - (\iff & dst < src) - \end{array} + (\iff dst <= src \wedge cnt > 1) \\[1ex] \begin{array}{lcl@{\qquad}l} - S; F; (\I32.\CONST~dst)~(\I32.\CONST~src)~(\I32.\CONST~(cnt+1))~\TABLECOPY &\stepto& S; F; + S; F; (\I32.\CONST~dst)~(\I32.\CONST~src)~(\I32.\CONST~cnt)~\TABLECOPY &\stepto& S; F; \begin{array}[t]{@{}l@{}} - (\I32.\CONST~(dst+cnt-1))~((\I32.\CONST~(src+cnt-1))~\TABLEGET)~\TABLESET \\ - (\I32.\CONST~dst)~(\I32.\CONST~src)~(\I32.\CONST~cnt)~\TABLECOPY \\ + (\I32.\CONST~(dst+cnt-1))~(\I32.\CONST~(src+cnt-1))~(\I32.\CONST~1)~\TABLECOPY \\ + (\I32.\CONST~dst)~(\I32.\CONST~src)~(\I32.\CONST~(cnt-1))~\TABLECOPY \\ \end{array} \\ - \end{array} \\ + \end{array} \\ \qquad - (\otherwise) \\ + (\iff dst > src \wedge cnt > 1) \\ \end{array} @@ -943,21 +1100,33 @@ Table Instructions a. Return. -18. If `src` is larger than the length of :math:`\X{elem}.\EIINIT`, then: +18. If :math:`cnt = 1`, then: - a. Trap. + a. Push the value :math:`\I32.\CONST~dst` to the stack. + + b. If `src` is larger than the length of :math:`\X{elem}.\EIINIT`, then: + + i. Trap. + + c. Let :math:`\funcelem` be the :ref:`function element ` :math:`\X{elem}.\EIINIT[src]`. + + d. Push the value :math:`\funcelem` to the stack. -19. Let :math:`\funcelem` be the :ref:`function element ` :math:`\X{elem}.\EIINIT[src]`. + e. Execute the instruction :math:`\TABLESET`. -20. Push the value :math:`\I32.\CONST~dst` to the stack. + f. Return. -21. Push the value :math:`\funcelem` to the stack. +19. Push the value :math:`\I32.\CONST~dst` to the stack. -22. Execute the instruction :math:`\TABLESET`. +20. Push the value :math:`\I32.\CONST~src` to the stack. -23. Push the value :math:`\I32.\CONST~(dst+1)` to the stack. +21. Push the value :math:`\I32.\CONST~1` to the stack. -24. Push the value :math:`\I32.\CONST~(src+1)` to the stack. +22. Execute the instruction :math:`\TABLEINIT~x`. + +23. Push the value :math:`\vconst_\I32(dst+1)` to the stack. + +24. Push the value :math:`\vconst_\I32(src+1)` to the stack. 25. Push the value :math:`\I32.\CONST~(cnt-1)` to the stack. @@ -967,16 +1136,13 @@ Table Instructions ~\\[-1ex] \begin{array}{l} \begin{array}{lcl@{\qquad}l} - S; F; (\I32.\CONST~dst)~(\I32.\CONST~src)~(\I32.\CONST~0)~(\TABLEINIT~x) &\stepto& S'; F; \epsilon + S; F; (\I32.\CONST~dst)~(\I32.\CONST~src)~(\I32.\CONST~0)~(\TABLEINIT~x) &\stepto& S; F; \epsilon \end{array} \\[1ex] \begin{array}{lcl@{\qquad}l} - S; F; (\I32.\CONST~dst)~(\I32.\CONST~src)~(\I32.\CONST~(cnt+1))~(\TABLEINIT~x) &\stepto& S'; F; - \begin{array}[t]{@{}l@{}} + S; F; (\I32.\CONST~dst)~(\I32.\CONST~src)~(\I32.\CONST~1)~(\TABLEINIT~x) &\stepto& S; F; (\I32.\CONST~dst)~\funcelem~(\TABLESET~x) \\ - (\I32.\CONST~(dst+1))~(\I32.\CONST~(src+1))~(\I32.\CONST~cnt)~(\TABLEINIT~x) \\ - \end{array} \\ - \end{array} \\ + \end{array} \\ \qquad \begin{array}[t]{@{}r@{~}l@{}} (\iff & src < |S.\SELEM[F.\AMODULE.\MIELEMS[x]].\EIINIT| \\ @@ -984,7 +1150,17 @@ Table Instructions \end{array} \\[1ex] \begin{array}{lcl@{\qquad}l} - S; F; (\I32.\CONST~dst)~(\I32.\CONST~src)~(\I32.\CONST~(cnt+1))~(\TABLEINIT~x) &\stepto& S; F; \TRAP + S; F; (\I32.\CONST~dst)~(\I32.\CONST~src)~(\I32.\CONST~cnt)~(\TABLEINIT~x) &\stepto& S; F; + \begin{array}[t]{@{}l@{}} + (\I32.\CONST~dst)~(\I32.\CONST~src)~(\I32.\CONST~1)~(\TABLEINIT~x) \\ + (\vconst_\I32(dst+1))~(\vconst_\I32(src+1))~(\I32.\CONST~(cnt-1))~(\TABLEINIT~x) \\ + \end{array} \\ + \end{array} + \\ \qquad + (\iff cnt > 1) + \\[1ex] + \begin{array}{lcl@{\qquad}l} + S; F; (\I32.\CONST~dst)~(\I32.\CONST~src)~(\I32.\CONST~cnt)~(\TABLEINIT~x) &\stepto& S; F; \TRAP \end{array} \\ \qquad (\otherwise) \\ diff --git a/document/core/exec/runtime.rst b/document/core/exec/runtime.rst index f142122ca1..346123327c 100644 --- a/document/core/exec/runtime.rst +++ b/document/core/exec/runtime.rst @@ -29,6 +29,19 @@ It is convenient to reuse the same notation as for the |CONST| :ref:`instruction \F64.\CONST~\f64 \end{array} +Conventions +........... + +The following auxiliary notation is defined for constant values, to ensure they are well-formed for the given :ref:`value type `. + +.. math:: + \begin{array}{lcl@{\qquad}l} + \vconst_t(x) &=& (t\K{.}\CONST~x) + & (\iff x~\mbox{is well-formed for}~t) \\ + \vconst_t(x) &=& \TRAP + & (\otherwise) \\ + \end{array} + .. index:: ! result, value, trap pair: abstract syntax; result @@ -381,8 +394,6 @@ It filters out entries of a specific kind in an order-preserving fashion: * :math:`\evglobals(\externval^\ast) = [\globaladdr ~|~ (\EVGLOBAL~\globaladdr) \in \externval^\ast]` - - .. index:: ! stack, ! frame, ! label, instruction, store, activation, function, call, local, module instance pair: abstract syntax; frame pair: abstract syntax; label diff --git a/document/core/util/macros.def b/document/core/util/macros.def index be0829cfff..40c500e171 100644 --- a/document/core/util/macros.def +++ b/document/core/util/macros.def @@ -885,6 +885,7 @@ .. |evtables| mathdef:: \xref{exec/runtime}{syntax-externval}{\F{tables}} .. |evmems| mathdef:: \xref{exec/runtime}{syntax-externval}{\F{mems}} .. |evglobals| mathdef:: \xref{exec/runtime}{syntax-externval}{\F{globals}} +.. |vconst| mathdef:: \xref{exec/runtime}{syntax-val}{\F{const}} .. Store, terminals From aadc467ee8baf6e82a6e4fb26503eae39774913d Mon Sep 17 00:00:00 2001 From: gahaas Date: Thu, 1 Aug 2019 21:31:55 +0200 Subject: [PATCH 116/199] Change element segment encoding (#108) * Change element segment encoding * Change table index letter --- document/core/binary/modules.rst | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/document/core/binary/modules.rst b/document/core/binary/modules.rst index 538d1fad12..025bdb2861 100644 --- a/document/core/binary/modules.rst +++ b/document/core/binary/modules.rst @@ -327,12 +327,18 @@ It decodes into a vector of :ref:`element segments ` that represent \production{element section} & \Belemsec &::=& \X{seg}^\ast{:}\Bsection_9(\Bvec(\Belem)) &\Rightarrow& \X{seg} \\ \production{element segment} & \Belem &::=& - \hex{00}~~e{:}\Bexpr~~y^\ast{:}\Bvec(\Bfuncidx) - &\Rightarrow& \{ \ETABLE~0, \EOFFSET~e, \EINIT~((\REFFUNC~y)~\END)^\ast \} \\ &&|& - \hex{01}~~\X{et}:\Belemtype~e^\ast{:}\Bvec(\Belemexpr) + \hex{00}~~o{:}\Bexpr~~y^\ast{:}\Bvec(\Bfuncidx) + &\Rightarrow& \{ \ETABLE~0, \EOFFSET~o, \ETYPE~\FUNCREF, \EINIT~((\REFFUNC~y)~\END)^\ast \} \\ &&|& + \hex{01}~~\hex{00}~~y^\ast{:}\Bvec(\Bfuncidx) + &\Rightarrow& \{ \ETYPE~\FUNCREF, \EINIT~((\REFFUNC~y)~\END)^\ast \} \\ &&|& + \hex{02}~~x{:}\Btableidx~~o{:}\Bexpr~~\hex{00}~~y^\ast{:}\Bvec(\Bfuncidx) + &\Rightarrow& \{ \ETABLE~x, \EOFFSET~o, \ETYPE~\FUNCREF, \EINIT~((\REFFUNC~y)~\END)^\ast \} \\ &&|& + \hex{04}~~o{:}\Bexpr~e^\ast{:}\Bvec(\Belemexpr) + &\Rightarrow& \{ \ETABLE~0, \EOFFSET~o, \ETYPE~\FUNCREF, \EINIT~e^\ast \} \\ &&|& + \hex{05}~~\X{et}:\Belemtype~~e^\ast{:}\Bvec(\Belemexpr) &\Rightarrow& \{ \ETYPE~et, \EINIT~e^\ast \} \\ &&|& - \hex{02}~~x{:}\Btableidx~~e{:}\Bexpr~~y^\ast{:}\Bvec(\Bfuncidx) - &\Rightarrow& \{ \ETABLE~x, \EOFFSET~e, \EINIT~((\REFFUNC~y)~\END)^\ast \} \\ + \hex{06}~~x{:}\Btableidx~~o{:}\Bexpr~~\X{et}:\Belemtype~~e^\ast{:}\Bvec(\Belemexpr) + &\Rightarrow& \{ \ETABLE~x, \EOFFSET~o, \ETYPE~et, \EINIT~e^\ast \} \\ \production{elemexpr} & \Belemexpr &::=& \hex{D0}~\hex{0B} &\Rightarrow& \REFNULL~\END \\ &&|& \hex{D2}~x{:}\Bfuncidx~\hex{0B} &\Rightarrow& (\REFFUNC~x)~\END \\ From 1f0d1583d8407e15185fa31cb54aa4cd3fe9323d Mon Sep 17 00:00:00 2001 From: Sergey Rubanov Date: Thu, 22 Aug 2019 02:14:23 +0300 Subject: [PATCH 117/199] Update some links (#52) --- proposals/reference-types/Overview.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/proposals/reference-types/Overview.md b/proposals/reference-types/Overview.md index 54acc0fc35..716b2291a9 100644 --- a/proposals/reference-types/Overview.md +++ b/proposals/reference-types/Overview.md @@ -6,8 +6,8 @@ TODO: more text, motivation, explanation Motivation: -* Easier and more efficient interop with host environment (see e.g. the [WebIDL bindings proposal](https://github.com/WebAssembly/webidl-bindings/blob/master/proposals/webidl-bindings/Explainer.md)) - - allow host references to be represented directly by type `anyref` (see [here](https://github.com/WebAssembly/webidl-bindings/issues/9)) +* Easier and more efficient interop with host environment (see e.g. the [Interface Types proposal](https://github.com/WebAssembly/interface-types/blob/master/proposals/interface-types/Explainer.md)) + - allow host references to be represented directly by type `anyref` (see [here](https://github.com/WebAssembly/interface-types/issues/9)) - without having to go through tables, allocating slots, and maintaining index bijections at the boundaries * Basic manipulation of tables inside Wasm @@ -19,7 +19,7 @@ by repurposing tables as a general memory for opaque data types * Set the stage for later additions: - Typed function references (see [below](#typed-function-references)) - - Exception references (see the [exception handling proposal](https://github.com/WebAssembly/exception-handling/blob/master/proposals/Level-1.md) and [here](https://github.com/WebAssembly/webidl-bindings/issues/10)) + - Exception references (see the [exception handling proposal](https://github.com/WebAssembly/exception-handling/blob/master/proposals/Exceptions.md) and [here](https://github.com/WebAssembly/interface-types/issues/10)) - A smoother transition path to GC (see the [GC proposal](https://github.com/WebAssembly/gc/blob/master/proposals/gc/Overview.md)) Get the most important parts soon! From c69a117cf915c7b048f581f68605de57707abb92 Mon Sep 17 00:00:00 2001 From: gahaas Date: Fri, 23 Aug 2019 17:46:15 +0200 Subject: [PATCH 118/199] New element section encoding in the interpreter (#109) --- document/core/syntax/modules.rst | 2 +- document/core/text/modules.rst | 25 +++++++--- document/core/util/macros.def | 1 + document/core/valid/modules.rst | 14 ++++-- interpreter/binary/decode.ml | 85 ++++++++++++++++++++++---------- interpreter/binary/encode.ml | 53 ++++++++++++-------- interpreter/exec/eval.ml | 16 +++--- interpreter/syntax/ast.ml | 18 ++++--- interpreter/syntax/free.ml | 8 +-- interpreter/text/arrange.ml | 42 +++++++++++----- interpreter/text/parser.mly | 70 +++++++++++++++++--------- interpreter/valid/valid.ml | 8 +-- test/core/binary.wast | 8 +-- test/core/bulk.wast | 2 +- test/core/elem.wast | 39 ++++++++++++--- test/core/imports.wast | 4 +- 16 files changed, 264 insertions(+), 131 deletions(-) diff --git a/document/core/syntax/modules.rst b/document/core/syntax/modules.rst index f1d12c20e3..2d1775cb1d 100644 --- a/document/core/syntax/modules.rst +++ b/document/core/syntax/modules.rst @@ -261,7 +261,7 @@ The |MELEM| component of a module defines a vector of element segments. Each act .. math:: \begin{array}{llll} \production{element segment} & \elem &::=& - \{ \ETABLE~\tableidx, \EOFFSET~\expr, \EINIT~\vec(\elemexpr) \} \\&&|& + \{ \ETABLE~\tableidx, \EOFFSET~\expr, \ETYPE~\elemtype, \EINIT~\vec(\elemexpr) \} \\&&|& \{ \ETYPE~\elemtype, \EINIT~\vec(\elemexpr) \} \\ \production{elemexpr} & \elemexpr &::=& \REFNULL~\END \\&&|& diff --git a/document/core/text/modules.rst b/document/core/text/modules.rst index 3208a0ff2e..e937abaf13 100644 --- a/document/core/text/modules.rst +++ b/document/core/text/modules.rst @@ -293,6 +293,16 @@ An :ref:`element segment ` can be given inline with a table definitio (\iff \Tid' = \Tid^? \neq \epsilon \vee \Tid' \idfresh) \\ \end{array} +.. math:: + \begin{array}{llclll} + \production{module field} & + \text{(}~\text{table}~~\Tid^?~~\Telemtype~~\text{(}~\text{elem}~~x^n{:}\Tvec(\Texpr)~\text{)}~~\text{)} \quad\equiv \\ & \qquad + \text{(}~\text{table}~~\Tid'~~n~~n~~\Telemtype~\text{)}~~ + \text{(}~\text{elem}~~\Tid'~~\text{(}~\text{i32.const}~~\text{0}~\text{)}~~\Tvec(\Texpr)~\text{)} + \\ & \qquad\qquad + (\iff \Tid' = \Tid^? \neq \epsilon \vee \Tid' \idfresh) \\ + \end{array} + Tables can be defined as :ref:`imports ` or :ref:`exports ` inline: .. math:: @@ -483,10 +493,13 @@ Element segments allow for an optional :ref:`table index ` to ide .. math:: \begin{array}{llclll} \production{element segment} & \Telem_I &::=& - \text{(}~\text{elem}~~\Tid^?~~x{:}\Ttableidx_I~~\text{(}~\text{offset}~~e{:}\Texpr_I~\text{)}~~y^\ast{:}\Tvec(\Tfuncidx_I)~\text{)} \\ &&& \qquad - \Rightarrow\quad \{ \ETABLE~x, \EOFFSET~e, \EINIT~y^\ast \} \\ &&|& - \text{(}~\text{elem}~~\Tid^?~~et{:}\Telemtype~~y^\ast{:}\Tvec(\Tfuncidx_I)~\text{)} \\ &&& \qquad - \Rightarrow\quad \{ \ETYPE~et, \EINIT~y^\ast \} \\ + \text{(}~\text{elem}~~\Tid^?~~\text{(}~\text{table}~~x{:}\Ttableidx_I ~\text{)}~~\text{(}~\text{offset}~~e{:}\Texpr_I~\text{)}~~(et, y^\ast){:}\Telemlist~\text{)} \\ &&& \qquad + \Rightarrow\quad \{ \ETABLE~x, \EOFFSET~e, \ETYPE~et, \EINIT~y^\ast \} \\ &&|& + \text{(}~\text{elem}~~\Tid^?~~(et, y^\ast){:}\Telemlist~\text{)} \\ &&& \qquad + \Rightarrow\quad \{\ETYPE~et,\EINIT~y^\ast \} \\ + \production{elemlist} & \Telemlist &::=& + \text{func}~~y^\ast{:}\Tvec(\Tfuncidx_I) \qquad\Rightarrow\quad ( \ETYPE~\FUNCREF, \EINIT~y^\ast ) \\ &&|& + et{:}\Telemtype~~y^\ast{:}\Tvec(\Texpr_I) \qquad\Rightarrow\quad ( \ETYPE~et, \EINIT~y^\ast ) \\ \end{array} .. note:: @@ -506,14 +519,14 @@ As an abbreviation, a single instruction may occur in place of the offset: \text{(}~\text{offset}~~\Tinstr~\text{)} \end{array} -Also, the table index can be omitted, defaulting to :math:`\T{0}`. +Also, the table index can be omitted, defaulting to :math:`\T{0}`. If the table index is omitted, also the :math:`\text{func}` keyword can be omitted. .. math:: \begin{array}{llclll} \production{element segment} & \text{(}~\text{elem}~~\text{(}~\text{offset}~~\Texpr_I~\text{)}~~\dots~\text{)} &\equiv& - \text{(}~\text{elem}~~0~~\text{(}~\text{offset}~~\Texpr_I~\text{)}~~\dots~\text{)} + \text{(}~\text{elem}~~\text{(}~\text{table}~~\text{0}~\text{)}~~\text{(}~\text{offset}~~\Texpr_I~\text{)}~~\dots~\text{)} \end{array} As another abbreviation, element segments may also be specified inline with :ref:`table ` definitions; see the respective section. diff --git a/document/core/util/macros.def b/document/core/util/macros.def index 40c500e171..a2dc1e5787 100644 --- a/document/core/util/macros.def +++ b/document/core/util/macros.def @@ -702,6 +702,7 @@ .. |Tmemarg| mathdef:: \xref{text/instructions}{text-memarg}{\T{memarg}} .. |Talign| mathdef:: \xref{text/instructions}{text-memarg}{\T{align}} .. |Toffset| mathdef:: \xref{text/instructions}{text-memarg}{\T{offset}} +.. |Telemlist| mathdef:: \xref{text/instructions}{text-memarg}{\T{elemlist}} .. |Tlabel| mathdef:: \xref{text/instructions}{text-label}{\T{label}} .. |Tinstr| mathdef:: \xref{text/instructions}{text-instr}{\T{instr}} diff --git a/document/core/valid/modules.rst b/document/core/valid/modules.rst index 35323b4b25..edb0e3f13f 100644 --- a/document/core/valid/modules.rst +++ b/document/core/valid/modules.rst @@ -147,8 +147,8 @@ Element Segments Element segments :math:`\elem` are classified by :ref:`segment types `. -:math:`\{ \ETABLE~x, \EOFFSET~\expr, \EINIT~e^\ast \}` -...................................................... +:math:`\{ \ETABLE~x, \EOFFSET~\expr, \ETYPE~et, \EINIT~e^\ast \}` +................................................................. * The table :math:`C.\CTABLES[x]` must be defined in the context. @@ -160,6 +160,8 @@ Element segments :math:`\elem` are classified by :ref:`segment types `. +* The :ref:`element type ` :math:`et` must be |FUNCREF|. + * For each :math:`e_i` in :math:`e^\ast`, * The element expression :math:`e_i` must be :ref:`valid `. @@ -175,15 +177,19 @@ Element segments :math:`\elem` are classified by :ref:`segment types ` :math:`et` must be |FUNCREF|. + * For each :math:`e_i` in :math:`e^\ast`, * The element expression :math:`e_i` must be :ref:`valid `. @@ -193,6 +199,8 @@ Element segments :math:`\elem` are classified by :ref:`segment types FuncRefType + | _ -> error s (pos s - 1) "invalid elem kind" + let table s = let ttype = table_type s in {ttype} @@ -613,27 +618,10 @@ let code_section s = (* Element section *) -let segment active passive s = - match vu32 s with - | 0l -> - let index = Source.(0l @@ Source.no_region) in - let offset = const s in - let init = active s in - Active {index; offset; init} - | 1l -> - let etype, data = passive s in - Passive {etype; data} - | 2l -> - let index = at var s in - let offset = const s in - let init = active s in - Active {index; offset; init} - | _ -> error s (pos s - 1) "invalid segment kind" - -let active_elem s = +let elem_index s = ref_func (at var s) -let passive_elem s = +let elem_expr s = match u8 s with | 0xd0 -> end_ s; ref_null | 0xd2 -> @@ -642,16 +630,45 @@ let passive_elem s = ref_func x | _ -> error s (pos s - 1) "invalid elem" -let active_elem_segment s = - vec (at active_elem) s +let elem_indices s = + vec (at elem_index) s -let passive_elem_segment s = - let etype = elem_type s in - let init = vec (at passive_elem) s in - etype, init +let elem_refs s = + vec (at elem_expr) s let table_segment s = - segment active_elem_segment passive_elem_segment s + match vu32 s with + | 0l -> + let index = Source.(0l @@ Source.no_region) in + let offset = const s in + let init = elem_indices s in + ActiveElem {index; offset; etype = FuncRefType; init} + | 1l -> + let etype = elem_kind s in + let data = elem_indices s in + PassiveElem {etype; data} + | 2l -> + let index = at var s in + let offset = const s in + let etype = elem_kind s in + let init = elem_indices s in + ActiveElem {index; offset; etype; init} + | 4l -> + let index = Source.(0l @@ Source.no_region) in + let offset = const s in + let init = elem_refs s in + ActiveElem {index; offset; etype = FuncRefType; init} + | 5l -> + let etype = elem_type s in + let data = elem_refs s in + PassiveElem {etype; data} + | 6l -> + let index = at var s in + let offset = const s in + let etype = elem_type s in + let init = elem_refs s in + ActiveElem {index; offset; etype; init} + | _ -> error s (pos s - 1) "invalid table segment kind" let elem_section s = section `ElemSection (vec (at table_segment)) [] s @@ -660,7 +677,21 @@ let elem_section s = (* Data section *) let memory_segment s = - segment string (fun s -> (), string s) s + match vu32 s with + | 0l -> + let index = Source.(0l @@ Source.no_region) in + let offset = const s in + let init = string s in + ActiveData {index; offset; init} + | 1l -> + let data = string s in + PassiveData {data} + | 2l -> + let index = at var s in + let offset = const s in + let init = string s in + ActiveData {index; offset; init} + | _ -> error s (pos s - 1) "invalid memory segment kind" let data_section s = section `DataSection (vec (at memory_segment)) [] s diff --git a/interpreter/binary/encode.ml b/interpreter/binary/encode.ml index 955628a01b..7bc5095120 100644 --- a/interpreter/binary/encode.ml +++ b/interpreter/binary/encode.ml @@ -477,39 +477,50 @@ let encode m = section 10 (vec code) fs (fs <> []) (* Element section *) - let segment active passive seg = - match seg.it with - | Active {index; offset; init} -> - if index.it = 0l then - u8 0x00 - else begin - u8 0x02; var index - end; - const offset; active init - | Passive {etype; data} -> - u8 0x01; passive etype data - - let active_elem el = + let elem_expr el = + match el.it with + | RefNull -> u8 0xd0; end_ () + | RefFunc x -> u8 0xd2; var x; end_ () + + let elem_index el = match el.it with | RefNull -> assert false | RefFunc x -> var x - let passive_elem el = - match el.it with - | RefNull -> u8 0xd0; end_ () - | RefFunc x -> u8 0xd2; var x; end_ () + let elem_indices data = vec elem_index data + + let all_func_ref l = not (List.exists (fun elem -> elem.it = RefNull) l) let table_segment seg = - let active init = vec active_elem init in - let passive etype data = elem_type etype; vec passive_elem data in - segment active passive seg + match seg.it with + | ActiveElem {index = {it = 0l;_}; offset; init; _} + when all_func_ref init -> + u8 0x00; const offset; elem_indices init + | PassiveElem {data; _} + when all_func_ref data -> + u8 0x01; u8 0x00; elem_indices data + | ActiveElem {index; offset; init; _} + when all_func_ref init -> + u8 0x02; var index; const offset; u8 0x00; elem_indices init + | ActiveElem {index = {it = 0l;_}; offset; etype; init} -> + u8 0x04; const offset; vec elem_expr init + | PassiveElem {etype; data} -> + u8 0x05; elem_type etype; vec elem_expr data + | ActiveElem {index; offset; etype; init} -> + u8 0x06; var index; const offset; elem_type etype; vec elem_expr init let elem_section elems = section 9 (vec table_segment) elems (elems <> []) (* Data section *) let memory_segment seg = - segment string (fun _ s -> string s) seg + match seg.it with + | ActiveData {index = {it = 0l;_}; offset; init} -> + u8 0x00; const offset; string init + | PassiveData {data} -> + u8 0x01; string data + | ActiveData {index; offset; init} -> + u8 0x02; var index; const offset; string init let data_section datas = section 11 (vec memory_segment) datas (datas <> []) diff --git a/interpreter/exec/eval.ml b/interpreter/exec/eval.ml index adf84945f6..1a9c73f02f 100644 --- a/interpreter/exec/eval.ml +++ b/interpreter/exec/eval.ml @@ -448,13 +448,13 @@ let elem_list inst init = let create_elem (inst : module_inst) (seg : table_segment) : elem_inst = match seg.it with - | Active _ -> ref None - | Passive {data; _} -> ref (Some (elem_list inst data)) + | ActiveElem _ -> ref None + | PassiveElem {data; _} -> ref (Some (elem_list inst data)) let create_data (inst : module_inst) (seg : memory_segment) : data_inst = match seg.it with - | Active _ -> ref None - | Passive {data; _} -> ref (Some data) + | ActiveData _ -> ref None + | PassiveData {data} -> ref (Some data) let init_func (inst : module_inst) (func : func_inst) = @@ -464,25 +464,25 @@ let init_func (inst : module_inst) (func : func_inst) = let init_table (inst : module_inst) (seg : table_segment) = match seg.it with - | Active {index; offset = const; init} -> + | ActiveElem {index; offset = const; init; _} -> let tab = table inst index in let offset = i32 (eval_const inst const) const.at in let elems = elem_list inst init in let len = Int32.of_int (List.length elems) in (try Table.init tab elems offset 0l len with Table.Bounds -> Link.error seg.at "elements segment does not fit table") - | Passive _ -> () + | PassiveElem _ -> () let init_memory (inst : module_inst) (seg : memory_segment) = match seg.it with - | Active {index; offset = const; init} -> + | ActiveData {index; offset = const; init} -> let mem = memory inst index in let offset' = i32 (eval_const inst const) const.at in let offset = I64_convert.extend_i32_u offset' in let len = Int32.of_int (String.length init) in (try Memory.init mem init offset 0L len with Memory.Bounds -> Link.error seg.at "data segment does not fit memory") - | Passive _ -> () + | PassiveData _ -> () let add_import (m : module_) (ext : extern) (im : import) (inst : module_inst) diff --git a/interpreter/syntax/ast.ml b/interpreter/syntax/ast.ml index 98f1044943..b7770a8715 100644 --- a/interpreter/syntax/ast.ml +++ b/interpreter/syntax/ast.ml @@ -140,18 +140,21 @@ and memory' = mtype : memory_type; } -type ('data, 'ty) segment = ('data, 'ty) segment' Source.phrase -and ('data, 'ty) segment' = - | Active of {index : var; offset : const; init : 'data} - | Passive of {etype : 'ty; data : 'data} - type elem = elem' Source.phrase and elem' = | RefNull | RefFunc of var -type table_segment = (elem list, elem_type) segment -type memory_segment = (string, unit) segment + +type table_segment = table_segment' Source.phrase +and table_segment' = + | ActiveElem of {index : var; offset : const; etype : elem_type; init : elem list} + | PassiveElem of {etype : elem_type; data : elem list} + +type memory_segment = memory_segment' Source.phrase +and memory_segment' = + | ActiveData of {index : var; offset : const; init : string} + | PassiveData of {data : string} (* Modules *) @@ -264,3 +267,4 @@ let string_of_name n = in List.iter escape n; Buffer.contents b + diff --git a/interpreter/syntax/free.ml b/interpreter/syntax/free.ml index a57a56719e..e4f5536dd2 100644 --- a/interpreter/syntax/free.ml +++ b/interpreter/syntax/free.ml @@ -97,14 +97,14 @@ let elem (e : elem) = let table_segment (s : table_segment) = match s.it with - | Active {index; offset; init} -> + | ActiveElem {index; offset; init; _} -> tables (var index) ++ const offset ++ list elem init - | Passive {etype; data} -> list elem data + | PassiveElem {data; _} -> list elem data let memory_segment (s : memory_segment) = match s.it with - | Active {index; offset; init} -> memories (var index) ++ const offset - | Passive {etype; data} -> empty + | ActiveData {index; offset; init} -> memories (var index) ++ const offset + | PassiveData {data} -> empty let type_ (t : type_) = empty diff --git a/interpreter/text/arrange.ml b/interpreter/text/arrange.ml index 599347b791..6ed57bbac6 100644 --- a/interpreter/text/arrange.ml +++ b/interpreter/text/arrange.ml @@ -296,29 +296,47 @@ let memory off i mem = let {mtype = MemoryType lim} = mem.it in Node ("memory $" ^ nat (off + i) ^ " " ^ limits nat32 lim, []) -let segment head active passive seg = - match seg.it with - | Active {index; offset; init} -> - Node (head, atom var index :: Node ("offset", const offset) :: active init) - | Passive {etype; data} -> Node (head, passive etype data) - -let active_elem el = +let elem_index el = match el.it with | RefNull -> assert false | RefFunc x -> atom var x -let passive_elem el = +let elem_expr el = match el.it with | RefNull -> Node ("ref.null", []) | RefFunc x -> Node ("ref.func", [atom var x]) +let all_func_ref l = not (List.exists (fun elem -> elem.it = RefNull) l) + let elems seg = - let active init = list active_elem init in - let passive etype init = atom elem_type etype :: list passive_elem init in - segment "elem" active passive seg + match seg.it with + | ActiveElem {index = {it = 0l;_}; offset; init; _} + when all_func_ref init -> + Node ("elem", Node ("offset", const offset) :: list elem_index init) + | ActiveElem {index; offset; init; _} + when all_func_ref init -> + Node ("elem", Node ("table", [atom var index]) + :: Node ("offset", const offset) :: Atom "func" :: list elem_index init) + | ActiveElem {index = {it = 0l;_}; offset; etype; init} -> + Node ("elem", Node ("offset", const offset) :: atom elem_type etype + :: list elem_expr init) + | ActiveElem {index; offset; etype; init} -> + Node ("elem", Node ("table", [atom var index]) + :: Node ("offset", const offset) + :: atom elem_type etype :: list elem_expr init) + | PassiveElem {data; _} + when all_func_ref data -> + Node ("elem func", list elem_index data) + | PassiveElem {etype; data} -> + Node ("elem", atom elem_type etype + :: list elem_expr data) let data seg = - segment "data" break_bytes (fun _ bs -> break_bytes bs) seg + match seg.it with + | ActiveData {index; offset; init} -> + Node ("data", atom var index :: Node ("offset", const offset) + :: break_bytes init) + | PassiveData {data} -> Node ("data", break_bytes data) (* Modules *) diff --git a/interpreter/text/parser.mly b/interpreter/text/parser.mly index 9aee29a034..5de6b0dc1d 100644 --- a/interpreter/text/parser.mly +++ b/interpreter/text/parser.mly @@ -566,42 +566,58 @@ func_body : /* Tables, Memories & Globals */ +table_use : + | LPAR TABLE var RPAR { fun c -> $3 c } + offset : | LPAR OFFSET const_expr RPAR { $3 } | expr { let at = at () in fun c -> $1 c @@ at } /* Sugar */ -elemref : +elem_kind : + | FUNC { FuncRefType } + +elem_expr : | LPAR REF_NULL RPAR { let at = at () in fun c -> ref_null @@ at } | LPAR REF_FUNC var RPAR { let at = at () in fun c -> ref_func ($3 c func) @@ at } -passive_elemref_list : +elem_expr_list : | /* empty */ { fun c -> [] } - | elemref passive_elemref_list { fun c -> $1 c :: $2 c } + | elem_expr elem_expr_list { fun c -> $1 c :: $2 c } -active_elemref_list : +elem_var_list : | var_list { let f = function {at; _} as x -> ref_func x @@ at in fun c lookup -> List.map f ($1 c lookup) } +elem_list : + | elem_kind elem_var_list + { ($1, fun c -> $2 c func) } + | elem_type elem_expr_list + { ($1, fun c -> $2 c) } + + elem : - | LPAR ELEM bind_var_opt elem_type passive_elemref_list RPAR + | LPAR ELEM bind_var_opt offset elem_var_list RPAR /* Sugar */ { let at = at () in fun c -> ignore ($3 c anon_elem bind_elem); - fun () -> Passive {etype = $4; data = $5 c} @@ at } - | LPAR ELEM bind_var var offset active_elemref_list RPAR - { let at = at () in - fun c -> ignore (bind_elem c $3); fun () -> - Active {index = $4 c table; offset = $5 c; init = $6 c func} @@ at } - | LPAR ELEM var offset active_elemref_list RPAR + ActiveElem {index = 0l @@ at; offset = $4 c; etype = FuncRefType; + init = $5 c func} @@ at } + | LPAR ELEM bind_var_opt elem_list RPAR + { let at = at () in + fun c -> ignore ($3 c anon_elem bind_elem); + fun () -> PassiveElem {etype = (fst $4); data = (snd $4) c} @@ at } + | LPAR ELEM bind_var_opt table_use offset elem_list RPAR { let at = at () in - fun c -> ignore (anon_elem c); + fun c -> ignore ($3 c anon_elem bind_elem); fun () -> - Active {index = $3 c table; offset = $4 c; init = $5 c func} @@ at } - | LPAR ELEM offset active_elemref_list RPAR /* Sugar */ + ActiveElem {index = $4 c table; offset = $5 c; + etype = (fst $6); init = (snd $6) c} @@ at } + | LPAR ELEM bind_var_opt offset elem_list RPAR /* Sugar */ { let at = at () in - fun c -> ignore (anon_elem c); - fun () -> Active {index = 0l @@ at; offset = $3 c; init = $4 c func} @@ at } + fun c -> ignore ($3 c anon_elem bind_elem); + fun () -> ActiveElem {index = 0l @@ at; offset = $4 c; + etype = (fst $5); init = (snd $5) c} @@ at } table : | LPAR TABLE bind_var_opt table_fields RPAR @@ -620,32 +636,40 @@ table_fields : | inline_export table_fields /* Sugar */ { fun c x at -> let tabs, elems, ims, exs = $2 c x at in tabs, elems, ims, $1 (TableExport x) c :: exs } - | elem_type LPAR ELEM active_elemref_list RPAR /* Sugar */ + | elem_type LPAR ELEM elem_var_list RPAR /* Sugar */ { fun c x at -> let offset = [i32_const (0l @@ at) @@ at] @@ at in let init = $4 c func in let size = Lib.List32.length init in [{ttype = TableType ({min = size; max = Some size}, $1)} @@ at], - [Active {index = x; offset; init} @@ at], + [ActiveElem {index = x; offset; etype = FuncRefType; init} @@ at], + [], [] } + | elem_type LPAR ELEM elem_expr elem_expr_list RPAR /* Sugar */ + { fun c x at -> + let offset = [i32_const (0l @@ at) @@ at] @@ at in + let init = (fun c -> $4 c :: $5 c) c in + let size = Lib.List32.length init in + [{ttype = TableType ({min = size; max = Some size}, $1)} @@ at], + [ActiveElem {index = x; offset; etype = FuncRefType; init} @@ at], [], [] } data : | LPAR DATA bind_var_opt string_list RPAR { let at = at () in fun c -> ignore ($3 c anon_data bind_data); - fun () -> Passive {etype = (); data = $4} @@ at } + fun () -> PassiveData {data = $4} @@ at } | LPAR DATA bind_var var offset string_list RPAR { let at = at () in fun c -> ignore (bind_data c $3); - fun () -> Active {index = $4 c memory; offset = $5 c; init = $6} @@ at } + fun () -> ActiveData {index = $4 c memory; offset = $5 c; init = $6} @@ at } | LPAR DATA var offset string_list RPAR { let at = at () in fun c -> ignore (anon_data c); - fun () -> Active {index = $3 c memory; offset = $4 c; init = $5} @@ at } + fun () -> ActiveData {index = $3 c memory; offset = $4 c; init = $5} @@ at } | LPAR DATA offset string_list RPAR /* Sugar */ { let at = at () in fun c -> ignore (anon_data c); - fun () -> Active {index = 0l @@ at; offset = $3 c; init = $4} @@ at } + fun () -> ActiveData {index = 0l @@ at; offset = $3 c; init = $4} @@ at } memory : | LPAR MEMORY bind_var_opt memory_fields RPAR @@ -669,7 +693,7 @@ memory_fields : let offset = [i32_const (0l @@ at) @@ at] @@ at in let size = Int32.(div (add (of_int (String.length $3)) 65535l) 65536l) in [{mtype = MemoryType {min = size; max = Some size}} @@ at], - [Active {index = x; offset; init = $3} @@ at], + [ActiveData {index = x; offset; init = $3} @@ at], [], [] } global : diff --git a/interpreter/valid/valid.ml b/interpreter/valid/valid.ml index 584fd30c8b..6217158fd4 100644 --- a/interpreter/valid/valid.ml +++ b/interpreter/valid/valid.ml @@ -429,19 +429,19 @@ let check_elemref (c : context) (el : elem) = let check_elem (c : context) (seg : table_segment) = match seg.it with - | Active {index; offset; init} -> + | ActiveElem {index; offset; init; _} -> ignore (table c index); check_const c offset I32Type; List.iter (check_elemref c) init - | Passive {etype; data} -> + | PassiveElem {data; _} -> List.iter (check_elemref c) data let check_data (c : context) (seg : memory_segment) = match seg.it with - | Active {index; offset; init} -> + | ActiveData {index; offset; init} -> ignore (memory c index); check_const c offset I32Type - | Passive init -> () + | PassiveData init -> () let check_global (c : context) (glob : global) = let {gtype; value} = glob.it in diff --git a/test/core/binary.wast b/test/core/binary.wast index a862cc6141..1f5ee375e3 100644 --- a/test/core/binary.wast +++ b/test/core/binary.wast @@ -733,7 +733,7 @@ "\05\03\01\00\00" ;; Memory section "\09\07\01" ;; Element section with one segment - "\01\70" ;; Passive, funcref + "\05\70" ;; Passive, funcref "\01" ;; 1 element "\d3\00\0b" ;; bad opcode, index 0, end @@ -759,7 +759,7 @@ "\05\03\01\00\00" ;; Memory section "\09\07\01" ;; Element section with one segment - "\01\7f" ;; Passive, i32 + "\05\7f" ;; Passive, i32 "\01" ;; 1 element "\d2\00\0b" ;; ref.func, index 0, end @@ -784,7 +784,7 @@ "\05\03\01\00\00" ;; Memory section "\09\07\01" ;; Element section with one segment - "\01\70" ;; Passive, funcref + "\05\70" ;; Passive, funcref "\01" ;; 1 element "\d2\00\0b" ;; ref.func, index 0, end @@ -808,7 +808,7 @@ "\05\03\01\00\00" ;; Memory section "\09\06\01" ;; Element section with one segment - "\01\70" ;; Passive, funcref + "\05\70" ;; Passive, funcref "\01" ;; 1 element "\d0\0b" ;; ref.null, end diff --git a/test/core/bulk.wast b/test/core/bulk.wast index f7c44e5432..98c4a49a61 100644 --- a/test/core/bulk.wast +++ b/test/core/bulk.wast @@ -215,7 +215,7 @@ (table 1 funcref) (func $f) (elem $p funcref (ref.func $f)) - (elem $a 0 (i32.const 0) $f) + (elem $a (table 0) (i32.const 0) func $f) (func (export "drop_passive") (elem.drop $p)) (func (export "init_passive") diff --git a/test/core/elem.wast b/test/core/elem.wast index 3dac72655a..4dd3e7822c 100644 --- a/test/core/elem.wast +++ b/test/core/elem.wast @@ -4,20 +4,43 @@ (module (table $t 10 funcref) (func $f) + (func $g) + (elem (table $t) (i32.const 0) func) (elem (i32.const 0)) (elem (i32.const 0) $f $f) (elem (offset (i32.const 0))) (elem (offset (i32.const 0)) $f $f) - (elem 0 (i32.const 0)) - (elem 0x0 (i32.const 0) $f $f) - (elem 0x000 (offset (i32.const 0))) - (elem 0 (offset (i32.const 0)) $f $f) - (elem $t (i32.const 0)) - (elem $t (i32.const 0) $f $f) - (elem $t (offset (i32.const 0))) - (elem $t (offset (i32.const 0)) $f $f) + + (elem func) + (elem $s func) + (elem func $f $f $g $g) + (elem $x func $f $f $g $g) + + (elem (table 0) (i32.const 0) func) + (elem (table 0x0) (i32.const 0) func $f $f) + (elem (table 0x000) (offset (i32.const 0)) func) + (elem (table 0) (offset (i32.const 0)) func $f $f) + (elem (table $t) (i32.const 0) func) + (elem (table $t) (i32.const 0) func $f $f) + (elem (table $t) (offset (i32.const 0)) func) + (elem (table $t) (offset (i32.const 0)) func $f $f) + + (elem (i32.const 3) funcref (ref.func $f) (ref.func $g) (ref.func $f)) + (elem (i32.const 3) funcref (ref.func $f) (ref.null) (ref.func $f)) + + (elem funcref (ref.func $f) (ref.func $g) (ref.func $f)) + (elem funcref (ref.func $f) (ref.func $g) (ref.null)) + + (elem (table $t) (i32.const 3) funcref (ref.func $f) (ref.func $g) (ref.func $f)) + (elem (table $t) (i32.const 3) funcref (ref.func $f) (ref.null) (ref.func $g)) ) +(module + (func $f) + (func $g) + + (table $t funcref (elem (ref.func $f) (ref.null) (ref.func $g))) +) ;; Basic use (module diff --git a/test/core/imports.wast b/test/core/imports.wast index 2f0200dc3f..bbb96e053b 100644 --- a/test/core/imports.wast +++ b/test/core/imports.wast @@ -271,7 +271,7 @@ (module (type (func (result i32))) (import "spectest" "table" (table 10 20 funcref)) - (elem 0 (i32.const 1) $f $g) + (elem (table 0) (i32.const 1) func $f $g) (func (export "call") (param i32) (result i32) (call_indirect (type 0) (local.get 0)) @@ -290,7 +290,7 @@ (module (type (func (result i32))) (table (import "spectest" "table") 10 20 funcref) - (elem 0 (i32.const 1) $f $g) + (elem (table 0) (i32.const 1) func $f $g) (func (export "call") (param i32) (result i32) (call_indirect (type 0) (local.get 0)) From 3d87cfaec8d9c55bd0cd28e488f6c9974ca60633 Mon Sep 17 00:00:00 2001 From: gahaas Date: Wed, 11 Sep 2019 20:02:00 +0200 Subject: [PATCH 119/199] Adjust element segment encoding to match the bulk-memory proposal (#53) * Adjust element segment encoding to match the bulk-memory proposal * Update interpreter/binary/encode.ml Co-Authored-By: Andreas Rossberg * Address comments --- document/core/binary/modules.rst | 2 +- interpreter/binary/decode.ml | 34 +++++++++++++++++++------------- interpreter/binary/encode.ml | 12 +++++------ test/core/binary.wast | 20 +++++++++++++------ 4 files changed, 40 insertions(+), 28 deletions(-) diff --git a/document/core/binary/modules.rst b/document/core/binary/modules.rst index 0d5e9a8420..f7c36c9f21 100644 --- a/document/core/binary/modules.rst +++ b/document/core/binary/modules.rst @@ -321,7 +321,7 @@ It decodes into a vector of :ref:`element segments ` that represent \production{element segment} & \Belem &::=& \hex{00}~~e{:}\Bexpr~~y^\ast{:}\Bvec(\Bfuncidx) &\Rightarrow& \{ \ETABLE~0, \EOFFSET~e, \EINIT~y^\ast \} \\ &&|& - \hex{02}~~x{:}\Btableidx~~e{:}\Bexpr~~y^\ast{:}\Bvec(\Bfuncidx) + \hex{02}~~x{:}\Btableidx~~e{:}\Bexpr~~\hex{00}~~y^\ast{:}\Bvec(\Bfuncidx) &\Rightarrow& \{ \ETABLE~x, \EOFFSET~e, \EINIT~y^\ast \} \\ \end{array} diff --git a/interpreter/binary/decode.ml b/interpreter/binary/decode.ml index 691778de70..56e44569ff 100644 --- a/interpreter/binary/decode.ml +++ b/interpreter/binary/decode.ml @@ -550,6 +550,10 @@ let table s = let table_section s = section `TableSection (vec (at table)) [] s +let elem_kind s = + match vs7 s with + | 0x00 -> FuncRefType + | _ -> error s (pos s - 1) "invalid elem kind" (* Memory section *) @@ -621,21 +625,23 @@ let code_section s = (* Element section *) -let segment dat s = - let pos = pos s in - let x = at vu32 s in - let index = - match x.Source.it with - | 0l -> x - | 2l -> at var s - | _ -> error s pos "invalid segment kind" - in - let offset = const s in - let init = dat s in - {index; offset; init} +let segment dat kind s = + match u8 s with + | 0 -> + let index = Source.(0l @@ Source.no_region) in + let offset = const s in + let init = dat s in + {index; offset; init} + | 2 -> + let index = at var s in + let offset = const s in + let _ = kind s in + let init = dat s in + {index; offset; init} + | _ -> error s (pos s - 1) "invalid segment kind" let table_segment s = - segment (vec (at var)) s + segment (vec (at var)) elem_kind s let elem_section s = section `ElemSection (vec (at table_segment)) [] s @@ -644,7 +650,7 @@ let elem_section s = (* Data section *) let memory_segment s = - segment string s + segment string (fun s -> ()) s let data_section s = section `DataSection (vec (at memory_segment)) [] s diff --git a/interpreter/binary/encode.ml b/interpreter/binary/encode.ml index 3d7d13a514..13a93fbaa1 100644 --- a/interpreter/binary/encode.ml +++ b/interpreter/binary/encode.ml @@ -490,13 +490,11 @@ let encode m = (* Element section *) let segment dat seg = - let {index; offset; init} = seg.it in - if index.it = 0l then - u8 0x00 - else begin - u8 0x02; var index - end; - const offset; dat init + match seg.it with + | {index; offset; init} when index.it = 0l -> + u8 0x00; const offset; dat init + | {index; offset; init} -> + u8 0x02; var index; const offset; u8 0x00; dat init let table_segment seg = segment (vec var) seg diff --git a/test/core/binary.wast b/test/core/binary.wast index e28f591ffd..aed81881e1 100644 --- a/test/core/binary.wast +++ b/test/core/binary.wast @@ -114,26 +114,34 @@ "\0b" ;; end ) -;; Data segment memory index can have non-minimal length (module binary "\00asm" "\01\00\00\00" "\05\03\01" ;; Memory section with 1 entry "\00\00" ;; no max, minimum 0 - "\0b\07\01" ;; Data section with 1 entry - "\80\00" ;; Memory index 0, encoded with 2 bytes + "\0b\06\01" ;; Data section with 1 entry + "\00" ;; Memory index 0 "\41\00\0b\00" ;; (i32.const 0) with contents "" ) -;; Element segment table index can have non-minimal length (module binary "\00asm" "\01\00\00\00" "\04\04\01" ;; Table section with 1 entry "\70\00\00" ;; no max, minimum 0, funcref - "\09\07\01" ;; Element section with 1 entry - "\80\00" ;; Table index 0, encoded with 2 bytes + "\09\06\01" ;; Element section with 1 entry + "\00" ;; Table index 0 "\41\00\0b\00" ;; (i32.const 0) with no elements ) +;; Element segment table index can have non-minimal length +(module binary + "\00asm" "\01\00\00\00" + "\04\04\01" ;; Table section with 1 entry + "\70\00\00" ;; no max, minimum 0, funcref + "\09\09\01" ;; Element section with 1 entry + "\02\80\00" ;; Table index 0, encoded with 2 bytes + "\41\00\0b\00\00" ;; (i32.const 0) with no elements +) + ;; Unsigned LEB128 must not be overlong (assert_malformed (module binary From bc8160206e607c12beff19829d6b08bfcc9b7ab6 Mon Sep 17 00:00:00 2001 From: gahaas Date: Thu, 12 Sep 2019 10:04:01 +0200 Subject: [PATCH 120/199] [test] Fix the binary.wast test for multi-bytes table indices (#110) --- interpreter/binary/decode.ml | 14 +++++++------- test/core/binary.wast | 6 +++--- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/interpreter/binary/decode.ml b/interpreter/binary/decode.ml index ddb73df273..ba1315d0ba 100644 --- a/interpreter/binary/decode.ml +++ b/interpreter/binary/decode.ml @@ -637,32 +637,32 @@ let elem_refs s = vec (at elem_expr) s let table_segment s = - match vu32 s with - | 0l -> + match u8 s with + | 0x00 -> let index = Source.(0l @@ Source.no_region) in let offset = const s in let init = elem_indices s in ActiveElem {index; offset; etype = FuncRefType; init} - | 1l -> + | 0x01 -> let etype = elem_kind s in let data = elem_indices s in PassiveElem {etype; data} - | 2l -> + | 0x02 -> let index = at var s in let offset = const s in let etype = elem_kind s in let init = elem_indices s in ActiveElem {index; offset; etype; init} - | 4l -> + | 0x04 -> let index = Source.(0l @@ Source.no_region) in let offset = const s in let init = elem_refs s in ActiveElem {index; offset; etype = FuncRefType; init} - | 5l -> + | 0x05 -> let etype = elem_type s in let data = elem_refs s in PassiveElem {etype; data} - | 6l -> + | 0x06 -> let index = at var s in let offset = const s in let etype = elem_type s in diff --git a/test/core/binary.wast b/test/core/binary.wast index 1f5ee375e3..cd9a1d6add 100644 --- a/test/core/binary.wast +++ b/test/core/binary.wast @@ -129,9 +129,9 @@ "\00asm" "\01\00\00\00" "\04\04\01" ;; Table section with 1 entry "\70\00\00" ;; no max, minimum 0, funcref - "\09\07\01" ;; Element section with 1 entry - "\80\00" ;; Table index 0, encoded with 2 bytes - "\41\00\0b\00" ;; (i32.const 0) with no elements + "\09\09\01" ;; Element section with 1 entry + "\02\80\00" ;; Table index 0, encoded with 2 bytes + "\41\00\0b\00\00" ;; (i32.const 0) with no elements ) ;; Unsigned LEB128 must not be overlong From d5101bc8cd097928936825c3c483e50cd509d7af Mon Sep 17 00:00:00 2001 From: gahaas Date: Tue, 17 Sep 2019 13:18:07 +0200 Subject: [PATCH 121/199] [test] Add negative test for ref.func globals (#54) --- test/core/ref_func.wast | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/test/core/ref_func.wast b/test/core/ref_func.wast index f3c8010bab..393d3f829f 100644 --- a/test/core/ref_func.wast +++ b/test/core/ref_func.wast @@ -53,3 +53,12 @@ (assert_return (invoke "call-v" (i32.const 4)) (i32.const 5)) (invoke "set-f") (assert_return (invoke "call-v" (i32.const 4)) (i32.const 4)) + +(assert_invalid + (module + (func $f (import "M" "f") (param i32) (result i32)) + (func $g (import "M" "g") (param i32) (result i32)) + (global funcref (ref.func 7)) + ) + "unknown function 7" +) From c1a04150d5783c6dda057a4499dd9d78252d11a1 Mon Sep 17 00:00:00 2001 From: Ryan Hunt Date: Fri, 20 Sep 2019 21:17:57 -0500 Subject: [PATCH 122/199] Fix typo in validation of br_table (#56) --- document/core/valid/instructions.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/document/core/valid/instructions.rst b/document/core/valid/instructions.rst index cf38da6ad0..82f4fd8e15 100644 --- a/document/core/valid/instructions.rst +++ b/document/core/valid/instructions.rst @@ -775,11 +775,11 @@ Control Instructions * The label :math:`C.\CLABELS[l_N]` must be defined in the context. * For all :math:`l_i` in :math:`l^\ast`, - the label :math:`C.\CLABELS[l_i]` must be defined in the context + the label :math:`C.\CLABELS[l_i]` must be defined in the context. * There must be a :ref:`result type ` :math:`[t^?]`, such that: - * The result type :math:`[t^?]` :ref:`matches ` :math:`C.\CLABELS[l_i]`. + * The result type :math:`[t^?]` :ref:`matches ` :math:`C.\CLABELS[l_N]`. * For all :math:`l_i` in :math:`l^\ast`, the result type :math:`[t^?]` :ref:`matches ` :math:`C.\CLABELS[l_i]`. From b1830ae4ae06cf73a0a4fa7abbacf912e4cae476 Mon Sep 17 00:00:00 2001 From: Andreas Rossberg Date: Fri, 4 Oct 2019 13:13:34 +0200 Subject: [PATCH 123/199] Adjust immediate memidx order (#118) --- proposals/bulk-memory-operations/Overview.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/proposals/bulk-memory-operations/Overview.md b/proposals/bulk-memory-operations/Overview.md index 6500b8a807..69fb55ffc1 100644 --- a/proposals/bulk-memory-operations/Overview.md +++ b/proposals/bulk-memory-operations/Overview.md @@ -418,11 +418,11 @@ instr ::= ... | ---- | ---- | ---- | ---- | | `memory.init` | `0xfc 0x08` | `segment:varuint32`, `memory:0x00` | :thinking: copy from a passive data segment to linear memory | | `data.drop` | `0xfc 0x09` | `segment:varuint32` | :thinking: prevent further use of passive data segment | -| `memory.copy` | `0xfc 0x0a` | `memory_src:0x00` `memory_dst:0x00` | :thinking: copy from one region of linear memory to another region | +| `memory.copy` | `0xfc 0x0a` | `memory_dst:0x00` `memory_src:0x00` | :thinking: copy from one region of linear memory to another region | | `memory.fill` | `0xfc 0x0b` | `memory:0x00` | :thinking: fill a region of linear memory with a given byte value | | `table.init` | `0xfc 0x0c` | `segment:varuint32`, `table:0x00` | :thinking: copy from a passive element segment to a table | | `elem.drop` | `0xfc 0x0d` | `segment:varuint32` | :thinking: prevent further use of a passive element segment | -| `table.copy` | `0xfc 0x0e` | `table_src:0x00` `table_dst:0x00` | :thinking: copy from one region of a table to another region | +| `table.copy` | `0xfc 0x0e` | `table_dst:0x00` `table_src:0x00` | :thinking: copy from one region of a table to another region | ### `DataCount` section From f47a675fd5357c89c205d1346e5561b6efb6da3a Mon Sep 17 00:00:00 2001 From: Andreas Rossberg Date: Mon, 7 Oct 2019 11:00:47 +0200 Subject: [PATCH 124/199] Segment refactoring (#113) Refactor segment representation in AST (in both spec and interpreter) by separating out a `segment_mode`. Other changes in Spec: - Various fixes to text format grammar of segments. - Factor out elemkind in binary format. - Add note about possible future extension of element kinds. - Add note about interpretation of segment kinds as bitfields. - Fix some cross references. Other changes in Interpreter: - Rename {table,memory}_segment to {elem,data}_segment. - Some rename elem to elem_expr and global.value to global.ginit for consistency with spec. - Decode the elem segment kind as vu32 to maintain backwards compat. - Some code simplifications / beautifications. --- document/core/appendix/index-rules.rst | 6 +- document/core/binary/modules.rst | 46 +++++--- document/core/exec/instructions.rst | 52 ++++----- document/core/exec/modules.rst | 46 ++++---- document/core/exec/runtime.rst | 2 +- document/core/syntax/modules.rst | 29 +++-- document/core/syntax/types.rst | 6 +- document/core/text/modules.rst | 61 +++++++---- document/core/util/macros.def | 22 +++- document/core/valid/modules.rst | 144 ++++++++++++++----------- interpreter/binary/decode.ml | 124 ++++++++++----------- interpreter/binary/encode.ml | 81 +++++++------- interpreter/exec/eval.ml | 55 +++++----- interpreter/syntax/ast.ml | 37 ++++--- interpreter/syntax/free.ml | 26 ++--- interpreter/syntax/free.mli | 4 +- interpreter/syntax/types.ml | 2 +- interpreter/text/arrange.ml | 58 +++++----- interpreter/text/parser.mly | 49 +++++---- interpreter/valid/valid.ml | 51 +++++---- 20 files changed, 505 insertions(+), 396 deletions(-) diff --git a/document/core/appendix/index-rules.rst b/document/core/appendix/index-rules.rst index 4d02f7af7a..673102aa04 100644 --- a/document/core/appendix/index-rules.rst +++ b/document/core/appendix/index-rules.rst @@ -25,8 +25,10 @@ Construct Judgement :ref:`Table ` :math:`C \vdashtable \table : \tabletype` :ref:`Memory ` :math:`C \vdashmem \mem : \memtype` :ref:`Global ` :math:`C \vdashglobal \global : \globaltype` -:ref:`Element segment ` :math:`C \vdashelem \elem \ok` -:ref:`Data segment ` :math:`C \vdashdata \data \ok` +:ref:`Element segment ` :math:`C \vdashelem \elem : \segtype` +:ref:`Element mode ` :math:`C \vdashelemmode \elemmode : \segtype` +:ref:`Data segment ` :math:`C \vdashdata \data : \segtype` +:ref:`Data mode ` :math:`C \vdashdatamode \datamode : \segtype` :ref:`Start function ` :math:`C \vdashstart \start \ok` :ref:`Export ` :math:`C \vdashexport \export : \externtype` :ref:`Export description ` :math:`C \vdashexportdesc \exportdesc : \externtype` diff --git a/document/core/binary/modules.rst b/document/core/binary/modules.rst index 025bdb2861..0cc7905abb 100644 --- a/document/core/binary/modules.rst +++ b/document/core/binary/modules.rst @@ -314,6 +314,7 @@ It decodes into an optional :ref:`start function ` that represents single: element; segment .. _binary-elem: .. _binary-elemsec: +.. _binary-elemkind: .. _binary-elemexpr: Element Section @@ -327,28 +328,37 @@ It decodes into a vector of :ref:`element segments ` that represent \production{element section} & \Belemsec &::=& \X{seg}^\ast{:}\Bsection_9(\Bvec(\Belem)) &\Rightarrow& \X{seg} \\ \production{element segment} & \Belem &::=& - \hex{00}~~o{:}\Bexpr~~y^\ast{:}\Bvec(\Bfuncidx) - &\Rightarrow& \{ \ETABLE~0, \EOFFSET~o, \ETYPE~\FUNCREF, \EINIT~((\REFFUNC~y)~\END)^\ast \} \\ &&|& - \hex{01}~~\hex{00}~~y^\ast{:}\Bvec(\Bfuncidx) - &\Rightarrow& \{ \ETYPE~\FUNCREF, \EINIT~((\REFFUNC~y)~\END)^\ast \} \\ &&|& - \hex{02}~~x{:}\Btableidx~~o{:}\Bexpr~~\hex{00}~~y^\ast{:}\Bvec(\Bfuncidx) - &\Rightarrow& \{ \ETABLE~x, \EOFFSET~o, \ETYPE~\FUNCREF, \EINIT~((\REFFUNC~y)~\END)^\ast \} \\ &&|& - \hex{04}~~o{:}\Bexpr~e^\ast{:}\Bvec(\Belemexpr) - &\Rightarrow& \{ \ETABLE~0, \EOFFSET~o, \ETYPE~\FUNCREF, \EINIT~e^\ast \} \\ &&|& - \hex{05}~~\X{et}:\Belemtype~~e^\ast{:}\Bvec(\Belemexpr) - &\Rightarrow& \{ \ETYPE~et, \EINIT~e^\ast \} \\ &&|& - \hex{06}~~x{:}\Btableidx~~o{:}\Bexpr~~\X{et}:\Belemtype~~e^\ast{:}\Bvec(\Belemexpr) - &\Rightarrow& \{ \ETABLE~x, \EOFFSET~o, \ETYPE~et, \EINIT~e^\ast \} \\ - \production{elemexpr} & \Belemexpr &::=& + \hex{00}~~e{:}\Bexpr~~y^\ast{:}\Bvec(\Bfuncidx) + &\Rightarrow& \{ \ETYPE~\FUNCREF, \EINIT~((\REFFUNC~y)~\END)^\ast, \EMODE~\EACTIVE~\{ \ETABLE~0, \EOFFSET~e \} \} \\ &&|& + \hex{01}~~\X{et}:\Belemkind~~y^\ast{:}\Bvec(\Bfuncidx) + &\Rightarrow& \{ \ETYPE~\X{et}, \EINIT~((\REFFUNC~y)~\END)^\ast, \EMODE~\EPASSIVE \} \\ &&|& + \hex{02}~~x{:}\Btableidx~~e{:}\Bexpr~~\X{et}:\Belemkind~~y^\ast{:}\Bvec(\Bfuncidx) + &\Rightarrow& \{ \ETYPE~\X{et}, \EINIT~((\REFFUNC~y)~\END)^\ast, \EMODE~\EACTIVE~\{ \ETABLE~x, \EOFFSET~e \} \} \\ &&|& + \hex{04}~~e{:}\Bexpr~~\X{el}^\ast{:}\Bvec(\Belemexpr) + &\Rightarrow& \{ \ETYPE~\FUNCREF, \EINIT~\X{el}^\ast, \EMODE~\EACTIVE~\{ \ETABLE~0, \EOFFSET~e \} \} \\ &&|& + \hex{05}~~\X{et}:\Belemtype~~\X{el}^\ast{:}\Bvec(\Belemexpr) + &\Rightarrow& \{ \ETYPE~et, \EINIT~\X{el}^\ast, \EMODE~\EPASSIVE \} \\ &&|& + \hex{06}~~x{:}\Btableidx~~e{:}\Bexpr~~\X{et}:\Belemtype~~\X{el}^\ast{:}\Bvec(\Belemexpr) + &\Rightarrow& \{ \ETYPE~et, \EINIT~\X{el}^\ast, \EMODE~\EACTIVE~\{ \ETABLE~x, \EOFFSET~e \} \} \\ + \production{element kind} & \Belemkind &::=& + \hex{00} &\Rightarrow& \FUNCREF \\ + \production{element expression} & \Belemexpr &::=& \hex{D0}~\hex{0B} &\Rightarrow& \REFNULL~\END \\ &&|& \hex{D2}~x{:}\Bfuncidx~\hex{0B} &\Rightarrow& (\REFFUNC~x)~\END \\ \end{array} .. note:: + The initial byte can be interpreted as a bitfield. + Bit 0 indicates a passive segment, + bit 1 indicates the presence of an explicit table index for an active segment, + bit 2 indicates the use of element type and element expressions instead of element kind and element indices. + In the current version of WebAssembly, at most one table may be defined or imported in a single module, so all valid :ref:`active ` element segments have a |ETABLE| value of :math:`0`. + Additional element kinds may be added in future versions of WebAssembly. + .. index:: ! code section, function, local, type index, function type pair: binary format; function @@ -427,14 +437,18 @@ It decodes into a vector of :ref:`data segments ` that represent th \X{seg}^\ast{:}\Bsection_{11}(\Bvec(\Bdata)) &\Rightarrow& \X{seg} \\ \production{data segment} & \Bdata &::=& \hex{00}~~e{:}\Bexpr~~b^\ast{:}\Bvec(\Bbyte) - &\Rightarrow& \{ \DMEM~0, \DOFFSET~e, \DINIT~b^\ast \} \\ &&|& + &\Rightarrow& \{ \DINIT~b^\ast, \DMODE~\DACTIVE~\{ \DMEM~0, \DOFFSET~e \} \} \\ &&|& \hex{01}~~b^\ast{:}\Bvec(\Bbyte) - &\Rightarrow& \{ \DINIT~b^\ast \} \\ &&|& + &\Rightarrow& \{ \DINIT~b^\ast, \DMODE~\DPASSIVE \} \\ &&|& \hex{02}~~x{:}\Bmemidx~~e{:}\Bexpr~~b^\ast{:}\Bvec(\Bbyte) - &\Rightarrow& \{ \DMEM~x, \DOFFSET~e, \DINIT~b^\ast \} \\ + &\Rightarrow& \{ \DINIT~b^\ast, \DMODE~\DACTIVE~\{ \DMEM~x, \DOFFSET~e \} \} \\ \end{array} .. note:: + The initial byte can be interpreted as a bitfield. + Bit 0 indicates a passive segment, + bit 1 indicates the presence of an explicit memory index for an active segment. + In the current version of WebAssembly, at most one memory may be defined or imported in a single module, so all valid :ref:`active ` data segments have a |DMEM| value of :math:`0`. diff --git a/document/core/exec/instructions.rst b/document/core/exec/instructions.rst index d9371dad49..db73b5bee8 100644 --- a/document/core/exec/instructions.rst +++ b/document/core/exec/instructions.rst @@ -667,7 +667,7 @@ Memory Instructions 17. Execute the instruction :math:`\MEMORYFILL`. -18. Push the value :math:`\vconst_\I32(i+1)` to the stack. +18. Push the value :math:`\vconst_{\I32}(i+1)` to the stack. 19. Push the value :math:`\val` to the stack. @@ -688,7 +688,7 @@ Memory Instructions S; F; (\I32.\CONST~i)~\val~(\I32.\CONST~n)~(\MEMORYFILL) &\stepto& S; F; \begin{array}[t]{@{}l@{}} (\I32.\CONST~i)~\val~(\I32.\CONST~1)~(\MEMORYFILL) \\ - (\vconst_\I32(i+1))~\val~(\I32.\CONST~(n-1))~(\MEMORYFILL) \\ + (\vconst_{\I32}(i+1))~\val~(\I32.\CONST~(n-1))~(\MEMORYFILL) \\ \end{array} \\ \end{array} \\ \qquad @@ -711,11 +711,11 @@ Memory Instructions 5. Let :math:`\X{mem}` be the :ref:`memory instance ` :math:`S.\SMEMS[\X{ma}]`. -6. Assert: due to :ref:`validation `, :math:`F.\AMODULE.\MIDATAS[x]` exists. +6. Assert: due to :ref:`validation `, :math:`F.\AMODULE.\MIDATAS[x]` exists. 7. Let :math:`\X{da}` be the :ref:`data address ` :math:`F.\AMODULE.\MIDATAS[x]`. -8. Assert: due to :ref:`validation `, :math:`S.\SDATA[\X{da}]` exists. +8. Assert: due to :ref:`validation `, :math:`S.\SDATA[\X{da}]` exists. 9. Let :math:`\X{data}^?` be the optional :ref:`data instance ` :math:`S.\SDATA[\X{da}]`. @@ -763,9 +763,9 @@ Memory Instructions 22. Execute the instruction :math:`\MEMORYINIT~x`. -23. Push the value :math:`\vconst_\I32(dst+1)` to the stack. +23. Push the value :math:`\vconst_{\I32}(dst+1)` to the stack. -24. Push the value :math:`\vconst_\I32(src+1)` to the stack. +24. Push the value :math:`\vconst_{\I32}(src+1)` to the stack. 25. Push the value :math:`\I32.\CONST~(cnt-1)` to the stack. @@ -792,7 +792,7 @@ Memory Instructions S; F; (\I32.\CONST~dst)~(\I32.\CONST~src)~(\I32.\CONST~cnt))~(\MEMORYINIT~x) &\stepto& S; F; \begin{array}[t]{@{}l@{}} (\I32.\CONST~dst)~(\I32.\CONST~src)~(\I32.\CONST~1)~(\MEMORYINIT~x) \\ - (\vconst_\I32(dst+1))~(\vconst_\I32(src+1))~(\I32.\CONST~(cnt-1))~(\MEMORYINIT~x) \\ + (\vconst_{\I32}(dst+1))~(\vconst_{\I32}(src+1))~(\I32.\CONST~(cnt-1))~(\MEMORYINIT~x) \\ \end{array} \\ \end{array} \\ \qquad @@ -813,11 +813,11 @@ Memory Instructions 1. Let :math:`F` be the :ref:`current ` :ref:`frame `. -2. Assert: due to :ref:`validation `, :math:`F.\AMODULE.\MIDATAS[x]` exists. +2. Assert: due to :ref:`validation `, :math:`F.\AMODULE.\MIDATAS[x]` exists. 3. Let :math:`a` be the :ref:`data address ` :math:`F.\AMODULE.\MIDATAS[x]`. -4. Assert: due to :ref:`validation `, :math:`S.\SDATA[a]` exists. +4. Assert: due to :ref:`validation `, :math:`S.\SDATA[a]` exists. 5. Let :math:`\X{data}^?` be the optional :ref:`data instance ` :math:`S.\SDATA[a]`. @@ -890,15 +890,15 @@ Memory Instructions d. Execute the instruction :math:`\MEMORYCOPY`. - e. Push the value :math:`\vconst_\I32(dst+1)` to the stack. + e. Push the value :math:`\vconst_{\I32}(dst+1)` to the stack. - f. Push the value :math:`\vconst_\I32(src+1)` to the stack. + f. Push the value :math:`\vconst_{\I32}(src+1)` to the stack. 10. Else: - a. Push the value :math:`\vconst_\I32(dst+cnt-1)` to the stack. + a. Push the value :math:`\vconst_{\I32}(dst+cnt-1)` to the stack. - b. Push the value :math:`\vconst_\I32(src+cnt-1)` to the stack. + b. Push the value :math:`\vconst_{\I32}(src+cnt-1)` to the stack. c. Push the value :math:`\I32.\CONST~1` to the stack. @@ -932,7 +932,7 @@ Memory Instructions S; F; (\I32.\CONST~dst)~(\I32.\CONST~src)~(\I32.\CONST~cnt)~\MEMORYCOPY &\stepto& S; F; \begin{array}[t]{@{}l@{}} (\I32.\CONST~dst)~(\I32.\CONST~src)~(\I32.\CONST~1)~\MEMORYCOPY \\ - (\vconst_\I32(dst+1))~(\vconst_\I32(src+1))~(\I32.\CONST~(cnt-1))~\MEMORYCOPY \\ + (\vconst_{\I32}(dst+1))~(\vconst_{\I32}(src+1))~(\I32.\CONST~(cnt-1))~\MEMORYCOPY \\ \end{array} \\ \end{array} \\ \qquad @@ -1001,15 +1001,15 @@ Table Instructions d. Execute the instruction :math:`\TABLECOPY`. - e. Push the value :math:`\vconst_\I32(dst+1)` to the stack. + e. Push the value :math:`\vconst_{\I32}(dst+1)` to the stack. - f. Push the value :math:`\vconst_\I32(src+1)` to the stack. + f. Push the value :math:`\vconst_{\I32}(src+1)` to the stack. 10. Else: - a. Push the value :math:`\vconst_\I32(dst+cnt-1)` to the stack. + a. Push the value :math:`\vconst_{\I32}(dst+cnt-1)` to the stack. - b. Push the value :math:`\vconst_\I32(src+cnt-1)` to the stack. + b. Push the value :math:`\vconst_{\I32}(src+cnt-1)` to the stack. c. Push the value :math:`\I32.\CONST~1` to the stack. @@ -1039,7 +1039,7 @@ Table Instructions S; F; (\I32.\CONST~dst)~(\I32.\CONST~src)~(\I32.\CONST~cnt)~\TABLECOPY &\stepto& S; F; \begin{array}[t]{@{}l@{}} (\I32.\CONST~dst)~(\I32.\CONST~src)~(\I32.\CONST~1)~\TABLECOPY \\ - (\vconst_\I32(dst+1))~(\vconst_\I32(src+1))~(\I32.\CONST~(cnt-1))~\TABLECOPY \\ + (\vconst_{\I32}(dst+1))~(\vconst_{\I32}(src+1))~(\I32.\CONST~(cnt-1))~\TABLECOPY \\ \end{array} \\ \end{array} \\ \qquad @@ -1072,11 +1072,11 @@ Table Instructions 5. Let :math:`\X{tab}` be the :ref:`table instance ` :math:`S.\STABLES[\X{ta}]`. -6. Assert: due to :ref:`validation `, :math:`F.\AMODULE.\MIELEMS[x]` exists. +6. Assert: due to :ref:`validation `, :math:`F.\AMODULE.\MIELEMS[x]` exists. 7. Let :math:`\X{ea}` be the :ref:`element address ` :math:`F.\AMODULE.\MIELEMS[x]`. -8. Assert: due to :ref:`validation `, :math:`S.\SELEM[\X{ea}]` exists. +8. Assert: due to :ref:`validation `, :math:`S.\SELEM[\X{ea}]` exists. 9. Let :math:`\X{elem}^?` be the optional :ref:`element instance ` :math:`S.\SELEM[\X{ea}]`. @@ -1124,9 +1124,9 @@ Table Instructions 22. Execute the instruction :math:`\TABLEINIT~x`. -23. Push the value :math:`\vconst_\I32(dst+1)` to the stack. +23. Push the value :math:`\vconst_{\I32}(dst+1)` to the stack. -24. Push the value :math:`\vconst_\I32(src+1)` to the stack. +24. Push the value :math:`\vconst_{\I32}(src+1)` to the stack. 25. Push the value :math:`\I32.\CONST~(cnt-1)` to the stack. @@ -1153,7 +1153,7 @@ Table Instructions S; F; (\I32.\CONST~dst)~(\I32.\CONST~src)~(\I32.\CONST~cnt)~(\TABLEINIT~x) &\stepto& S; F; \begin{array}[t]{@{}l@{}} (\I32.\CONST~dst)~(\I32.\CONST~src)~(\I32.\CONST~1)~(\TABLEINIT~x) \\ - (\vconst_\I32(dst+1))~(\vconst_\I32(src+1))~(\I32.\CONST~(cnt-1))~(\TABLEINIT~x) \\ + (\vconst_{\I32}(dst+1))~(\vconst_{\I32}(src+1))~(\I32.\CONST~(cnt-1))~(\TABLEINIT~x) \\ \end{array} \\ \end{array} \\ \qquad @@ -1174,11 +1174,11 @@ Table Instructions 1. Let :math:`F` be the :ref:`current ` :ref:`frame `. -2. Assert: due to :ref:`validation `, :math:`F.\AMODULE.\MIELEMS[x]` exists. +2. Assert: due to :ref:`validation `, :math:`F.\AMODULE.\MIELEMS[x]` exists. 3. Let :math:`a` be the :ref:`element address ` :math:`F.\AMODULE.\MIELEMS[x]`. -4. Assert: due to :ref:`validation `, :math:`S.\SELEM[a]` exists. +4. Assert: due to :ref:`validation `, :math:`S.\SELEM[a]` exists. 5. Let :math:`\X{elem}^?` be the optional :ref:`elem instance ` :math:`S.\SELEM[a]`. diff --git a/document/core/exec/modules.rst b/document/core/exec/modules.rst index ce6eda189c..91ffa3d529 100644 --- a/document/core/exec/modules.rst +++ b/document/core/exec/modules.rst @@ -614,6 +614,8 @@ Moreover, if the dots :math:`\dots` are a sequence :math:`A^n` (as for globals), Instantiation ~~~~~~~~~~~~~ +.. todo:: Adjust for passive segments. + Given a :ref:`store ` :math:`S`, a :ref:`module ` :math:`\module` is instantiated with a list of :ref:`external values ` :math:`\externval^n` supplying the required imports as follows. Instantiation checks that the module is :ref:`valid ` and the provided imports :ref:`match ` the declared types, @@ -665,47 +667,43 @@ It is up to the :ref:`embedder ` to define how such conditions are rep 8. Push the frame :math:`F` to the stack. -9. For each :ref:`element segment ` :math:`\elem_i` in :math:`\module.\MELEM`, do: - - a. Let :math:`\X{eoval}_i` be the result of :ref:`evaluating ` the expression :math:`\elem_i.\EOFFSET`. +9. For each :ref:`element segment ` :math:`\elem_i` in :math:`\module.\MELEM` whose :ref:`mode ` :math:`\elem_i.\EMODE` is of the form :math:`\EACTIVE~\{ \ETABLE~\tableidx_i, \EOFFSET~\X{eoexpr}_i \}`, do: - b. Assert: due to :ref:`validation `, :math:`\X{eoval}_i` is of the form :math:`\I32.\CONST~\X{eo}_i`. + a. Assert: due to :ref:`validation `, :math:`\moduleinst.\MITABLES[\tableidx_i]` exists. - c. Let :math:`\tableidx_i` be the :ref:`table index ` :math:`\elem_i.\ETABLE`. + b. Let :math:`\tableaddr_i` be the :ref:`table address ` :math:`\moduleinst.\MITABLES[\tableidx_i]`. - d. Assert: due to :ref:`validation `, :math:`\moduleinst.\MITABLES[\tableidx_i]` exists. + c. Assert: due to :ref:`validation `, :math:`S'.\STABLES[\tableaddr_i]` exists. - e. Let :math:`\tableaddr_i` be the :ref:`table address ` :math:`\moduleinst.\MITABLES[\tableidx_i]`. + d. Let :math:`\tableinst_i` be the :ref:`table instance ` :math:`S'.\STABLES[\tableaddr_i]`. - f. Assert: due to :ref:`validation `, :math:`S'.\STABLES[\tableaddr_i]` exists. + e. Let :math:`\X{eoval}_i` be the result of :ref:`evaluating ` the expression :math:`\X{eoexpr}_i`. - g. Let :math:`\tableinst_i` be the :ref:`table instance ` :math:`S'.\STABLES[\tableaddr_i]`. + f. Assert: due to :ref:`validation `, :math:`\X{eoval}_i` is of the form :math:`\I32.\CONST~\X{eo}_i`. - h. Let :math:`\X{eend}_i` be :math:`\X{eo}_i` plus the length of :math:`\elem_i.\EINIT`. + g. Let :math:`\X{eend}_i` be :math:`\X{eo}_i` plus the length of :math:`\elem_i.\EINIT`. - i. If :math:`\X{eend}_i` is larger than the length of :math:`\tableinst_i.\TIELEM`, then: + h. If :math:`\X{eend}_i` is larger than the length of :math:`\tableinst_i.\TIELEM`, then: i. Fail. -10. For each :ref:`data segment ` :math:`\data_i` in :math:`\module.\MDATA`, do: - - a. Let :math:`\X{doval}_i` be the result of :ref:`evaluating ` the expression :math:`\data_i.\DOFFSET`. +10. For each :ref:`data segment ` :math:`\data_i` in :math:`\module.\MDATA` whose :ref:`mode ` :math:`\data_i.\DMODE` is of the form :math:`\DACTIVE~\{ \DMEM~\memidx_i, \DOFFSET~\X{doexpr}_i \}`, do: - b. Assert: due to :ref:`validation `, :math:`\X{doval}_i` is of the form :math:`\I32.\CONST~\X{do}_i`. + a. Assert: due to :ref:`validation `, :math:`\moduleinst.\MIMEMS[\memidx_i]` exists. - c. Let :math:`\memidx_i` be the :ref:`memory index ` :math:`\data_i.\DMEM`. + b. Let :math:`\memaddr_i` be the :ref:`memory address ` :math:`\moduleinst.\MIMEMS[\memidx_i]`. - d. Assert: due to :ref:`validation `, :math:`\moduleinst.\MIMEMS[\memidx_i]` exists. + c. Assert: due to :ref:`validation `, :math:`S'.\SMEMS[\memaddr_i]` exists. - e. Let :math:`\memaddr_i` be the :ref:`memory address ` :math:`\moduleinst.\MIMEMS[\memidx_i]`. + d. Let :math:`\meminst_i` be the :ref:`memory instance ` :math:`S'.\SMEMS[\memaddr_i]`. - f. Assert: due to :ref:`validation `, :math:`S'.\SMEMS[\memaddr_i]` exists. + e. Let :math:`\X{doval}_i` be the result of :ref:`evaluating ` the expression :math:`\data_i.\DOFFSET`. - g. Let :math:`\meminst_i` be the :ref:`memory instance ` :math:`S'.\SMEMS[\memaddr_i]`. + f. Assert: due to :ref:`validation `, :math:`\X{doval}_i` is of the form :math:`\I32.\CONST~\X{do}_i`. - h. Let :math:`\X{dend}_i` be :math:`\X{do}_i` plus the length of :math:`\data_i.\DINIT`. + g. Let :math:`\X{dend}_i` be :math:`\X{do}_i` plus the length of :math:`\data_i.\DINIT`. - i. If :math:`\X{dend}_i` is larger than the length of :math:`\meminst_i.\MIDATA`, then: + h. If :math:`\X{dend}_i` is larger than the length of :math:`\meminst_i.\MIDATA`, then: i. Fail. @@ -713,7 +711,7 @@ It is up to the :ref:`embedder ` to define how such conditions are rep 12. Pop the frame from the stack. -13. For each :ref:`element segment ` :math:`\elem_i` in :math:`\module.\MELEM`, do: +13. For each :ref:`element segment ` :math:`\elem_i` in :math:`\module.\MELEM` whose :ref:`mode ` :math:`\elem_i.\EMODE` is of the form :math:`\EACTIVE~\{ \ETABLE~\tableidx_i, \EOFFSET~\X{eoexpr}_i \}`, do: a. For each :ref:`function index ` :math:`\funcidx_{ij}` in :math:`\elem_i.\EINIT` (starting with :math:`j = 0`), do: @@ -723,7 +721,7 @@ It is up to the :ref:`embedder ` to define how such conditions are rep iii. Replace :math:`\tableinst_i.\TIELEM[\X{eo}_i + j]` with :math:`\funcaddr_{ij}`. -14. For each :ref:`data segment ` :math:`\data_i` in :math:`\module.\MDATA`, do: +14. For each :ref:`data segment ` :math:`\data_i` in :math:`\module.\MDATA` whose :ref:`mode ` :math:`\data_i.\DMODE` is of the form :math:`\DACTIVE~\{ \DMEM~\memidx_i, \DOFFSET~\X{doexpr}_i \}`, do: a. For each :ref:`byte ` :math:`b_{ij}` in :math:`\data_i.\DINIT` (starting with :math:`j = 0`), do: diff --git a/document/core/exec/runtime.rst b/document/core/exec/runtime.rst index 346123327c..0b66c091da 100644 --- a/document/core/exec/runtime.rst +++ b/document/core/exec/runtime.rst @@ -314,7 +314,7 @@ Element Instances ~~~~~~~~~~~~~~~~~ An *element instance* is the runtime representation of an :ref:`element segment `. -Like table instances, an element instance holds a vector of function elements. +It holds a vector of function elements. .. math:: \begin{array}{llll} diff --git a/document/core/syntax/modules.rst b/document/core/syntax/modules.rst index 2d1775cb1d..8f2037ec0f 100644 --- a/document/core/syntax/modules.rst +++ b/document/core/syntax/modules.rst @@ -247,6 +247,7 @@ starting with the smallest index not referencing a global :ref:`import ` of elements. -Element segments can be :ref:`active ` or :ref:`passive `. An active element segment copies its elements into a table during :ref:`instantiation `. A passive element segment's elements can be copied using the |TABLEINIT| instruction. +The |MELEM| component of a module defines a vector of element segments. +Each element segment defines an :ref:`element type ` and a corresponding list of :ref:`element expressions `. -The |MELEM| component of a module defines a vector of element segments. Each active element segment defines the |ETABLE| and the starting |EOFFSET| in that table to initialize. Each passive element segment defines its element type and contents. +Element segments have a mode that identifies them as either :ref:`passive ` or :ref:`active `. +A passive element segment's elements can be copied to a table using the |TABLEINIT| instruction. +An active element segment copies its elements into a table during :ref:`instantiation `, as specified by a :ref:`table index ` and a :ref:`constant ` :ref:`expression ` defining an offset into that table. .. math:: \begin{array}{llll} \production{element segment} & \elem &::=& - \{ \ETABLE~\tableidx, \EOFFSET~\expr, \ETYPE~\elemtype, \EINIT~\vec(\elemexpr) \} \\&&|& - \{ \ETYPE~\elemtype, \EINIT~\vec(\elemexpr) \} \\ + \{ \ETYPE~\elemtype, \EINIT~\vec(\elemexpr), \EMODE~\elemmode \} \\ + \production{element segment mode} & \elemmode &::=& + \EPASSIVE \\&&|& + \EACTIVE~\{ \ETABLE~\tableidx, \EOFFSET~\expr \} \\ \production{elemexpr} & \elemexpr &::=& \REFNULL~\END \\&&|& (\REFFUNC~\funcidx)~\END \\ @@ -282,25 +288,28 @@ Element segments are referenced through :ref:`element indices `. single: memory; data single: data; segment .. _syntax-data: +.. _syntax-datamode: Data Segments ~~~~~~~~~~~~~ The initial contents of a :ref:`memory ` are zero bytes. *Data segments* can be used to initialize a range of memory from a static :ref:`vector ` of :ref:`bytes `. -Like element segments, data segments can be :ref:`active ` or :ref:`passive `. An active data segment copies its contents into a table during :ref:`instantiation `. A passive data segment's contents can be copied using the |MEMORYINIT| instruction. +The |MDATA| component of a module defines a vector of data segments. -The |MDATA| component of a module defines a vector of data segments. Each active data segment defines the memory to initialize, and the starting |DOFFSET| in that memory to initialize. Each passive data segment only defines its contents. +Like element segments, data segments have a mode that identifies them as either :ref:`passive ` or :ref:`active `. +A passive data segment's contents can be copied into a memory using the |MEMORYINIT| instruction. +An active data segment copies its contents into a memory during :ref:`instantiation `, as specified by a :ref:`memory index ` and a :ref:`constant ` :ref:`expression ` defining an offset into that memory. .. math:: \begin{array}{llll} \production{data segment} & \data &::=& - \{ \DMEM~\memidx, \DOFFSET~\expr, \DINIT~\vec(\byte) \} \\&&|& - \{ \DINIT~\vec(\byte) \} \\ + \{ \DINIT~\vec(\byte), \DMODE~\datamode \} \\ + \production{data segment mode} & \datamode &::=& + \DPASSIVE \\&&|& + \DACTIVE~\{ \DMEM~\memidx, \DOFFSET~\expr \} \\ \end{array} -The |DOFFSET| is given by a :ref:`constant ` :ref:`expression `. - Data segments are referenced through :ref:`data indices `. .. note:: diff --git a/document/core/syntax/types.rst b/document/core/syntax/types.rst index ef0f658938..9f045ba478 100644 --- a/document/core/syntax/types.rst +++ b/document/core/syntax/types.rst @@ -190,13 +190,13 @@ Global Types Segment Types ~~~~~~~~~~~~~ -*Segment types* classify :ref:`data segments ` and :ref:`element segments `, which can either be *active* or *passive*. +*Segment types* classify :ref:`data segments ` and :ref:`element segments `, which can either be *passive* or *active*. .. math:: \begin{array}{llll} \production{segment type} & \segtype &::=& - \SACTIVE ~|~ - \SPASSIVE \\ + \SPASSIVE ~|~ + \SACTIVE \\ \end{array} diff --git a/document/core/text/modules.rst b/document/core/text/modules.rst index e937abaf13..114d6b1787 100644 --- a/document/core/text/modules.rst +++ b/document/core/text/modules.rst @@ -286,9 +286,9 @@ An :ref:`element segment ` can be given inline with a table definitio .. math:: \begin{array}{llclll} \production{module field} & - \text{(}~\text{table}~~\Tid^?~~\Telemtype~~\text{(}~\text{elem}~~x^n{:}\Tvec(\Tfuncidx)~\text{)}~~\text{)} \quad\equiv \\ & \qquad + \text{(}~\text{table}~~\Tid^?~~\Telemtype~~\text{(}~\text{elem}~~\Telemlist~\text{)} \quad\equiv \\ & \qquad \text{(}~\text{table}~~\Tid'~~n~~n~~\Telemtype~\text{)}~~ - \text{(}~\text{elem}~~\Tid'~~\text{(}~\text{i32.const}~~\text{0}~\text{)}~~\Tvec(\Tfuncidx)~\text{)} + \text{(}~\text{elem}~~\text{(}~\text{table}~~\Tid'~\text{)}~~\text{(}~\text{i32.const}~~\text{0}~\text{)}~~\Telemlist~\text{)} \\ & \qquad\qquad (\iff \Tid' = \Tid^? \neq \epsilon \vee \Tid' \idfresh) \\ \end{array} @@ -357,7 +357,7 @@ A :ref:`data segment ` can be given inline with a memory definition, \production{module field} & \text{(}~\text{memory}~~\Tid^?~~\text{(}~\text{data}~~b^n{:}\Tdatastring~\text{)}~~\text{)} \quad\equiv \\ & \qquad \text{(}~\text{memory}~~\Tid'~~m~~m~\text{)}~~ - \text{(}~\text{data}~~\Tid'~~\text{(}~\text{i32.const}~~\text{0}~\text{)}~~\Tdatastring~\text{)} + \text{(}~\text{data}~~\text{(}~\text{memory}~~\Tid'~\text{)}~~\text{(}~\text{i32.const}~~\text{0}~\text{)}~~\Tdatastring~\text{)} \\ & \qquad\qquad (\iff \Tid' = \Tid^? \neq \epsilon \vee \Tid' \idfresh, m = \F{ceil}(n / 64\F{Ki})) \\ \end{array} @@ -484,6 +484,8 @@ A :ref:`start function ` is defined in terms of its index. single: table; element single: element; segment .. _text-elem: +.. _text-elemlist: +.. _text-elemexpr: Element Segments ~~~~~~~~~~~~~~~~ @@ -493,13 +495,15 @@ Element segments allow for an optional :ref:`table index ` to ide .. math:: \begin{array}{llclll} \production{element segment} & \Telem_I &::=& - \text{(}~\text{elem}~~\Tid^?~~\text{(}~\text{table}~~x{:}\Ttableidx_I ~\text{)}~~\text{(}~\text{offset}~~e{:}\Texpr_I~\text{)}~~(et, y^\ast){:}\Telemlist~\text{)} \\ &&& \qquad - \Rightarrow\quad \{ \ETABLE~x, \EOFFSET~e, \ETYPE~et, \EINIT~y^\ast \} \\ &&|& \text{(}~\text{elem}~~\Tid^?~~(et, y^\ast){:}\Telemlist~\text{)} \\ &&& \qquad - \Rightarrow\quad \{\ETYPE~et,\EINIT~y^\ast \} \\ - \production{elemlist} & \Telemlist &::=& - \text{func}~~y^\ast{:}\Tvec(\Tfuncidx_I) \qquad\Rightarrow\quad ( \ETYPE~\FUNCREF, \EINIT~y^\ast ) \\ &&|& - et{:}\Telemtype~~y^\ast{:}\Tvec(\Texpr_I) \qquad\Rightarrow\quad ( \ETYPE~et, \EINIT~y^\ast ) \\ + \Rightarrow\quad \{ \ETYPE~et, \EINIT~y^\ast, \EMODE~\EPASSIVE \} \\ &&|& + \text{(}~\text{elem}~~\Tid^?~~\text{(}~\text{table}~~x{:}\Ttableidx_I ~\text{)}~~\text{(}~\text{offset}~~e{:}\Texpr_I~\text{)}~~(et, y^\ast){:}\Telemlist~\text{)} \\ &&& \qquad + \Rightarrow\quad \{ \ETYPE~et, \EINIT~y^\ast, \EMODE~\EACTIVE~\{ \ETABLE~x, \EOFFSET~e \} \} \\ + \production{element list} & \Telemlist &::=& + et{:}\Telemtype~~y^\ast{:}\Tvec(\Telemexpr_I) \qquad\Rightarrow\quad ( \ETYPE~et, \EINIT~y^\ast ) \\ + \production{element expression} & \Telemexpr &::=& + \text{(}~\text{ref.null}~\text{)} \\ &&|& + \text{(}~\text{ref.func}~~\Tfuncidx_I~\text{)} \\ \end{array} .. note:: @@ -510,7 +514,7 @@ Element segments allow for an optional :ref:`table index ` to ide Abbreviations ............. -As an abbreviation, a single instruction may occur in place of the offset: +As an abbreviation, a single instruction may occur in place of the offset of an active element segment: .. math:: \begin{array}{llcll} @@ -519,14 +523,27 @@ As an abbreviation, a single instruction may occur in place of the offset: \text{(}~\text{offset}~~\Tinstr~\text{)} \end{array} -Also, the table index can be omitted, defaulting to :math:`\T{0}`. If the table index is omitted, also the :math:`\text{func}` keyword can be omitted. +Also, the element list may be written as just a sequence of :ref:`function indices `: .. math:: - \begin{array}{llclll} + \begin{array}{llcll} + \production{element list} & + \text{func}~~\Tvec(\Tfuncidx_I) &\equiv& + \text{funcref}~~\Tvec(\text{(}~\text{ref.func}~~\Tfuncidx_I~\text{)}) + \end{array} + +Also, the table index can be omitted, defaulting to :math:`\T{0}`. +Furthermore, for backwards compatibility with earlier versions of WebAssembly, if the table index is omitted, the :math:`\text{func}` keyword can be omitted as well. + +.. math:: + \begin{array}{ll} \production{element segment} & - \text{(}~\text{elem}~~\text{(}~\text{offset}~~\Texpr_I~\text{)}~~\dots~\text{)} - &\equiv& - \text{(}~\text{elem}~~\text{(}~\text{table}~~\text{0}~\text{)}~~\text{(}~\text{offset}~~\Texpr_I~\text{)}~~\dots~\text{)} + \text{(}~\text{elem}~~\Tid^?~~\text{(}~\text{offset}~~\Texpr_I~\text{)}~~\Telemlist~\text{)} + \quad\equiv \\& + \text{(}~\text{elem}~~\Tid^?~~\text{(}~\text{table}~~\text{0}~\text{)}~~\text{(}~\text{offset}~~\Texpr_I~\text{)}~~\Telemlist~\text{)} \\ + \text{(}~\text{elem}~~\Tid^?~~\text{(}~\text{offset}~~\Texpr_I~\text{)}~~\Tvec(\Tfuncidx_I)~\text{)} + \quad\equiv \\& + \text{(}~\text{elem}~~\Tid^?~~\text{(}~\text{table}~~\text{0}~\text{)}~~\text{(}~\text{offset}~~\Texpr_I~\text{)}~~\text{func}~~\Tvec(\Tfuncidx_I)~\text{)} \end{array} As another abbreviation, element segments may also be specified inline with :ref:`table ` definitions; see the respective section. @@ -548,10 +565,10 @@ The data is written as a :ref:`string `, which may be split up into .. math:: \begin{array}{llclll} \production{data segment} & \Tdata_I &::=& - \text{(}~\text{data}~~\Tid^?~~x{:}\Tmemidx_I~~\text{(}~\text{offset}~~e{:}\Texpr_I~\text{)}~~b^\ast{:}\Tdatastring~\text{)} \\ &&& \qquad - \Rightarrow\quad \{ \DMEM~x', \DOFFSET~e, \DINIT~b^\ast \} \\ &&|& - \text{(}~\text{data}~~\Tid^?~~\text{passive}~~b^\ast{:}\Tdatastring~\text{)} \\ &&& \qquad - \Rightarrow\quad \{ \DINIT~b^\ast \} \\ + \text{(}~\text{data}~~\Tid^?~~b^\ast{:}\Tdatastring~\text{)} \\ &&& \qquad + \Rightarrow\quad \{ \DINIT~b^\ast, \DMODE~\DPASSIVE \} \\ &&|& + \text{(}~\text{data}~~\Tid^?~~\text{(}~\text{memory}~~x{:}\Tmemidx_I ~\text{)}~~\text{(}~\text{offset}~~e{:}\Texpr_I~\text{)}~~b^\ast{:}\Tdatastring~\text{)} \\ &&& \qquad + \Rightarrow\quad \{ \DINIT~b^\ast, \DMODE~\DACTIVE~\{ \DMEM~x', \DOFFSET~e \} \} \\ \production{data string} & \Tdatastring &::=& (b^\ast{:}\Tstring)^\ast \quad\Rightarrow\quad \concat((b^\ast)^\ast) \\ \end{array} @@ -564,7 +581,7 @@ The data is written as a :ref:`string `, which may be split up into Abbreviations ............. -As an abbreviation, a single instruction may occur in place of the offset: +As an abbreviation, a single instruction may occur in place of the offset of an active data segment: .. math:: \begin{array}{llcll} @@ -578,9 +595,9 @@ Also, the memory index can be omitted, defaulting to :math:`\T{0}`. .. math:: \begin{array}{llclll} \production{data segment} & - \text{(}~\text{data}~~\text{(}~\text{offset}~~\Texpr_I~\text{)}~~\dots~\text{)} + \text{(}~\text{data}~~\Tid^?~~\text{(}~\text{offset}~~\Texpr_I~\text{)}~~\dots~\text{)} &\equiv& - \text{(}~\text{data}~~0~~\text{(}~\text{offset}~~\Texpr_I~\text{)}~~\dots~\text{)} + \text{(}~\text{data}~~\Tid^?~~\text{(}~\text{memory}~~\text{0}~\text{)}~~\text{(}~\text{offset}~~\Texpr_I~\text{)}~~\dots~\text{)} \end{array} As another abbreviation, data segments may also be specified inline with :ref:`memory ` definitions; see the respective section. diff --git a/document/core/util/macros.def b/document/core/util/macros.def index a2dc1e5787..5756c05ad6 100644 --- a/document/core/util/macros.def +++ b/document/core/util/macros.def @@ -263,17 +263,23 @@ .. |GTYPE| mathdef:: \xref{syntax/modules}{syntax-global}{\K{type}} .. |GINIT| mathdef:: \xref{syntax/modules}{syntax-global}{\K{init}} +.. |ETYPE| mathdef:: \xref{syntax/modules}{syntax-elem}{\K{type}} +.. |EINIT| mathdef:: \xref{syntax/modules}{syntax-elem}{\K{init}} +.. |EMODE| mathdef:: \xref{syntax/modules}{syntax-elem}{\K{mode}} +.. |EPASSIVE| mathdef:: \xref{syntax/modules}{syntax-elem}{\K{passive}} +.. |EACTIVE| mathdef:: \xref{syntax/modules}{syntax-elem}{\K{active}} .. |ETABLE| mathdef:: \xref{syntax/modules}{syntax-elem}{\K{table}} .. |EOFFSET| mathdef:: \xref{syntax/modules}{syntax-elem}{\K{offset}} -.. |EINIT| mathdef:: \xref{syntax/modules}{syntax-elem}{\K{init}} -.. |ETYPE| mathdef:: \xref{syntax/modules}{syntax-elem}{\K{type}} .. |REFNULL| mathdef:: \xref{syntax/modules}{syntax-elemexpr}{\K{ref.null}} .. |REFFUNC| mathdef:: \xref{syntax/modules}{syntax-elemexpr}{\K{ref.func}} -.. |DMEM| mathdef:: \xref{syntax/modules}{syntax-data}{\K{data}} -.. |DOFFSET| mathdef:: \xref{syntax/modules}{syntax-data}{\K{offset}} .. |DINIT| mathdef:: \xref{syntax/modules}{syntax-data}{\K{init}} +.. |DMODE| mathdef:: \xref{syntax/modules}{syntax-data}{\K{mode}} +.. |DPASSIVE| mathdef:: \xref{syntax/modules}{syntax-data}{\K{passive}} +.. |DACTIVE| mathdef:: \xref{syntax/modules}{syntax-data}{\K{active}} +.. |DMEM| mathdef:: \xref{syntax/modules}{syntax-data}{\K{memory}} +.. |DOFFSET| mathdef:: \xref{syntax/modules}{syntax-data}{\K{offset}} .. |SFUNC| mathdef:: \xref{syntax/modules}{syntax-start}{\K{func}} @@ -306,8 +312,10 @@ .. |importdesc| mathdef:: \xref{syntax/modules}{syntax-importdesc}{\X{importdesc}} .. |exportdesc| mathdef:: \xref{syntax/modules}{syntax-exportdesc}{\X{exportdesc}} .. |elem| mathdef:: \xref{syntax/modules}{syntax-elem}{\X{elem}} +.. |elemmode| mathdef:: \xref{syntax/modules}{syntax-elemmode}{\X{elemmode}} .. |elemexpr| mathdef:: \xref{syntax/modules}{syntax-elemexpr}{\X{elemexpr}} .. |data| mathdef:: \xref{syntax/modules}{syntax-data}{\X{data}} +.. |datamode| mathdef:: \xref{syntax/modules}{syntax-datamode}{\X{datamode}} .. |start| mathdef:: \xref{syntax/modules}{syntax-start}{\X{start}} @@ -534,6 +542,7 @@ .. |Bimportdesc| mathdef:: \xref{binary/modules}{binary-importdesc}{\B{importdesc}} .. |Bexportdesc| mathdef:: \xref{binary/modules}{binary-exportdesc}{\B{exportdesc}} .. |Belem| mathdef:: \xref{binary/modules}{binary-elem}{\B{elem}} +.. |Belemkind| mathdef:: \xref{binary/modules}{binary-elemexpr}{\B{elemkind}} .. |Belemexpr| mathdef:: \xref{binary/modules}{binary-elemexpr}{\B{elemexpr}} .. |Bcode| mathdef:: \xref{binary/modules}{binary-code}{\B{code}} .. |Blocal| mathdef:: \xref{binary/modules}{binary-local}{\B{local}} @@ -689,6 +698,8 @@ .. |Timportdesc| mathdef:: \xref{text/modules}{text-importdesc}{\T{importdesc}} .. |Texportdesc| mathdef:: \xref{text/modules}{text-exportdesc}{\T{exportdesc}} .. |Telem| mathdef:: \xref{text/modules}{text-elem}{\T{elem}} +.. |Telemlist| mathdef:: \xref{text/modules}{text-elemlist}{\T{elemlist}} +.. |Telemexpr| mathdef:: \xref{text/modules}{text-elemexpr}{\X{elemexpr}} .. |Tcode| mathdef:: \xref{text/modules}{text-code}{\T{code}} .. |Tlocal| mathdef:: \xref{text/modules}{text-local}{\T{local}} .. |Tlocals| mathdef:: \xref{text/modules}{text-local}{\T{locals}} @@ -702,7 +713,6 @@ .. |Tmemarg| mathdef:: \xref{text/instructions}{text-memarg}{\T{memarg}} .. |Talign| mathdef:: \xref{text/instructions}{text-memarg}{\T{align}} .. |Toffset| mathdef:: \xref{text/instructions}{text-memarg}{\T{offset}} -.. |Telemlist| mathdef:: \xref{text/instructions}{text-memarg}{\T{elemlist}} .. |Tlabel| mathdef:: \xref{text/instructions}{text-label}{\T{label}} .. |Tinstr| mathdef:: \xref{text/instructions}{text-instr}{\T{instr}} @@ -780,8 +790,10 @@ .. |vdashmem| mathdef:: \xref{valid/modules}{valid-mem}{\vdash} .. |vdashglobal| mathdef:: \xref{valid/modules}{valid-global}{\vdash} .. |vdashelem| mathdef:: \xref{valid/modules}{valid-elem}{\vdash} +.. |vdashelemmode| mathdef:: \xref{valid/modules}{valid-elemmode}{\vdash} .. |vdashelemexpr| mathdef:: \xref{valid/modules}{valid-elemexpr}{\vdash} .. |vdashdata| mathdef:: \xref{valid/modules}{valid-data}{\vdash} +.. |vdashdatamode| mathdef:: \xref{valid/modules}{valid-datamode}{\vdash} .. |vdashstart| mathdef:: \xref{valid/modules}{valid-start}{\vdash} .. |vdashexport| mathdef:: \xref{valid/modules}{valid-export}{\vdash} .. |vdashexportdesc| mathdef:: \xref{valid/modules}{valid-exportdesc}{\vdash} diff --git a/document/core/valid/modules.rst b/document/core/valid/modules.rst index edb0e3f13f..408ae81361 100644 --- a/document/core/valid/modules.rst +++ b/document/core/valid/modules.rst @@ -145,65 +145,27 @@ Globals :math:`\global` are classified by :ref:`global types Element Segments ~~~~~~~~~~~~~~~~ -Element segments :math:`\elem` are classified by :ref:`segment types `. +Element segments :math:`\elem` are classified by :ref:`segment types `, as determined by their :ref:`mode `. -:math:`\{ \ETABLE~x, \EOFFSET~\expr, \ETYPE~et, \EINIT~e^\ast \}` -................................................................. - -* The table :math:`C.\CTABLES[x]` must be defined in the context. - -* Let :math:`\limits~\elemtype` be the :ref:`table type ` :math:`C.\CTABLES[x]`. - -* The :ref:`element type ` :math:`\elemtype` must be |FUNCREF|. - -* The expression :math:`\expr` must be :ref:`valid ` with :ref:`result type ` :math:`[\I32]`. - -* The expression :math:`\expr` must be :ref:`constant `. - -* The :ref:`element type ` :math:`et` must be |FUNCREF|. +:math:`\{ \ETYPE~et, \EINIT~e^\ast, \EMODE~\elemmode \}` +........................................................ * For each :math:`e_i` in :math:`e^\ast`, * The element expression :math:`e_i` must be :ref:`valid `. -* Then the element segment is valid with type |SACTIVE|. - - -.. math:: - \frac{ - C.\CTABLES[x] = \limits~\FUNCREF - \qquad - C \vdashexpr \expr : [\I32] - \qquad - C \vdashexprconst \expr \const - \qquad - et = \FUNCREF - \qquad - (C \vdashelemexpr e \ok)^\ast - }{ - C \vdashelem \{ \ETABLE~x, \EOFFSET~\expr, \ETYPE~et, \EINIT~e^\ast \} : \SACTIVE - } - - -:math:`\{ \ETYPE~et, \EINIT~e^\ast \}` -...................................... - -* The :ref:`element type ` :math:`et` must be |FUNCREF|. - -* For each :math:`e_i` in :math:`e^\ast`, - - * The element expression :math:`e_i` must be :ref:`valid `. +* The element mode :math:`\elemmode` must valid with type :math:`\segtype`. -* Then the element segment is valid with type |SPASSIVE|. +* Then the element segment is valid with type :math:`\segtype`. .. math:: \frac{ - et = \FUNCREF - \qquad (C \vdashelemexpr e \ok)^\ast + \qquad + C; \X{et} \vdashelemmode \elemmode : \segtype }{ - C \vdashelem \{ \ETYPE~et, \EINIT~e^\ast \} : \SPASSIVE + C \vdashelem \{ \ETYPE~et, \EINIT~e^\ast, \EMODE~\elemmode \} : \segtype } @@ -231,6 +193,49 @@ Element segments :math:`\elem` are classified by :ref:`segment types ` :math:`C.\CTABLES[x]`. + +* The :ref:`element type ` :math:`\X{et}` of the segment must match :math:`\elemtype`. + +* The expression :math:`\expr` must be :ref:`valid ` with :ref:`result type ` :math:`[\I32]`. + +* The expression :math:`\expr` must be :ref:`constant `. + +* Then the element mode is valid with type |SACTIVE|. + +.. math:: + \frac{ + C.\CTABLES[x] = \limits~\elemtype + \qquad + \X{et} = \elemtype + \qquad + C \vdashexpr \expr : [\I32] + \qquad + C \vdashexprconst \expr \const + }{ + C; \X{et} \vdashelemmode \EACTIVE~\{ \ETABLE~x, \EOFFSET~\expr \} : \SACTIVE + } + + .. index:: data, memory, memory index, expression, byte pair: validation; data single: abstract syntax; data @@ -241,42 +246,57 @@ Element segments :math:`\elem` are classified by :ref:`segment types `. +Data segments :math:`\data` are classified by :ref:`segment types `, as determined by their :ref:`mode `. -:math:`\{ \DMEM~x, \DOFFSET~\expr, \DINIT~b^\ast \}` +:math:`\{ \DINIT~b^\ast, \DMODE~\datamode \}` .................................................... -* The memory :math:`C.\CMEMS[x]` must be defined in the context. +* The data mode :math:`\datamode` must valid with type :math:`\segtype`. -* The expression :math:`\expr` must be :ref:`valid ` with :ref:`result type ` :math:`[\I32]`. +* Then the data segment is valid with type :math:`\segtype`. + +.. math:: + \frac{ + C \vdashdatamode \datamode : \segtype + }{ + C \vdashdata \{ \DINIT~b^\ast, \DMODE~\datamode \} : \segtype + } -* The expression :math:`\expr` must be :ref:`constant `. -* Then the data segment is valid with type |SACTIVE|. +.. _valid-datamode: +:math:`\DPASSIVE` +................. + +* The data mode is valid with type |SPASSIVE|. .. math:: \frac{ - C.\CMEMS[x] = \limits - \qquad - C \vdashexpr \expr : [\I32] - \qquad - C \vdashexprconst \expr \const }{ - C \vdashdata \{ \DMEM~x, \DOFFSET~\expr, \DINIT~b^\ast \} : \SACTIVE + C \vdashdatamode \DPASSIVE : \SPASSIVE } -:math:`\{ \DINIT~b^\ast \}` -.................................................... +:math:`\DACTIVE~\{ \DMEM~x, \DOFFSET~\expr \}` +.............................................. + +* The memory :math:`C.\CMEMS[x]` must be defined in the context. -* The data segment is valid. +* The expression :math:`\expr` must be :ref:`valid ` with :ref:`result type ` :math:`[\I32]`. + +* The expression :math:`\expr` must be :ref:`constant `. +* Then the data mode is valid with type |SACTIVE|. .. math:: \frac{ + C.\CMEMS[x] = \limits + \qquad + C \vdashexpr \expr : [\I32] + \qquad + C \vdashexprconst \expr \const }{ - C \vdashdata \{ \DINIT~b^\ast \} : \SPASSIVE + C \vdashelemmode \EACTIVE~\{ \DMEM~x, \DOFFSET~\expr \} : \SACTIVE } diff --git a/interpreter/binary/decode.ml b/interpreter/binary/decode.ml index ba1315d0ba..69596b6cc1 100644 --- a/interpreter/binary/decode.ml +++ b/interpreter/binary/decode.ml @@ -535,11 +535,6 @@ let func_section s = (* Table section *) -let elem_kind s = - match vs7 s with - | 0x00 -> FuncRefType - | _ -> error s (pos s - 1) "invalid elem kind" - let table s = let ttype = table_type s in {ttype} @@ -562,8 +557,8 @@ let memory_section s = let global s = let gtype = global_type s in - let value = const s in - {gtype; value} + let ginit = const s in + {gtype; ginit} let global_section s = section `GlobalSection (vec (at global)) [] s @@ -618,9 +613,27 @@ let code_section s = (* Element section *) +let passive s = + Passive + +let active s = + let index = at var s in + let offset = const s in + Active {index; offset} + +let active_zero s = + let index = Source.(0l @@ Source.no_region) in + let offset = const s in + Active {index; offset} + let elem_index s = ref_func (at var s) +let elem_kind s = + match u8 s with + | 0x00 -> FuncRefType + | _ -> error s (pos s - 1) "invalid element kind" + let elem_expr s = match u8 s with | 0xd0 -> end_ s; ref_null @@ -628,73 +641,64 @@ let elem_expr s = let x = at var s in end_ s; ref_func x - | _ -> error s (pos s - 1) "invalid elem" - -let elem_indices s = - vec (at elem_index) s - -let elem_refs s = - vec (at elem_expr) s + | _ -> error s (pos s - 1) "invalid element expression" -let table_segment s = - match u8 s with - | 0x00 -> - let index = Source.(0l @@ Source.no_region) in - let offset = const s in - let init = elem_indices s in - ActiveElem {index; offset; etype = FuncRefType; init} - | 0x01 -> +let elem s = + match vu32 s with + | 0x00l -> + let emode = at active_zero s in + let einit = vec (at elem_index) s in + {etype = FuncRefType; einit; emode} + | 0x01l -> + let emode = at passive s in let etype = elem_kind s in - let data = elem_indices s in - PassiveElem {etype; data} - | 0x02 -> - let index = at var s in - let offset = const s in + let einit = vec (at elem_index) s in + {etype; einit; emode} + | 0x02l -> + let emode = at active s in let etype = elem_kind s in - let init = elem_indices s in - ActiveElem {index; offset; etype; init} - | 0x04 -> - let index = Source.(0l @@ Source.no_region) in - let offset = const s in - let init = elem_refs s in - ActiveElem {index; offset; etype = FuncRefType; init} - | 0x05 -> + let einit = vec (at elem_index) s in + {etype; einit; emode} + | 0x04l -> + let emode = at active_zero s in + let einit = vec (at elem_expr) s in + {etype = FuncRefType; einit; emode} + | 0x05l -> + let emode = at passive s in let etype = elem_type s in - let data = elem_refs s in - PassiveElem {etype; data} - | 0x06 -> - let index = at var s in - let offset = const s in + let einit = vec (at elem_expr) s in + {etype; einit; emode} + | 0x06l -> + let emode = at active s in let etype = elem_type s in - let init = elem_refs s in - ActiveElem {index; offset; etype; init} - | _ -> error s (pos s - 1) "invalid table segment kind" + let einit = vec (at elem_expr) s in + {etype; einit; emode} + | _ -> error s (pos s - 1) "invalid elements segment kind" let elem_section s = - section `ElemSection (vec (at table_segment)) [] s + section `ElemSection (vec (at elem)) [] s (* Data section *) -let memory_segment s = +let data s = match vu32 s with - | 0l -> - let index = Source.(0l @@ Source.no_region) in - let offset = const s in - let init = string s in - ActiveData {index; offset; init} - | 1l -> - let data = string s in - PassiveData {data} - | 2l -> - let index = at var s in - let offset = const s in - let init = string s in - ActiveData {index; offset; init} - | _ -> error s (pos s - 1) "invalid memory segment kind" + | 0x00l -> + let dmode = at active_zero s in + let dinit = string s in + {dinit; dmode} + | 0x01l -> + let dmode = at passive s in + let dinit = string s in + {dinit; dmode} + | 0x02l -> + let dmode = at active s in + let dinit = string s in + {dinit; dmode} + | _ -> error s (pos s - 1) "invalid data segment kind" let data_section s = - section `DataSection (vec (at memory_segment)) [] s + section `DataSection (vec (at data)) [] s (* DataCount section *) diff --git a/interpreter/binary/encode.ml b/interpreter/binary/encode.ml index 7bc5095120..1be8b07f98 100644 --- a/interpreter/binary/encode.ml +++ b/interpreter/binary/encode.ml @@ -430,8 +430,8 @@ let encode m = (* Global section *) let global g = - let {gtype; value} = g.it in - global_type gtype; const value + let {gtype; ginit} = g.it in + global_type gtype; const ginit let global_section gs = section 6 (vec global) gs (gs <> []) @@ -477,53 +477,60 @@ let encode m = section 10 (vec code) fs (fs <> []) (* Element section *) - let elem_expr el = - match el.it with + let elem_kind = function + | FuncRefType -> u8 0x00 + + let elem_expr e = + match e.it with | RefNull -> u8 0xd0; end_ () | RefFunc x -> u8 0xd2; var x; end_ () - let elem_index el = - match el.it with + let elem_index e = + match e.it with | RefNull -> assert false | RefFunc x -> var x - let elem_indices data = vec elem_index data - - let all_func_ref l = not (List.exists (fun elem -> elem.it = RefNull) l) - - let table_segment seg = - match seg.it with - | ActiveElem {index = {it = 0l;_}; offset; init; _} - when all_func_ref init -> - u8 0x00; const offset; elem_indices init - | PassiveElem {data; _} - when all_func_ref data -> - u8 0x01; u8 0x00; elem_indices data - | ActiveElem {index; offset; init; _} - when all_func_ref init -> - u8 0x02; var index; const offset; u8 0x00; elem_indices init - | ActiveElem {index = {it = 0l;_}; offset; etype; init} -> - u8 0x04; const offset; vec elem_expr init - | PassiveElem {etype; data} -> - u8 0x05; elem_type etype; vec elem_expr data - | ActiveElem {index; offset; etype; init} -> - u8 0x06; var index; const offset; elem_type etype; vec elem_expr init + let is_func_ref e = match e.it with RefFunc _ -> true | _ -> false + + let elem seg = + let {etype; einit; emode} = seg.it in + let has_indices = List.for_all is_func_ref einit in + match emode.it with + | Passive -> + if has_indices then + (vu32 0x01l; elem_kind etype; vec elem_index einit) + else + (vu32 0x05l; elem_type etype; vec elem_expr einit) + | Active {index; offset} -> + match index.it = 0l, etype = FuncRefType, has_indices with + | true, true, true -> + vu32 0x00l; const offset; vec elem_index einit + | true, true, false -> + vu32 0x04l; const offset; vec elem_expr einit + | _, _, true -> + vu32 0x02l; + var index; const offset; elem_kind etype; vec elem_index einit + | _, _, false -> + vu32 0x06l; + var index; const offset; elem_type etype; vec elem_expr einit let elem_section elems = - section 9 (vec table_segment) elems (elems <> []) + section 9 (vec elem) elems (elems <> []) (* Data section *) - let memory_segment seg = - match seg.it with - | ActiveData {index = {it = 0l;_}; offset; init} -> - u8 0x00; const offset; string init - | PassiveData {data} -> - u8 0x01; string data - | ActiveData {index; offset; init} -> - u8 0x02; var index; const offset; string init + let data seg = + let {dinit; dmode} = seg.it in + match dmode.it with + | Passive -> + vu32 0x01l; string dinit + | Active {index; offset} -> + if index.it = 0l then + (vu32 0x00l; const offset; string dinit) + else + (vu32 0x02l; var index; const offset; string dinit) let data_section datas = - section 11 (vec memory_segment) datas (datas <> []) + section 11 (vec data) datas (datas <> []) (* Data count section *) let data_count_section datas m = diff --git a/interpreter/exec/eval.ml b/interpreter/exec/eval.ml index 1a9c73f02f..90c0ddcd3a 100644 --- a/interpreter/exec/eval.ml +++ b/interpreter/exec/eval.ml @@ -425,8 +425,8 @@ let create_memory (inst : module_inst) (mem : memory) : memory_inst = Memory.alloc mtype let create_global (inst : module_inst) (glob : global) : global_inst = - let {gtype; value} = glob.it in - let v = eval_const inst value in + let {gtype; ginit} = glob.it in + let v = eval_const inst ginit in Global.alloc gtype v let create_export (inst : module_inst) (ex : export) : export_inst = @@ -446,15 +446,17 @@ let elem_list inst init = | RefFunc x -> FuncElem (func inst x) in List.map to_elem init -let create_elem (inst : module_inst) (seg : table_segment) : elem_inst = - match seg.it with - | ActiveElem _ -> ref None - | PassiveElem {data; _} -> ref (Some (elem_list inst data)) +let create_elem (inst : module_inst) (seg : elem_segment) : elem_inst = + let {etype; einit; emode} = seg.it in + match emode.it with + | Passive -> ref (Some (elem_list inst einit)) + | Active _ -> ref None -let create_data (inst : module_inst) (seg : memory_segment) : data_inst = - match seg.it with - | ActiveData _ -> ref None - | PassiveData {data} -> ref (Some data) +let create_data (inst : module_inst) (seg : data_segment) : data_inst = + let {dinit; dmode} = seg.it in + match dmode.it with + | Passive -> ref (Some dinit) + | Active _ -> ref None let init_func (inst : module_inst) (func : func_inst) = @@ -462,27 +464,28 @@ let init_func (inst : module_inst) (func : func_inst) = | Func.AstFunc (_, inst_ref, _) -> inst_ref := inst | _ -> assert false -let init_table (inst : module_inst) (seg : table_segment) = - match seg.it with - | ActiveElem {index; offset = const; init; _} -> +let init_table (inst : module_inst) (seg : elem_segment) = + let {etype; einit; emode} = seg.it in + match emode.it with + | Passive -> () + | Active {index; offset} -> + let refs = elem_list inst einit in let tab = table inst index in - let offset = i32 (eval_const inst const) const.at in - let elems = elem_list inst init in - let len = Int32.of_int (List.length elems) in - (try Table.init tab elems offset 0l len + let i = i32 (eval_const inst offset) offset.at in + let n = Int32.of_int (List.length einit) in + (try Table.init tab refs i 0l n with Table.Bounds -> Link.error seg.at "elements segment does not fit table") - | PassiveElem _ -> () -let init_memory (inst : module_inst) (seg : memory_segment) = - match seg.it with - | ActiveData {index; offset = const; init} -> +let init_memory (inst : module_inst) (seg : data_segment) = + let {dinit; dmode} = seg.it in + match dmode.it with + | Passive -> () + | Active {index; offset} -> let mem = memory inst index in - let offset' = i32 (eval_const inst const) const.at in - let offset = I64_convert.extend_i32_u offset' in - let len = Int32.of_int (String.length init) in - (try Memory.init mem init offset 0L len + let i = i32 (eval_const inst offset) offset.at in + let n = Int32.of_int (String.length dinit) in + (try Memory.init mem dinit (I64_convert.extend_i32_u i) 0L n with Memory.Bounds -> Link.error seg.at "data segment does not fit memory") - | PassiveData _ -> () let add_import (m : module_) (ext : extern) (im : import) (inst : module_inst) diff --git a/interpreter/syntax/ast.ml b/interpreter/syntax/ast.ml index b7770a8715..e450dabf58 100644 --- a/interpreter/syntax/ast.ml +++ b/interpreter/syntax/ast.ml @@ -114,7 +114,7 @@ type global = global' Source.phrase and global' = { gtype : global_type; - value : const; + ginit : const; } type func = func' Source.phrase @@ -140,21 +140,30 @@ and memory' = mtype : memory_type; } -type elem = elem' Source.phrase -and elem' = +type segment_mode = segment_mode' Source.phrase +and segment_mode' = + | Passive + | Active of {index : var; offset : const} + +type elem_expr = elem_expr' Source.phrase +and elem_expr' = | RefNull | RefFunc of var +type elem_segment = elem_segment' Source.phrase +and elem_segment' = +{ + etype : elem_type; + einit : elem_expr list; + emode : segment_mode; +} -type table_segment = table_segment' Source.phrase -and table_segment' = - | ActiveElem of {index : var; offset : const; etype : elem_type; init : elem list} - | PassiveElem of {etype : elem_type; data : elem list} - -type memory_segment = memory_segment' Source.phrase -and memory_segment' = - | ActiveData of {index : var; offset : const; init : string} - | PassiveData of {data : string} +type data_segment = data_segment' Source.phrase +and data_segment' = +{ + dinit : string; + dmode : segment_mode; +} (* Modules *) @@ -199,8 +208,8 @@ and module_' = memories : memory list; funcs : func list; start : var option; - elems : table_segment list; - datas : memory_segment list; + elems : elem_segment list; + datas : data_segment list; imports : import list; exports : export list; } diff --git a/interpreter/syntax/free.ml b/interpreter/syntax/free.ml index e4f5536dd2..ebd1182b92 100644 --- a/interpreter/syntax/free.ml +++ b/interpreter/syntax/free.ml @@ -85,26 +85,26 @@ and block (es : instr list) = let const (c : const) = block c.it -let global (g : global) = const g.it.value +let global (g : global) = const g.it.ginit let func (f : func) = {(block f.it.body) with locals = Set.empty} let table (t : table) = empty let memory (m : memory) = empty -let elem (e : elem) = +let segment_mode f (m : segment_mode) = + match m.it with + | Passive -> empty + | Active {index; offset} -> f (var index) ++ const offset + +let elem_expr (e : elem_expr) = match e.it with | RefNull -> empty | RefFunc x -> funcs (var x) -let table_segment (s : table_segment) = - match s.it with - | ActiveElem {index; offset; init; _} -> - tables (var index) ++ const offset ++ list elem init - | PassiveElem {data; _} -> list elem data +let elem (s : elem_segment) = + list elem_expr s.it.einit ++ segment_mode tables s.it.emode -let memory_segment (s : memory_segment) = - match s.it with - | ActiveData {index; offset; init} -> memories (var index) ++ const offset - | PassiveData {data} -> empty +let data (s : data_segment) = + segment_mode memories s.it.dmode let type_ (t : type_) = empty @@ -135,7 +135,7 @@ let module_ (m : module_) = list memory m.it.memories ++ list func m.it.funcs ++ start m.it.start ++ - list table_segment m.it.elems ++ - list memory_segment m.it.datas ++ + list elem m.it.elems ++ + list data m.it.datas ++ list import m.it.imports ++ list export m.it.exports diff --git a/interpreter/syntax/free.mli b/interpreter/syntax/free.mli index b7ea2d7480..288a27b679 100644 --- a/interpreter/syntax/free.mli +++ b/interpreter/syntax/free.mli @@ -25,8 +25,8 @@ val global : Ast.global -> t val func : Ast.func -> t val table : Ast.table -> t val memory : Ast.memory -> t -val table_segment : Ast.table_segment -> t -val memory_segment : Ast.memory_segment -> t +val elem : Ast.elem_segment -> t +val data : Ast.data_segment -> t val export : Ast.export -> t val import : Ast.import -> t val start : Ast.var option -> t diff --git a/interpreter/syntax/types.ml b/interpreter/syntax/types.ml index 82d897952a..ea59848b74 100644 --- a/interpreter/syntax/types.ml +++ b/interpreter/syntax/types.ml @@ -10,7 +10,7 @@ type mutability = Immutable | Mutable type table_type = TableType of Int32.t limits * elem_type type memory_type = MemoryType of Int32.t limits type global_type = GlobalType of value_type * mutability -type segment_type = SegmentType +type segment_type = PassiveType | ActiveType type extern_type = | ExternFuncType of func_type | ExternTableType of table_type diff --git a/interpreter/text/arrange.ml b/interpreter/text/arrange.ml index 6ed57bbac6..21ca70a24a 100644 --- a/interpreter/text/arrange.ml +++ b/interpreter/text/arrange.ml @@ -296,6 +296,9 @@ let memory off i mem = let {mtype = MemoryType lim} = mem.it in Node ("memory $" ^ nat (off + i) ^ " " ^ limits nat32 lim, []) +let elem_kind = function + | FuncRefType -> "func" + let elem_index el = match el.it with | RefNull -> assert false @@ -306,37 +309,28 @@ let elem_expr el = | RefNull -> Node ("ref.null", []) | RefFunc x -> Node ("ref.func", [atom var x]) -let all_func_ref l = not (List.exists (fun elem -> elem.it = RefNull) l) - -let elems seg = - match seg.it with - | ActiveElem {index = {it = 0l;_}; offset; init; _} - when all_func_ref init -> - Node ("elem", Node ("offset", const offset) :: list elem_index init) - | ActiveElem {index; offset; init; _} - when all_func_ref init -> - Node ("elem", Node ("table", [atom var index]) - :: Node ("offset", const offset) :: Atom "func" :: list elem_index init) - | ActiveElem {index = {it = 0l;_}; offset; etype; init} -> - Node ("elem", Node ("offset", const offset) :: atom elem_type etype - :: list elem_expr init) - | ActiveElem {index; offset; etype; init} -> - Node ("elem", Node ("table", [atom var index]) - :: Node ("offset", const offset) - :: atom elem_type etype :: list elem_expr init) - | PassiveElem {data; _} - when all_func_ref data -> - Node ("elem func", list elem_index data) - | PassiveElem {etype; data} -> - Node ("elem", atom elem_type etype - :: list elem_expr data) +let segment_mode category mode = + match mode.it with + | Passive -> [] + | Active {index; offset} -> + (if index.it = 0l then [] else [Node (category, [atom var index])]) @ + [Node ("offset", const offset)] + +let is_func_ref e = match e.it with RefFunc _ -> true | _ -> false + +let elem seg = + let {etype; einit; emode} = seg.it in + Node ("elem", + segment_mode "table" emode @ + if List.for_all is_func_ref einit then + atom elem_kind etype :: list elem_index einit + else + atom elem_type etype :: list elem_expr einit + ) let data seg = - match seg.it with - | ActiveData {index; offset; init} -> - Node ("data", atom var index :: Node ("offset", const offset) - :: break_bytes init) - | PassiveData {data} -> Node ("data", break_bytes data) + let {dinit; dmode} = seg.it in + Node ("data", segment_mode "memory" dmode @ break_bytes dinit) (* Modules *) @@ -370,8 +364,8 @@ let export ex = Node ("export", [atom name n; export_desc edesc]) let global off i g = - let {gtype; value} = g.it in - Node ("global $" ^ nat (off + i), global_type gtype :: const value) + let {gtype; ginit} = g.it in + Node ("global $" ^ nat (off + i), global_type gtype :: const ginit) (* Modules *) @@ -406,7 +400,7 @@ let module_with_var_opt x_opt m = listi (func_with_index (List.length func_imports)) m.it.funcs @ list export m.it.exports @ opt start m.it.start @ - list elems m.it.elems @ + list elem m.it.elems @ list data m.it.datas ) diff --git a/interpreter/text/parser.mly b/interpreter/text/parser.mly index 5de6b0dc1d..81b01939f0 100644 --- a/interpreter/text/parser.mly +++ b/interpreter/text/parser.mly @@ -601,23 +601,25 @@ elem : { let at = at () in fun c -> ignore ($3 c anon_elem bind_elem); fun () -> - ActiveElem {index = 0l @@ at; offset = $4 c; etype = FuncRefType; - init = $5 c func} @@ at } + { etype = FuncRefType; einit = $5 c func; + emode = Active {index = 0l @@ at; offset = $4 c} @@ at} @@ at } | LPAR ELEM bind_var_opt elem_list RPAR { let at = at () in fun c -> ignore ($3 c anon_elem bind_elem); - fun () -> PassiveElem {etype = (fst $4); data = (snd $4) c} @@ at } + fun () -> + {etype = (fst $4); einit = (snd $4) c; emode = Passive @@ at} @@ at } | LPAR ELEM bind_var_opt table_use offset elem_list RPAR { let at = at () in fun c -> ignore ($3 c anon_elem bind_elem); fun () -> - ActiveElem {index = $4 c table; offset = $5 c; - etype = (fst $6); init = (snd $6) c} @@ at } + { etype = (fst $6); einit = (snd $6) c; + emode = Active {index = $4 c table; offset = $5 c} @@ at} @@ at } | LPAR ELEM bind_var_opt offset elem_list RPAR /* Sugar */ { let at = at () in fun c -> ignore ($3 c anon_elem bind_elem); - fun () -> ActiveElem {index = 0l @@ at; offset = $4 c; - etype = (fst $5); init = (snd $5) c} @@ at } + fun () -> + { etype = (fst $5); einit = (snd $5) c; + emode = Active {index = 0l @@ at; offset = $4 c} @@ at} @@ at } table : | LPAR TABLE bind_var_opt table_fields RPAR @@ -639,37 +641,42 @@ table_fields : | elem_type LPAR ELEM elem_var_list RPAR /* Sugar */ { fun c x at -> let offset = [i32_const (0l @@ at) @@ at] @@ at in - let init = $4 c func in - let size = Lib.List32.length init in + let einit = $4 c func in + let size = Lib.List32.length einit in + let emode = Active {index = x; offset} @@ at in [{ttype = TableType ({min = size; max = Some size}, $1)} @@ at], - [ActiveElem {index = x; offset; etype = FuncRefType; init} @@ at], + [{etype = FuncRefType; einit; emode} @@ at], [], [] } | elem_type LPAR ELEM elem_expr elem_expr_list RPAR /* Sugar */ { fun c x at -> let offset = [i32_const (0l @@ at) @@ at] @@ at in - let init = (fun c -> $4 c :: $5 c) c in - let size = Lib.List32.length init in + let einit = (fun c -> $4 c :: $5 c) c in + let size = Lib.List32.length einit in + let emode = Active {index = x; offset} @@ at in [{ttype = TableType ({min = size; max = Some size}, $1)} @@ at], - [ActiveElem {index = x; offset; etype = FuncRefType; init} @@ at], + [{etype = FuncRefType; einit; emode} @@ at], [], [] } data : | LPAR DATA bind_var_opt string_list RPAR { let at = at () in fun c -> ignore ($3 c anon_data bind_data); - fun () -> PassiveData {data = $4} @@ at } + fun () -> {dinit = $4; dmode = Passive @@ at} @@ at } | LPAR DATA bind_var var offset string_list RPAR { let at = at () in fun c -> ignore (bind_data c $3); - fun () -> ActiveData {index = $4 c memory; offset = $5 c; init = $6} @@ at } + fun () -> + {dinit = $6; dmode = Active {index = $4 c memory; offset = $5 c} @@ at} @@ at } | LPAR DATA var offset string_list RPAR { let at = at () in fun c -> ignore (anon_data c); - fun () -> ActiveData {index = $3 c memory; offset = $4 c; init = $5} @@ at } + fun () -> + {dinit = $5; dmode = Active {index = $3 c memory; offset = $4 c} @@ at} @@ at } | LPAR DATA offset string_list RPAR /* Sugar */ { let at = at () in fun c -> ignore (anon_data c); - fun () -> ActiveData {index = 0l @@ at; offset = $3 c; init = $4} @@ at } + fun () -> + {dinit = $4; dmode = Active {index = 0l @@ at; offset = $3 c} @@ at} @@ at } memory : | LPAR MEMORY bind_var_opt memory_fields RPAR @@ -693,7 +700,7 @@ memory_fields : let offset = [i32_const (0l @@ at) @@ at] @@ at in let size = Int32.(div (add (of_int (String.length $3)) 65535l) 65536l) in [{mtype = MemoryType {min = size; max = Some size}} @@ at], - [ActiveData {index = x; offset; init = $3} @@ at], + [{dinit = $3; dmode = Active {index = x; offset} @@ at} @@ at], [], [] } global : @@ -704,7 +711,7 @@ global : global_fields : | global_type const_expr - { fun c x at -> [{gtype = $1; value = $2 c} @@ at], [], [] } + { fun c x at -> [{gtype = $1; ginit = $2 c} @@ at], [], [] } | inline_import global_type /* Sugar */ { fun c x at -> [], @@ -858,9 +865,9 @@ script_var_opt : script_module : | module_ { $1 } | LPAR MODULE module_var_opt BIN string_list RPAR - { $3, Encoded ("binary", $5) @@ at() } + { $3, Encoded ("binary:" ^ string_of_pos (at()).left, $5) @@ at() } | LPAR MODULE module_var_opt QUOTE string_list RPAR - { $3, Quoted ("quote", $5) @@ at() } + { $3, Quoted ("quote:" ^ string_of_pos (at()).left, $5) @@ at() } action : | LPAR INVOKE module_var_opt name const_list RPAR diff --git a/interpreter/valid/valid.ml b/interpreter/valid/valid.ml index 6217158fd4..1a33d35d26 100644 --- a/interpreter/valid/valid.ml +++ b/interpreter/valid/valid.ml @@ -422,31 +422,39 @@ let check_memory (c : context) (mem : memory) = let {mtype} = mem.it in check_memory_type mtype mem.at -let check_elemref (c : context) (el : elem) = - match el.it with +let check_elem_expr (c : context) (t : elem_type) (e : elem_expr) = + match e.it with | RefNull -> () | RefFunc x -> ignore (func c x) -let check_elem (c : context) (seg : table_segment) = - match seg.it with - | ActiveElem {index; offset; init; _} -> - ignore (table c index); - check_const c offset I32Type; - List.iter (check_elemref c) init - | PassiveElem {data; _} -> - List.iter (check_elemref c) data - -let check_data (c : context) (seg : memory_segment) = - match seg.it with - | ActiveData {index; offset; init} -> +let check_elem_mode (c : context) (t : elem_type) (mode : segment_mode) = + match mode.it with + | Passive -> () + | Active {index; offset} -> + let TableType (_, et) = table c index in + require (et = t) mode.at "type mismatch in active element segment"; + check_const c offset I32Type + +let check_elem (c : context) (seg : elem_segment) = + let {etype; einit; emode} = seg.it in + List.iter (check_elem_expr c etype) einit; + check_elem_mode c etype emode + +let check_data_mode (c : context) (mode : segment_mode) = + match mode.it with + | Passive -> () + | Active {index; offset} -> ignore (memory c index); check_const c offset I32Type - | PassiveData init -> () + +let check_data (c : context) (seg : data_segment) = + let {dinit; dmode} = seg.it in + check_data_mode c dmode let check_global (c : context) (glob : global) = - let {gtype; value} = glob.it in + let {gtype; ginit} = glob.it in let GlobalType (t, mut) = gtype in - check_const c value t + check_const c ginit t (* Modules *) @@ -485,6 +493,11 @@ let check_export (c : context) (set : NameSet.t) (ex : export) : NameSet.t = require (not (NameSet.mem name set)) ex.at "duplicate export name"; NameSet.add name set +let segment_type mode = + match mode.it with + | Passive -> PassiveType + | Active _ -> ActiveType + let check_module (m : module_) = let { types; imports; tables; memories; globals; funcs; start; elems; datas; @@ -499,8 +512,8 @@ let check_module (m : module_) = funcs = c0.funcs @ List.map (fun f -> type_ c0 f.it.ftype) funcs; tables = c0.tables @ List.map (fun tab -> tab.it.ttype) tables; memories = c0.memories @ List.map (fun mem -> mem.it.mtype) memories; - elems = List.map (fun elem -> SegmentType) elems; - datas = List.map (fun data -> SegmentType) datas; + elems = List.map (fun elem -> segment_type elem.it.emode) elems; + datas = List.map (fun data -> segment_type data.it.dmode) datas; } in let c = From df2a55f0c58192baf441e8b1d50b8825b2d5341f Mon Sep 17 00:00:00 2001 From: Andreas Rossberg Date: Mon, 7 Oct 2019 11:45:11 +0200 Subject: [PATCH 125/199] [spec] Specify instantiate (#114) Incorporate active/passive segments into instantiation. While doing so, drop the notion of segment types as well as initelem/initdata administrative instructions and express the latter in terms of table.init and memory.init instructions. Adjust interpreter accordingly. --- document/core/appendix/index-rules.rst | 8 +- document/core/appendix/properties.rst | 48 ------- document/core/binary/modules.rst | 12 +- document/core/exec/modules.rst | 174 +++++++++++++------------ document/core/exec/runtime.rst | 9 -- document/core/syntax/modules.rst | 14 +- document/core/syntax/types.rst | 19 --- document/core/text/modules.rst | 4 +- document/core/util/macros.def | 14 +- document/core/valid/conventions.rst | 8 +- document/core/valid/instructions.rst | 16 +-- document/core/valid/modules.rst | 62 +++++---- interpreter/exec/eval.ml | 87 ++++++------- interpreter/syntax/types.ml | 1 - interpreter/util/lib.ml | 5 + interpreter/util/lib.mli | 1 + interpreter/valid/valid.ml | 13 +- test/core/data.wast | 50 +++---- test/core/elem.wast | 44 +++---- test/core/linking.wast | 28 ++-- 20 files changed, 266 insertions(+), 351 deletions(-) diff --git a/document/core/appendix/index-rules.rst b/document/core/appendix/index-rules.rst index 673102aa04..622852aa9a 100644 --- a/document/core/appendix/index-rules.rst +++ b/document/core/appendix/index-rules.rst @@ -25,10 +25,10 @@ Construct Judgement :ref:`Table ` :math:`C \vdashtable \table : \tabletype` :ref:`Memory ` :math:`C \vdashmem \mem : \memtype` :ref:`Global ` :math:`C \vdashglobal \global : \globaltype` -:ref:`Element segment ` :math:`C \vdashelem \elem : \segtype` -:ref:`Element mode ` :math:`C \vdashelemmode \elemmode : \segtype` -:ref:`Data segment ` :math:`C \vdashdata \data : \segtype` -:ref:`Data mode ` :math:`C \vdashdatamode \datamode : \segtype` +:ref:`Element segment ` :math:`C \vdashelem \elem \ok` +:ref:`Element mode ` :math:`C \vdashelemmode \elemmode \ok` +:ref:`Data segment ` :math:`C \vdashdata \data \ok` +:ref:`Data mode ` :math:`C \vdashdatamode \datamode \ok` :ref:`Start function ` :math:`C \vdashstart \start \ok` :ref:`Export ` :math:`C \vdashexport \export : \externtype` :ref:`Export description ` :math:`C \vdashexportdesc \exportdesc : \externtype` diff --git a/document/core/appendix/properties.rst b/document/core/appendix/properties.rst index 330f42dc4d..b875c1a9fb 100644 --- a/document/core/appendix/properties.rst +++ b/document/core/appendix/properties.rst @@ -485,54 +485,6 @@ To that end, all previous typing judgements :math:`C \vdash \X{prop}` are genera } -.. index:: element, table, table address, module instance, function index - -:math:`\INITELEM~\tableaddr~o~x^n` -.................................. - -* The :ref:`external table value ` :math:`\EVTABLE~\tableaddr` must be :ref:`valid ` with some :ref:`external table type ` :math:`\ETTABLE~\limits~\FUNCREF`. - -* The index :math:`o + n` must be smaller than or equal to :math:`\limits.\LMIN`. - -* The :ref:`module instance ` :math:`\moduleinst` must be :ref:`valid ` with some :ref:`context ` :math:`C`. - -* Each :ref:`function index ` :math:`x_i` in :math:`x^n` must be defined in the context :math:`C`. - -* Then the instruction is valid. - -.. math:: - \frac{ - S \vdashexternval \EVTABLE~\tableaddr : \ETTABLE~\limits~\FUNCREF - \qquad - o + n \leq \limits.\LMIN - \qquad - (C.\CFUNCS[x] = \functype)^n - }{ - S; C \vdashadmininstr \INITELEM~\tableaddr~o~x^n \ok - } - - -.. index:: data, memory, memory address, byte - -:math:`\INITDATA~\memaddr~o~b^n` -................................ - -* The :ref:`external memory value ` :math:`\EVMEM~\memaddr` must be :ref:`valid ` with some :ref:`external memory type ` :math:`\ETMEM~\limits`. - -* The index :math:`o + n` must be smaller than or equal to :math:`\limits.\LMIN` divided by the :ref:`page size ` :math:`64\,\F{Ki}`. - -* Then the instruction is valid. - -.. math:: - \frac{ - S \vdashexternval \EVMEM~\memaddr : \ETMEM~\limits - \qquad - o + n \leq \limits.\LMIN \cdot 64\,\F{Ki} - }{ - S; C \vdashadmininstr \INITDATA~\memaddr~o~b^n \ok - } - - .. index:: label, instruction, result type :math:`\LABEL_n\{\instr_0^\ast\}~\instr^\ast~\END` diff --git a/document/core/binary/modules.rst b/document/core/binary/modules.rst index 0cc7905abb..36c1c993fd 100644 --- a/document/core/binary/modules.rst +++ b/document/core/binary/modules.rst @@ -321,7 +321,7 @@ Element Section ~~~~~~~~~~~~~~~ The *element section* has the id 9. -It decodes into a vector of :ref:`element segments ` that represent the |MELEM| component of a :ref:`module `. +It decodes into a vector of :ref:`element segments ` that represent the |MELEMS| component of a :ref:`module `. .. math:: \begin{array}{llclll} @@ -354,7 +354,7 @@ It decodes into a vector of :ref:`element segments ` that represent bit 2 indicates the use of element type and element expressions instead of element kind and element indices. In the current version of WebAssembly, at most one table may be defined or - imported in a single module, so all valid :ref:`active ` + imported in a single module, so all valid :ref:`active ` element segments have a |ETABLE| value of :math:`0`. Additional element kinds may be added in future versions of WebAssembly. @@ -429,7 +429,7 @@ Data Section ~~~~~~~~~~~~ The *data section* has the id 11. -It decodes into a vector of :ref:`data segments ` that represent the |MDATA| component of a :ref:`module `. +It decodes into a vector of :ref:`data segments ` that represent the |MDATAS| component of a :ref:`module `. .. math:: \begin{array}{llclll} @@ -450,7 +450,7 @@ It decodes into a vector of :ref:`data segments ` that represent th bit 1 indicates the presence of an explicit memory index for an active segment. In the current version of WebAssembly, at most one memory may be defined or - imported in a single module, so all valid :ref:`active ` data + imported in a single module, so all valid :ref:`active ` data segments have a |DMEM| value of :math:`0`. @@ -543,8 +543,8 @@ Furthermore, it must be present if any :math:`data index ` occur \MTABLES~\table^\ast, \\ \MMEMS~\mem^\ast, \\ \MGLOBALS~\global^\ast, \\ - \MELEM~\elem^\ast, \\ - \MDATA~\data^m, \\ + \MELEMS~\elem^\ast, \\ + \MDATAS~\data^m, \\ \MSTART~\start^?, \\ \MIMPORTS~\import^\ast, \\ \MEXPORTS~\export^\ast ~\} \\ diff --git a/document/core/exec/modules.rst b/document/core/exec/modules.rst index 91ffa3d529..1e083a0038 100644 --- a/document/core/exec/modules.rst +++ b/document/core/exec/modules.rst @@ -488,10 +488,10 @@ Growing :ref:`memories ` .................................. The allocation function for :ref:`modules ` requires a suitable list of :ref:`external values ` that are assumed to :ref:`match ` the :ref:`import ` vector of the module, -and a list of initialization :ref:`values ` for the module's :ref:`globals `. +a list of initialization :ref:`values ` for the module's :ref:`globals `, +and list of :ref:`function element ` vectors for the module's :ref:`element segments `. -1. Let :math:`\module` be the :ref:`module ` to allocate and :math:`\externval_{\F{im}}^\ast` the vector of :ref:`external values ` providing the module's imports, -and :math:`\val^\ast` the initialization :ref:`values ` of the module's :ref:`globals `. +1. Let :math:`\module` be the :ref:`module ` to allocate and :math:`\externval_{\F{im}}^\ast` the vector of :ref:`external values ` providing the module's imports, :math:`\val^\ast` the initialization :ref:`values ` of the module's :ref:`globals `, and :math:`(\funcelem^\ast)^\ast` the :ref:`function element ` vectors of the module's :ref:`element segments `. 2. For each :ref:`function ` :math:`\func_i` in :math:`\module.\MFUNCS`, do: @@ -509,23 +509,35 @@ and :math:`\val^\ast` the initialization :ref:`values ` of the modul a. Let :math:`\globaladdr_i` be the :ref:`global address ` resulting from :ref:`allocating ` :math:`\global_i.\GTYPE` with initializer value :math:`\val^\ast[i]`. -6. Let :math:`\funcaddr^\ast` be the the concatenation of the :ref:`function addresses ` :math:`\funcaddr_i` in index order. +6. For each :ref:`element segment ` :math:`\elem_i` in :math:`\module.\MELEMS`, do: -7. Let :math:`\tableaddr^\ast` be the the concatenation of the :ref:`table addresses ` :math:`\tableaddr_i` in index order. + a. Let :math:`\elemaddr_i` be the :ref:`element address ` resulting from :ref:`allocating ` a :ref:`element instance ` with contents :math:`(\funcelem^\ast)^\ast[i]`. -8. Let :math:`\memaddr^\ast` be the the concatenation of the :ref:`memory addresses ` :math:`\memaddr_i` in index order. +7. For each :ref:`data segment ` :math:`\data_i` in :math:`\module.\MDATAS`, do: -9. Let :math:`\globaladdr^\ast` be the the concatenation of the :ref:`global addresses ` :math:`\globaladdr_i` in index order. + a. Let :math:`\dataaddr_i` be the :ref:`data address ` resulting from :ref:`allocating ` a :ref:`data instance ` with contents :math:`\data_i.\DINIT`. -10. Let :math:`\funcaddr_{\F{mod}}^\ast` be the list of :ref:`function addresses ` extracted from :math:`\externval_{\F{im}}^\ast`, concatenated with :math:`\funcaddr^\ast`. +8. Let :math:`\funcaddr^\ast` be the the concatenation of the :ref:`function addresses ` :math:`\funcaddr_i` in index order. -11. Let :math:`\tableaddr_{\F{mod}}^\ast` be the list of :ref:`table addresses ` extracted from :math:`\externval_{\F{im}}^\ast`, concatenated with :math:`\tableaddr^\ast`. +9. Let :math:`\tableaddr^\ast` be the the concatenation of the :ref:`table addresses ` :math:`\tableaddr_i` in index order. -12. Let :math:`\memaddr_{\F{mod}}^\ast` be the list of :ref:`memory addresses ` extracted from :math:`\externval_{\F{im}}^\ast`, concatenated with :math:`\memaddr^\ast`. +10. Let :math:`\memaddr^\ast` be the the concatenation of the :ref:`memory addresses ` :math:`\memaddr_i` in index order. -13. Let :math:`\globaladdr_{\F{mod}}^\ast` be the list of :ref:`global addresses ` extracted from :math:`\externval_{\F{im}}^\ast`, concatenated with :math:`\globaladdr^\ast`. +11. Let :math:`\globaladdr^\ast` be the the concatenation of the :ref:`global addresses ` :math:`\globaladdr_i` in index order. -14. For each :ref:`export ` :math:`\export_i` in :math:`\module.\MEXPORTS`, do: +12. Let :math:`\elemaddr^\ast` be the the concatenation of the :ref:`element addresses ` :math:`\elemaddr_i` in index order. + +13. Let :math:`\dataaddr^\ast` be the the concatenation of the :ref:`data addresses ` :math:`\dataaddr_i` in index order. + +14. Let :math:`\funcaddr_{\F{mod}}^\ast` be the list of :ref:`function addresses ` extracted from :math:`\externval_{\F{im}}^\ast`, concatenated with :math:`\funcaddr^\ast`. + +15. Let :math:`\tableaddr_{\F{mod}}^\ast` be the list of :ref:`table addresses ` extracted from :math:`\externval_{\F{im}}^\ast`, concatenated with :math:`\tableaddr^\ast`. + +16. Let :math:`\memaddr_{\F{mod}}^\ast` be the list of :ref:`memory addresses ` extracted from :math:`\externval_{\F{im}}^\ast`, concatenated with :math:`\memaddr^\ast`. + +17. Let :math:`\globaladdr_{\F{mod}}^\ast` be the list of :ref:`global addresses ` extracted from :math:`\externval_{\F{im}}^\ast`, concatenated with :math:`\globaladdr^\ast`. + +18. For each :ref:`export ` :math:`\export_i` in :math:`\module.\MEXPORTS`, do: a. If :math:`\export_i` is a function export for :ref:`function index ` :math:`x`, then let :math:`\externval_i` be the :ref:`external value ` :math:`\EVFUNC~(\funcaddr_{\F{mod}}^\ast[x])`. @@ -537,17 +549,17 @@ and :math:`\val^\ast` the initialization :ref:`values ` of the modul e. Let :math:`\exportinst_i` be the :ref:`export instance ` :math:`\{\EINAME~(\export_i.\ENAME), \EIVALUE~\externval_i\}`. -15. Let :math:`\exportinst^\ast` be the the concatenation of the :ref:`export instances ` :math:`\exportinst_i` in index order. +19. Let :math:`\exportinst^\ast` be the the concatenation of the :ref:`export instances ` :math:`\exportinst_i` in index order. -16. Let :math:`\moduleinst` be the :ref:`module instance ` :math:`\{\MITYPES~(\module.\MTYPES),` :math:`\MIFUNCS~\funcaddr_{\F{mod}}^\ast,` :math:`\MITABLES~\tableaddr_{\F{mod}}^\ast,` :math:`\MIMEMS~\memaddr_{\F{mod}}^\ast,` :math:`\MIGLOBALS~\globaladdr_{\F{mod}}^\ast,` :math:`\MIEXPORTS~\exportinst^\ast\}`. +20. Let :math:`\moduleinst` be the :ref:`module instance ` :math:`\{\MITYPES~(\module.\MTYPES),` :math:`\MIFUNCS~\funcaddr_{\F{mod}}^\ast,` :math:`\MITABLES~\tableaddr_{\F{mod}}^\ast,` :math:`\MIMEMS~\memaddr_{\F{mod}}^\ast,` :math:`\MIGLOBALS~\globaladdr_{\F{mod}}^\ast,` :math:`\MIEXPORTS~\exportinst^\ast\}`. -17. Return :math:`\moduleinst`. +21. Return :math:`\moduleinst`. .. math:: ~\\ \begin{array}{rlll} - \allocmodule(S, \module, \externval_{\F{im}}^\ast, \val^\ast) &=& S', \moduleinst \end{array} + \allocmodule(S, \module, \externval_{\F{im}}^\ast, \val^\ast, (\funcelem^\ast)^\ast) &=& S', \moduleinst \end{array} where: @@ -560,6 +572,8 @@ where: \MITABLES~\evtables(\externval_{\F{im}}^\ast)~\tableaddr^\ast, \\ \MIMEMS~\evmems(\externval_{\F{im}}^\ast)~\memaddr^\ast, \\ \MIGLOBALS~\evglobals(\externval_{\F{im}}^\ast)~\globaladdr^\ast, \\ + \MIELEMS~\elemaddr^\ast, \\ + \MIDATAS~\dataaddr^\ast, \\ \MIEXPORTS~\exportinst^\ast ~\} \end{array} \\[1ex] S_1, \funcaddr^\ast &=& \allocfunc^\ast(S, \module.\MFUNCS, \moduleinst) \\ @@ -567,8 +581,11 @@ where: \qquad\qquad\qquad~ (\where \table^\ast = \module.\MTABLES) \\ S_3, \memaddr^\ast &=& \allocmem^\ast(S_2, (\mem.\MTYPE)^\ast) \qquad\qquad\qquad~ (\where \mem^\ast = \module.\MMEMS) \\ - S', \globaladdr^\ast &=& \allocglobal^\ast(S_3, (\global.\GTYPE)^\ast, \val^\ast) + S_4, \globaladdr^\ast &=& \allocglobal^\ast(S_3, (\global.\GTYPE)^\ast, \val^\ast) \qquad\quad~ (\where \global^\ast = \module.\MGLOBALS) \\ + S_5, \elemaddr^\ast &=& \allocelem^\ast(S_4, (\funcelem^\ast)^\ast) \\ + S', \dataaddr^\ast &=& \allocdata^\ast(S_5, (\data.\DINIT)^\ast) + \qquad\qquad\qquad~ (\where \data^\ast = \module.\MDATAS) \\ \exportinst^\ast &=& \{ \EINAME~(\export.\ENAME), \EIVALUE~\externval_{\F{ex}} \}^\ast \quad (\where \export^\ast = \module.\MEXPORTS) \\[1ex] \evfuncs(\externval_{\F{ex}}^\ast) &=& (\moduleinst.\MIFUNCS[x])^\ast @@ -614,8 +631,6 @@ Moreover, if the dots :math:`\dots` are a sequence :math:`A^n` (as for globals), Instantiation ~~~~~~~~~~~~~ -.. todo:: Adjust for passive segments. - Given a :ref:`store ` :math:`S`, a :ref:`module ` :math:`\module` is instantiated with a list of :ref:`external values ` :math:`\externval^n` supplying the required imports as follows. Instantiation checks that the module is :ref:`valid ` and the provided imports :ref:`match ` the declared types, @@ -661,121 +676,110 @@ It is up to the :ref:`embedder ` to define how such conditions are rep f. Pop the frame :math:`F_{\F{im}}` from the stack. -6. Let :math:`\moduleinst` be a new module instance :ref:`allocated ` from :math:`\module` in store :math:`S` with imports :math:`\externval^n` and global initializer values :math:`\val^\ast`, and let :math:`S'` be the extended store produced by module allocation. - -7. Let :math:`F` be the :ref:`frame ` :math:`\{ \AMODULE~\moduleinst, \ALOCALS~\epsilon \}`. + g. Let :math:`\val^\ast` be the conatenation of :math:`\val_i` in index order. -8. Push the frame :math:`F` to the stack. +6. Let :math:`(\funcelem^\ast)^\ast` be the list of :ref:`function element ` vectors determined by the :ref:`element segments ` in :math:`\module`. These may be calculated as follows. -9. For each :ref:`element segment ` :math:`\elem_i` in :math:`\module.\MELEM` whose :ref:`mode ` :math:`\elem_i.\EMODE` is of the form :math:`\EACTIVE~\{ \ETABLE~\tableidx_i, \EOFFSET~\X{eoexpr}_i \}`, do: + a. For each :ref:`element segment ` :math:`\elem_i` in :math:`\module.\MELEMS`, and for each :ref:`element expression ` :math:`\elemexpr_{ij}` in :math:`\elem_i.\EINIT`, do: - a. Assert: due to :ref:`validation `, :math:`\moduleinst.\MITABLES[\tableidx_i]` exists. + i. If :math:`\elemexpr_{ij}` is of the form :math:`\REFNULL`, then let the :ref:`function element ` :math:`\funcelem_{ij}` be :math:`\epsilon`. - b. Let :math:`\tableaddr_i` be the :ref:`table address ` :math:`\moduleinst.\MITABLES[\tableidx_i]`. + ii. Else, :math:`\elemexpr_{ij}` is of the form is :math:`\REFFUNC~\funcidx_{ij}`. - c. Assert: due to :ref:`validation `, :math:`S'.\STABLES[\tableaddr_i]` exists. + iii. Assert: due to :ref:`validation `, :math:`\moduleinst.\MIFUNCS[\funcidx_{ij}]` exists. - d. Let :math:`\tableinst_i` be the :ref:`table instance ` :math:`S'.\STABLES[\tableaddr_i]`. + iv. Let the :ref:`function element ` :math:`\funcelem_{ij}` be the :ref:`function address ` :math:`\moduleinst.\MIFUNCS[\funcidx_{ij}]`. - e. Let :math:`\X{eoval}_i` be the result of :ref:`evaluating ` the expression :math:`\X{eoexpr}_i`. + b. Let :math:`\funcelem^\ast_i` be the concatenation of function elements :math:`\funcelem_{ij}` in order of index :math:`j`. - f. Assert: due to :ref:`validation `, :math:`\X{eoval}_i` is of the form :math:`\I32.\CONST~\X{eo}_i`. + c. Let :math:`(\funcelem^\ast)^\ast` be the concatenation of function element vectors :math:`\funcelem^\ast_i` in order of index :math:`i`. - g. Let :math:`\X{eend}_i` be :math:`\X{eo}_i` plus the length of :math:`\elem_i.\EINIT`. +7. Let :math:`\moduleinst` be a new module instance :ref:`allocated ` from :math:`\module` in store :math:`S` with imports :math:`\externval^n`, global initializer values :math:`\val^\ast`, and element segment contents :math:`(\funcelem^\ast)^\ast`, and let :math:`S'` be the extended store produced by module allocation. - h. If :math:`\X{eend}_i` is larger than the length of :math:`\tableinst_i.\TIELEM`, then: +8. Let :math:`F` be the auxiliary :ref:`frame ` :math:`\{ \AMODULE~\moduleinst, \ALOCALS~\epsilon \}`. - i. Fail. +9. Push the frame :math:`F` to the stack. -10. For each :ref:`data segment ` :math:`\data_i` in :math:`\module.\MDATA` whose :ref:`mode ` :math:`\data_i.\DMODE` is of the form :math:`\DACTIVE~\{ \DMEM~\memidx_i, \DOFFSET~\X{doexpr}_i \}`, do: +10. For each :ref:`element segment ` :math:`\elem_i` in :math:`\module.\MELEMS` whose :ref:`mode ` is of the form :math:`\EACTIVE~\{ \ETABLE~\tableidx_i, \EOFFSET~\X{einstr}^\ast_i~\END \}`, do: - a. Assert: due to :ref:`validation `, :math:`\moduleinst.\MIMEMS[\memidx_i]` exists. + a. Assert: :math:`\tableidx_i` is :math:`0`. - b. Let :math:`\memaddr_i` be the :ref:`memory address ` :math:`\moduleinst.\MIMEMS[\memidx_i]`. + b. Let :math:`n` be the length of the vector :math:`\elem_i.\EINIT`. - c. Assert: due to :ref:`validation `, :math:`S'.\SMEMS[\memaddr_i]` exists. + c. :ref:`Execute ` the instruction sequence :math:`\X{einstr}^\ast_i`. - d. Let :math:`\meminst_i` be the :ref:`memory instance ` :math:`S'.\SMEMS[\memaddr_i]`. + d. :ref:`Execute ` the instruction :math:`\I32.\CONST~0`. - e. Let :math:`\X{doval}_i` be the result of :ref:`evaluating ` the expression :math:`\data_i.\DOFFSET`. + e. :ref:`Execute ` the instruction :math:`\I32.\CONST~n`. - f. Assert: due to :ref:`validation `, :math:`\X{doval}_i` is of the form :math:`\I32.\CONST~\X{do}_i`. + f. :ref:`Execute ` the instruction :math:`\TABLEINIT~i`. - g. Let :math:`\X{dend}_i` be :math:`\X{do}_i` plus the length of :math:`\data_i.\DINIT`. + g. :ref:`Execute ` the instruction :math:`\ELEMDROP~i`. - h. If :math:`\X{dend}_i` is larger than the length of :math:`\meminst_i.\MIDATA`, then: +11. For each :ref:`data segment ` :math:`\data_i` in :math:`\module.\MDATAS` whose :ref:`mode ` is of the form :math:`\DACTIVE~\{ \DMEM~\memidx_i, \DOFFSET~\X{dinstr}^\ast_i~\END \}`, do: - i. Fail. + a. Assert: :math:`\memidx_i` is :math:`0`. -11. Assert: due to :ref:`validation `, the frame :math:`F` is now on the top of the stack. + b. Let :math:`n` be the length of the vector :math:`\data_i.\DINIT`. -12. Pop the frame from the stack. + c. :ref:`Execute ` the instruction sequence :math:`\X{dinstr}^\ast_i`. -13. For each :ref:`element segment ` :math:`\elem_i` in :math:`\module.\MELEM` whose :ref:`mode ` :math:`\elem_i.\EMODE` is of the form :math:`\EACTIVE~\{ \ETABLE~\tableidx_i, \EOFFSET~\X{eoexpr}_i \}`, do: + d. :ref:`Execute ` the instruction :math:`\I32.\CONST~0`. - a. For each :ref:`function index ` :math:`\funcidx_{ij}` in :math:`\elem_i.\EINIT` (starting with :math:`j = 0`), do: + e. :ref:`Execute ` the instruction :math:`\I32.\CONST~n`. - i. Assert: due to :ref:`validation `, :math:`\moduleinst.\MIFUNCS[\funcidx_{ij}]` exists. + f. :ref:`Execute ` the instruction :math:`\MEMORYINIT~i`. - ii. Let :math:`\funcaddr_{ij}` be the :ref:`function address ` :math:`\moduleinst.\MIFUNCS[\funcidx_{ij}]`. + g. :ref:`Execute ` the instruction :math:`\DATADROP~i`. - iii. Replace :math:`\tableinst_i.\TIELEM[\X{eo}_i + j]` with :math:`\funcaddr_{ij}`. +12. If the :ref:`start function ` :math:`\module.\MSTART` is not empty, then: -14. For each :ref:`data segment ` :math:`\data_i` in :math:`\module.\MDATA` whose :ref:`mode ` :math:`\data_i.\DMODE` is of the form :math:`\DACTIVE~\{ \DMEM~\memidx_i, \DOFFSET~\X{doexpr}_i \}`, do: + a. Let :math:`\start` be the :ref:`start function ` :math:`\module.\MSTART`. - a. For each :ref:`byte ` :math:`b_{ij}` in :math:`\data_i.\DINIT` (starting with :math:`j = 0`), do: + b. :ref:`Execute ` the instruction :math:`\CALL~\start.\SFUNC`. - i. Replace :math:`\meminst_i.\MIDATA[\X{do}_i + j]` with :math:`b_{ij}`. +13. Assert: due to :ref:`validation `, the frame :math:`F` is now on the top of the stack. -15. If the :ref:`start function ` :math:`\module.\MSTART` is not empty, then: - - a. Assert: due to :ref:`validation `, :math:`\moduleinst.\MIFUNCS[\module.\MSTART.\SFUNC]` exists. - - b. Let :math:`\funcaddr` be the :ref:`function address ` :math:`\moduleinst.\MIFUNCS[\module.\MSTART.\SFUNC]`. - - c. :ref:`Invoke ` the function instance at :math:`\funcaddr`. +14. Pop the frame :math:`F` from the stack. .. math:: ~\\ \begin{array}{@{}rcll} - \instantiate(S, \module, \externval^n) &=& S'; F; + \instantiate(S, \module, \externval^k) &=& S'; F; \begin{array}[t]{@{}l@{}} - (\INITELEM~\tableaddr~\X{eo}~\elem.\EINIT)^\ast \\ - (\INITDATA~\memaddr~\X{do}~\data.\DINIT)^\ast \\ - (\INVOKE~\funcaddr)^? \\ + \F{runelem}_0(\elem^n[0])~\dots~\F{runelem}_{n-1}(\elem^n[n-1]) \\ + \F{rundata}_0(\data^m[0])~\dots~\F{rundata}_{m-1}(\data^m[m-1]) \\ + (\CALL~\start.\SFUNC)^? \\ \end{array} \\ &(\iff - & \vdashmodule \module : \externtype_{\F{im}}^n \to \externtype_{\F{ex}}^\ast \\ - &\wedge& (S \vdashexternval \externval : \externtype)^n \\ - &\wedge& (\vdashexterntypematch \externtype \matches \externtype_{\F{im}})^n \\[1ex] + & \vdashmodule \module : \externtype_{\F{im}}^k \to \externtype_{\F{ex}}^\ast \\ + &\wedge& (S \vdashexternval \externval : \externtype)^k \\ + &\wedge& (\vdashexterntypematch \externtype \matches \externtype_{\F{im}})^k \\[1ex] &\wedge& \module.\MGLOBALS = \global^\ast \\ - &\wedge& \module.\MELEM = \elem^\ast \\ - &\wedge& \module.\MDATA = \data^\ast \\ + &\wedge& \module.\MELEMS = \elem^n \\ + &\wedge& \module.\MDATAS = \data^m \\ &\wedge& \module.\MSTART = \start^? \\[1ex] - &\wedge& S', \moduleinst = \allocmodule(S, \module, \externval^n, \val^\ast) \\ + &\wedge& S', \moduleinst = \allocmodule(S, \module, \externval^k, \val^\ast) \\ &\wedge& F = \{ \AMODULE~\moduleinst, \ALOCALS~\epsilon \} \\[1ex] &\wedge& (S'; F; \global.\GINIT \stepto^\ast S'; F; \val~\END)^\ast \\ &\wedge& (S'; F; \elem.\EOFFSET \stepto^\ast S'; F; \I32.\CONST~\X{eo}~\END)^\ast \\ &\wedge& (S'; F; \data.\DOFFSET \stepto^\ast S'; F; \I32.\CONST~\X{do}~\END)^\ast \\[1ex] - &\wedge& (\X{eo} + |\elem.\EINIT| \leq |S'.\STABLES[\tableaddr].\TIELEM|)^\ast \\ - &\wedge& (\X{do} + |\data.\DINIT| \leq |S'.\SMEMS[\memaddr].\MIDATA|)^\ast - \\[1ex] &\wedge& (\tableaddr = \moduleinst.\MITABLES[\elem.\ETABLE])^\ast \\ &\wedge& (\memaddr = \moduleinst.\MIMEMS[\data.\DMEM])^\ast \\ &\wedge& (\funcaddr = \moduleinst.\MIFUNCS[\start.\SFUNC])^?) - \\[2ex] - S; F; \INITELEM~a~i~\epsilon &\stepto& - S; F; \epsilon \\ - S; F; \INITELEM~a~i~(x_0~x^\ast) &\stepto& - S'; F; \INITELEM~a~(i+1)~x^\ast \\ && - (\iff S' = S \with \STABLES[a].\TIELEM[i] = F.\AMODULE.\MIFUNCS[x_0]) - \\[1ex] - S; F; \INITDATA~a~i~\epsilon &\stepto& - S; F; \epsilon \\ - S; F; \INITDATA~a~i~(b_0~b^\ast) &\stepto& - S'; F; \INITDATA~a~(i+1)~b^\ast \\ && - (\iff S' = S \with \SMEMS[a].\MIDATA[i] = b_0) + \end{array} + +where: + +.. math:: + \begin{array}{@{}l} + \F{runelem}_i(\{\ETYPE~\X{et}, \EINIT~\funcelem^n, \EMODE~\EPASSIVE\}) \quad=\quad \epsilon \\ + \F{runelem}_i(\{\ETYPE~\X{et}, \EINIT~\funcelem^n, \EMODE~\EACTIVE \{\ETABLE~0, \EOFFSET~\instr^\ast~\END\}\}) \quad=\\ \qquad + \instr^\ast~(\I32.\CONST~0)~(\I32.\CONST~n)~(\TABLEINIT~i)~(\ELEMDROP~i) \\[1ex] + \F{rundata}_i(\{\DINIT~b^n, DMODE~\DPASSIVE\}) \quad=\quad \epsilon \\ + \F{rundata}_i(\{\DINIT~b^n, DMODE~\DACTIVE \{\DMEM~0, \DOFFSET~\instr^\ast~\END\}\}) \quad=\\ \qquad + \instr^\ast~(\I32.\CONST~0)~(\I32.\CONST~n)~(\MEMORYINIT~i)~(\DATADROP~i) \\ \end{array} .. note:: diff --git a/document/core/exec/runtime.rst b/document/core/exec/runtime.rst index 0b66c091da..414a8baffd 100644 --- a/document/core/exec/runtime.rst +++ b/document/core/exec/runtime.rst @@ -489,8 +489,6 @@ Conventions pair:: abstract syntax; administrative instruction .. _syntax-trap: .. _syntax-invoke: -.. _syntax-init_elem: -.. _syntax-init_data: .. _syntax-table_get: .. _syntax-table_set: .. _syntax-instr-admin: @@ -509,8 +507,6 @@ In order to express the reduction of :ref:`traps `, :ref:`calls `, identified by its :ref:`address `. It unifies the handling of different forms of calls. -The |INITELEM| and |INITDATA| instructions perform initialization of :ref:`element ` and :ref:`data ` segments during module :ref:`instantiation `. - -.. note:: - The reason for splitting instantiation into individual reduction steps is to provide a semantics that is compatible with future extensions like threads. - The |TABLEGET| and |TABLESET| instructions are used to simplify the specification of the |TABLEINIT| and |TABLECOPY| instructions. .. note:: diff --git a/document/core/syntax/modules.rst b/document/core/syntax/modules.rst index 8f2037ec0f..8361644520 100644 --- a/document/core/syntax/modules.rst +++ b/document/core/syntax/modules.rst @@ -9,7 +9,7 @@ WebAssembly programs are organized into *modules*, which are the unit of deployment, loading, and compilation. A module collects definitions for :ref:`types `, :ref:`functions `, :ref:`tables `, :ref:`memories `, and :ref:`globals `. In addition, it can declare :ref:`imports ` and :ref:`exports ` -and provide initialization in the form of :ref:`active ` and :ref:`passive ` :ref:`data ` and :ref:`element ` segments, or a :ref:`start function `. +and provide initialization in the form of :ref:`data ` and :ref:`element ` segments, or a :ref:`start function `. .. math:: \begin{array}{lllll} @@ -19,8 +19,8 @@ and provide initialization in the form of :ref:`active ` and :ref \MTABLES~\vec(\table), \\&&&& \MMEMS~\vec(\mem), \\&&&& \MGLOBALS~\vec(\global), \\&&&& - \MELEM~\vec(\elem), \\&&&& - \MDATA~\vec(\data), \\&&&& + \MELEMS~\vec(\elem), \\&&&& + \MDATAS~\vec(\data), \\&&&& \MSTART~\start^?, \\&&&& \MIMPORTS~\vec(\import), \\&&&& \MEXPORTS~\vec(\export) \quad\} \\ @@ -255,10 +255,10 @@ Element Segments The initial contents of a table is uninitialized. *Element segments* can be used to initialize a subrange of a table from a static :ref:`vector ` of elements. -The |MELEM| component of a module defines a vector of element segments. +The |MELEMS| component of a module defines a vector of element segments. Each element segment defines an :ref:`element type ` and a corresponding list of :ref:`element expressions `. -Element segments have a mode that identifies them as either :ref:`passive ` or :ref:`active `. +Element segments have a mode that identifies them as either *passive* or *active*. A passive element segment's elements can be copied to a table using the |TABLEINIT| instruction. An active element segment copies its elements into a table during :ref:`instantiation `, as specified by a :ref:`table index ` and a :ref:`constant ` :ref:`expression ` defining an offset into that table. @@ -295,9 +295,9 @@ Data Segments The initial contents of a :ref:`memory ` are zero bytes. *Data segments* can be used to initialize a range of memory from a static :ref:`vector ` of :ref:`bytes `. -The |MDATA| component of a module defines a vector of data segments. +The |MDATAS| component of a module defines a vector of data segments. -Like element segments, data segments have a mode that identifies them as either :ref:`passive ` or :ref:`active `. +Like element segments, data segments have a mode that identifies them as either *passive* or *active*. A passive data segment's contents can be copied into a memory using the |MEMORYINIT| instruction. An active data segment copies its contents into a memory during :ref:`instantiation `, as specified by a :ref:`memory index ` and a :ref:`constant ` :ref:`expression ` defining an offset into that memory. diff --git a/document/core/syntax/types.rst b/document/core/syntax/types.rst index 9f045ba478..be81063622 100644 --- a/document/core/syntax/types.rst +++ b/document/core/syntax/types.rst @@ -181,25 +181,6 @@ Global Types \end{array} -.. index:: ! segtype, ! active, ! passive - pair: abstract syntax; segtype -.. _syntax-segtype: -.. _syntax-active: -.. _syntax-passive: - -Segment Types -~~~~~~~~~~~~~ - -*Segment types* classify :ref:`data segments ` and :ref:`element segments `, which can either be *passive* or *active*. - -.. math:: - \begin{array}{llll} - \production{segment type} & \segtype &::=& - \SPASSIVE ~|~ - \SACTIVE \\ - \end{array} - - .. index:: ! external type, function type, table type, memory type, global type, import, external value pair: abstract syntax; external type pair: external; type diff --git a/document/core/text/modules.rst b/document/core/text/modules.rst index 114d6b1787..91ebbd5628 100644 --- a/document/core/text/modules.rst +++ b/document/core/text/modules.rst @@ -641,8 +641,8 @@ The name serves a documentary role only. \X{gl}{:}\Tglobal_I &\Rightarrow& \{\MGLOBALS~\X{gl}\} \\ |& \X{ex}{:}\Texport_I &\Rightarrow& \{\MEXPORTS~\X{ex}\} \\ |& \X{st}{:}\Tstart_I &\Rightarrow& \{\MSTART~\X{st}\} \\ |& - \X{el}{:}\Telem_I &\Rightarrow& \{\MELEM~\X{el}\} \\ |& - \X{da}{:}\Tdata_I &\Rightarrow& \{\MDATA~\X{da}\} \\ + \X{el}{:}\Telem_I &\Rightarrow& \{\MELEMS~\X{el}\} \\ |& + \X{da}{:}\Tdata_I &\Rightarrow& \{\MDATAS~\X{da}\} \\ \end{array} \end{array} diff --git a/document/core/util/macros.def b/document/core/util/macros.def index 5756c05ad6..967c4d0b6b 100644 --- a/document/core/util/macros.def +++ b/document/core/util/macros.def @@ -179,9 +179,6 @@ .. |LMIN| mathdef:: \xref{syntax/types}{syntax-limits}{\K{min}} .. |LMAX| mathdef:: \xref{syntax/types}{syntax-limits}{\K{max}} -.. |SACTIVE| mathdef:: \xref{syntax/types}{syntax-segtype}{\K{active}} -.. |SPASSIVE| mathdef:: \xref{syntax/types}{syntax-segtype}{\K{passive}} - .. |ETFUNC| mathdef:: \xref{syntax/types}{syntax-externtype}{\K{func}} .. |ETTABLE| mathdef:: \xref{syntax/types}{syntax-externtype}{\K{table}} .. |ETMEM| mathdef:: \xref{syntax/types}{syntax-externtype}{\K{mem}} @@ -197,7 +194,6 @@ .. |tabletype| mathdef:: \xref{syntax/types}{syntax-tabletype}{\X{tabletype}} .. |elemtype| mathdef:: \xref{syntax/types}{syntax-elemtype}{\X{elemtype}} .. |memtype| mathdef:: \xref{syntax/types}{syntax-memtype}{\X{memtype}} -.. |segtype| mathdef:: \xref{syntax/types}{syntax-segtype}{\X{segtype}} .. |limits| mathdef:: \xref{syntax/types}{syntax-limits}{\X{limits}} .. |mut| mathdef:: \xref{syntax/types}{syntax-mut}{\X{mut}} @@ -248,8 +244,8 @@ .. |MGLOBALS| mathdef:: \xref{syntax/modules}{syntax-module}{\K{globals}} .. |MIMPORTS| mathdef:: \xref{syntax/modules}{syntax-module}{\K{imports}} .. |MEXPORTS| mathdef:: \xref{syntax/modules}{syntax-module}{\K{exports}} -.. |MDATA| mathdef:: \xref{syntax/modules}{syntax-module}{\K{data}} -.. |MELEM| mathdef:: \xref{syntax/modules}{syntax-module}{\K{elem}} +.. |MDATAS| mathdef:: \xref{syntax/modules}{syntax-module}{\K{datas}} +.. |MELEMS| mathdef:: \xref{syntax/modules}{syntax-module}{\K{elems}} .. |MSTART| mathdef:: \xref{syntax/modules}{syntax-module}{\K{start}} .. |FTYPE| mathdef:: \xref{syntax/modules}{syntax-func}{\K{type}} @@ -764,8 +760,8 @@ .. |CTABLES| mathdef:: \xref{valid/conventions}{context}{\K{tables}} .. |CMEMS| mathdef:: \xref{valid/conventions}{context}{\K{mems}} .. |CGLOBALS| mathdef:: \xref{valid/conventions}{context}{\K{globals}} -.. |CELEM| mathdef:: \xref{valid/conventions}{context}{\K{elem}} -.. |CDATA| mathdef:: \xref{valid/conventions}{context}{\K{data}} +.. |CELEMS| mathdef:: \xref{valid/conventions}{context}{\K{elems}} +.. |CDATAS| mathdef:: \xref{valid/conventions}{context}{\K{datas}} .. |CLOCALS| mathdef:: \xref{valid/conventions}{context}{\K{locals}} .. |CLABELS| mathdef:: \xref{valid/conventions}{context}{\K{labels}} .. |CRETURN| mathdef:: \xref{valid/conventions}{context}{\K{return}} @@ -934,8 +930,6 @@ .. |TRAP| mathdef:: \xref{exec/runtime}{syntax-trap}{\K{trap}} .. |INVOKE| mathdef:: \xref{exec/runtime}{syntax-invoke}{\K{invoke}} -.. |INITELEM| mathdef:: \xref{exec/runtime}{syntax-init_elem}{\K{init\_elem}} -.. |INITDATA| mathdef:: \xref{exec/runtime}{syntax-init_data}{\K{init\_data}} .. |TABLEGET| mathdef:: \xref{exec/runtime}{syntax-table_get}{\K{table.get}} .. |TABLESET| mathdef:: \xref{exec/runtime}{syntax-table_set}{\K{table.set}} diff --git a/document/core/valid/conventions.rst b/document/core/valid/conventions.rst index 4e04ce289a..7f132d7ea3 100644 --- a/document/core/valid/conventions.rst +++ b/document/core/valid/conventions.rst @@ -38,8 +38,8 @@ which collects relevant information about the surrounding :ref:`module ` :math: & \CTABLES & \tabletype^\ast, \\ & \CMEMS & \memtype^\ast, \\ & \CGLOBALS & \globaltype^\ast, \\ - & \CELEM & \segtype^\ast, \\ - & \CDATA & \segtype^\ast, \\ + & \CELEMS & {\ok}^\ast, \\ + & \CDATAS & {\ok}^\ast, \\ & \CLOCALS & \valtype^\ast, \\ & \CLABELS & \resulttype^\ast, \\ & \CRETURN & \resulttype^? ~\} \\ diff --git a/document/core/valid/instructions.rst b/document/core/valid/instructions.rst index 6aef34abbf..806dde7171 100644 --- a/document/core/valid/instructions.rst +++ b/document/core/valid/instructions.rst @@ -330,7 +330,7 @@ Table Instructions * The table :math:`C.\CTABLES[0]` must be defined in the context. -* The element segment :math:`C.\CELEM[x]` must be defined in the context. +* The element segment :math:`C.\CELEMS[x]` must be defined in the context. * Then the instruction is valid with type :math:`[\I32~\I32~\I32] \to []`. @@ -338,7 +338,7 @@ Table Instructions \frac{ C.\CTABLES[0] = \tabletype \qquad - C.\CELEM[x] = \segtype + C.\CELEMS[x] = {\ok} }{ C \vdashinstr \TABLEINIT~x : [\I32~\I32~\I32] \to [] } @@ -349,13 +349,13 @@ Table Instructions :math:`\ELEMDROP~x` ................... -* The element segment :math:`C.\CELEM[x]` must be defined in the context. +* The element segment :math:`C.\CELEMS[x]` must be defined in the context. * Then the instruction is valid with type :math:`[] \to []`. .. math:: \frac{ - C.\CELEM[x] = \segtype + C.\CELEMS[x] = {\ok} }{ C \vdashinstr \ELEMDROP~x : [] \to [] } @@ -527,7 +527,7 @@ Memory Instructions * The memory :math:`C.\CMEMS[0]` must be defined in the context. -* The data segment :math:`C.\CDATA[x]` must be defined in the context. +* The data segment :math:`C.\CDATAS[x]` must be defined in the context. * Then the instruction is valid with type :math:`[\I32~\I32~\I32] \to []`. @@ -535,7 +535,7 @@ Memory Instructions \frac{ C.\CMEMS[0] = \memtype \qquad - C.\CDATA[x] = \segtype + C.\CDATAS[x] = {\ok} }{ C \vdashinstr \MEMORYINIT~x : [\I32~\I32~\I32] \to [] } @@ -546,13 +546,13 @@ Memory Instructions :math:`\DATADROP~x` ................... -* The data segment :math:`C.\CDATA[x]` must be defined in the context. +* The data segment :math:`C.\CDATAS[x]` must be defined in the context. * Then the instruction is valid with type :math:`[] \to []`. .. math:: \frac{ - C.\CDATA[x] = \segtype + C.\CDATAS[x] = {\ok} }{ C \vdashinstr \DATADROP~x : [] \to [] } diff --git a/document/core/valid/modules.rst b/document/core/valid/modules.rst index 408ae81361..cd65e527c5 100644 --- a/document/core/valid/modules.rst +++ b/document/core/valid/modules.rst @@ -145,7 +145,7 @@ Globals :math:`\global` are classified by :ref:`global types Element Segments ~~~~~~~~~~~~~~~~ -Element segments :math:`\elem` are classified by :ref:`segment types `, as determined by their :ref:`mode `. +Element segments :math:`\elem` are not classified by any type but merely checked for well-formedness. :math:`\{ \ETYPE~et, \EINIT~e^\ast, \EMODE~\elemmode \}` ........................................................ @@ -154,18 +154,18 @@ Element segments :math:`\elem` are classified by :ref:`segment types `. -* The element mode :math:`\elemmode` must valid with type :math:`\segtype`. +* The element mode :math:`\elemmode` must be valid. -* Then the element segment is valid with type :math:`\segtype`. +* Then the element segment is valid. .. math:: \frac{ (C \vdashelemexpr e \ok)^\ast \qquad - C; \X{et} \vdashelemmode \elemmode : \segtype + C; \X{et} \vdashelemmode \elemmode \ok }{ - C \vdashelem \{ \ETYPE~et, \EINIT~e^\ast, \EMODE~\elemmode \} : \segtype + C \vdashelem \{ \ETYPE~et, \EINIT~e^\ast, \EMODE~\elemmode \} \ok } @@ -198,12 +198,12 @@ Element segments :math:`\elem` are classified by :ref:`segment types `. -* Then the element mode is valid with type |SACTIVE|. +* Then the element mode is valid. .. math:: \frac{ @@ -232,7 +232,7 @@ Element segments :math:`\elem` are classified by :ref:`segment types `, as determined by their :ref:`mode `. +Data segments :math:`\data` are not classified by any type but merely checked for well-formedness. :math:`\{ \DINIT~b^\ast, \DMODE~\datamode \}` .................................................... -* The data mode :math:`\datamode` must valid with type :math:`\segtype`. +* The data mode :math:`\datamode` must be valid. -* Then the data segment is valid with type :math:`\segtype`. +* Then the data segment is valid. .. math:: \frac{ - C \vdashdatamode \datamode : \segtype + C \vdashdatamode \datamode \ok }{ - C \vdashdata \{ \DINIT~b^\ast, \DMODE~\datamode \} : \segtype + C \vdashdata \{ \DINIT~b^\ast, \DMODE~\datamode \} \ok } @@ -268,12 +268,12 @@ Data segments :math:`\data` are classified by :ref:`segment types `. -* Then the data mode is valid with type |SACTIVE|. +* Then the data mode is valid. .. math:: \frac{ @@ -296,7 +296,7 @@ Data segments :math:`\data` are classified by :ref:`segment types ` :math:`\X{it}^\ast` and the internal :ref:`global types ` :math:`\X{gt}^\ast` as determined below, - * :math:`C.\CELEM` is :math:`\X{est}^\ast`, with :ref:`segment types ` :math:`\X{est}^\ast` as determined below, + * :math:`C.\CELEMS` is :math:`{\ok}^{N_e}`, where :math:`N_e` is the length of the vector :math:`\module.\MELEMS`, - * :math:`C.\CDATA` is :math:`\X{dst}^\ast`, with :ref:`segment types ` :math:`\X{dst}^\ast` as determined below, + * :math:`C.\CDATAS` is :math:`{\ok}^{N_d}`, where :math:`N_d` is the length of the vector :math:`\module.\MDATAS`, * :math:`C.\CLOCALS` is empty, @@ -568,11 +568,11 @@ Instead, the context :math:`C` for validation of the module's content is constru * Under the context :math:`C'`, the definition :math:`\global_i` must be :ref:`valid ` with a :ref:`global type ` :math:`\X{gt}_i`. - * For each :math:`\elem_i` in :math:`\module.\MELEM`, - the segment :math:`\elem_i` must be :ref:`valid ` with a :ref:`segment type ` :math:`\X{est}_i`. + * For each :math:`\elem_i` in :math:`\module.\MELEMS`, + the segment :math:`\elem_i` must be :ref:`valid `. - * For each :math:`\data_i` in :math:`\module.\MDATA`, - the segment :math:`\data_i` must be :ref:`valid ` with a :ref:`segment type ` :math:`\X{dst}_i`. + * For each :math:`\data_i` in :math:`\module.\MDATAS`, + the segment :math:`\data_i` must be :ref:`valid `. * If :math:`\module.\MSTART` is non-empty, then :math:`\module.\MSTART` must be :ref:`valid `. @@ -597,10 +597,6 @@ Instead, the context :math:`C` for validation of the module's content is constru * Let :math:`\X{gt}^\ast` be the concatenation of the internal :ref:`global types ` :math:`\X{gt}_i`, in index order. -* Let :math:`\X{est}^\ast` be the concatenation of the :ref:`segment types ` :math:`\X{est}_i`, in index order. - -* Let :math:`\X{dst}^\ast` be the concatenation of the :ref:`segment types ` :math:`\X{dst}_i`, in index order. - * Let :math:`\X{it}^\ast` be the concatenation of :ref:`external types ` :math:`\X{it}_i` of the imports, in index order. * Let :math:`\X{et}^\ast` be the concatenation of :ref:`external types ` :math:`\X{et}_i` of the exports, in index order. @@ -620,9 +616,9 @@ Instead, the context :math:`C` for validation of the module's content is constru \quad (C' \vdashglobal \global : \X{gt})^\ast \\ - (C \vdashelem \elem : \X{est})^\ast + (C \vdashelem \elem \ok)^{N_e} \quad - (C \vdashdata \data : \X{dst})^\ast + (C \vdashdata \data \ok)^{N_d} \quad (C \vdashstart \start \ok)^? \quad @@ -638,7 +634,7 @@ Instead, the context :math:`C` for validation of the module's content is constru \qquad \X{igt}^\ast = \etglobals(\X{it}^\ast) \\ - C = \{ \CTYPES~\functype^\ast, \CFUNCS~\X{ift}^\ast~\X{ft}^\ast, \CTABLES~\X{itt}^\ast~\X{tt}^\ast, \CMEMS~\X{imt}^\ast~\X{mt}^\ast, \CGLOBALS~\X{igt}^\ast~\X{gt}^\ast, \CELEM~\X{est}^\ast, \CDATA~\X{dst}^\ast \} + C = \{ \CTYPES~\functype^\ast, \CFUNCS~\X{ift}^\ast~\X{ft}^\ast, \CTABLES~\X{itt}^\ast~\X{tt}^\ast, \CMEMS~\X{imt}^\ast~\X{mt}^\ast, \CGLOBALS~\X{igt}^\ast~\X{gt}^\ast, \CELEMS~{\ok}^{N_e}, \CDATAS~{\ok}^{N_d} \} \\ C' = \{ \CGLOBALS~\X{igt}^\ast \} \qquad @@ -656,8 +652,8 @@ Instead, the context :math:`C` for validation of the module's content is constru \MTABLES~\table^\ast, \MMEMS~\mem^\ast, \MGLOBALS~\global^\ast, \\ - \MELEM~\elem^\ast, - \MDATA~\data^\ast, + \MELEMS~\elem^\ast, + \MDATAS~\data^\ast, \MSTART~\start^?, \MIMPORTS~\import^\ast, \MEXPORTS~\export^\ast \} : \X{it}^\ast \to \X{et}^\ast \\ diff --git a/interpreter/exec/eval.ml b/interpreter/exec/eval.ml index 90c0ddcd3a..5aaf42ad54 100644 --- a/interpreter/exec/eval.ml +++ b/interpreter/exec/eval.ml @@ -405,11 +405,6 @@ let eval_const (inst : module_inst) (const : const) : value = | [v] -> v | vs -> Crash.error const.at "wrong number of results on stack" -let i32 (v : value) at = - match v with - | I32 i -> i - | _ -> Crash.error at "type error: i32 value expected" - (* Modules *) @@ -447,45 +442,12 @@ let elem_list inst init = in List.map to_elem init let create_elem (inst : module_inst) (seg : elem_segment) : elem_inst = - let {etype; einit; emode} = seg.it in - match emode.it with - | Passive -> ref (Some (elem_list inst einit)) - | Active _ -> ref None + let {etype; einit; _} = seg.it in + ref (Some (elem_list inst einit)) let create_data (inst : module_inst) (seg : data_segment) : data_inst = - let {dinit; dmode} = seg.it in - match dmode.it with - | Passive -> ref (Some dinit) - | Active _ -> ref None - - -let init_func (inst : module_inst) (func : func_inst) = - match func with - | Func.AstFunc (_, inst_ref, _) -> inst_ref := inst - | _ -> assert false - -let init_table (inst : module_inst) (seg : elem_segment) = - let {etype; einit; emode} = seg.it in - match emode.it with - | Passive -> () - | Active {index; offset} -> - let refs = elem_list inst einit in - let tab = table inst index in - let i = i32 (eval_const inst offset) offset.at in - let n = Int32.of_int (List.length einit) in - (try Table.init tab refs i 0l n - with Table.Bounds -> Link.error seg.at "elements segment does not fit table") - -let init_memory (inst : module_inst) (seg : data_segment) = - let {dinit; dmode} = seg.it in - match dmode.it with - | Passive -> () - | Active {index; offset} -> - let mem = memory inst index in - let i = i32 (eval_const inst offset) offset.at in - let n = Int32.of_int (String.length dinit) in - (try Memory.init mem dinit (I64_convert.extend_i32_u i) 0L n - with Memory.Bounds -> Link.error seg.at "data segment does not fit memory") + let {dinit; _} = seg.it in + ref (Some dinit) let add_import (m : module_) (ext : extern) (im : import) (inst : module_inst) @@ -498,6 +460,40 @@ let add_import (m : module_) (ext : extern) (im : import) (inst : module_inst) | ExternMemory mem -> {inst with memories = mem :: inst.memories} | ExternGlobal glob -> {inst with globals = glob :: inst.globals} +let init_func (inst : module_inst) (func : func_inst) = + match func with + | Func.AstFunc (_, inst_ref, _) -> inst_ref := inst + | _ -> assert false + +let run_elem i elem = + match elem.it.emode.it with + | Passive -> [] + | Active {index; offset} -> + let at = elem.it.emode.at in + let x = i @@ at in + offset.it @ [ + Const (I32 0l @@ at) @@ at; + Const (I32 (Lib.List32.length elem.it.einit) @@ at) @@ at; + TableInit x @@ at; + ElemDrop x @@ at + ] + +let run_data i data = + match data.it.dmode.it with + | Passive -> [] + | Active {index; offset} -> + let at = data.it.dmode.at in + let x = i @@ at in + offset.it @ [ + Const (I32 0l @@ at) @@ at; + Const (I32 (Int32.of_int (String.length data.it.dinit)) @@ at) @@ at; + MemoryInit x @@ at; + DataDrop x @@ at + ] + +let run_start start = + [Call start @@ start.at] + let init (m : module_) (exts : extern list) : module_inst = let { imports; tables; memories; globals; funcs; types; @@ -527,7 +523,8 @@ let init (m : module_) (exts : extern list) : module_inst = } in List.iter (init_func inst) fs; - List.iter (init_table inst) elems; - List.iter (init_memory inst) datas; - Lib.Option.app (fun x -> ignore (invoke (func inst x) [])) start; + let es_elem = List.concat (Lib.List32.mapi run_elem elems) in + let es_data = List.concat (Lib.List32.mapi run_data datas) in + let es_start = Lib.Option.get (Lib.Option.map run_start start) [] in + ignore (eval (config inst [] (List.map plain (es_elem @ es_data @ es_start)))); inst diff --git a/interpreter/syntax/types.ml b/interpreter/syntax/types.ml index ea59848b74..00b76f6c16 100644 --- a/interpreter/syntax/types.ml +++ b/interpreter/syntax/types.ml @@ -10,7 +10,6 @@ type mutability = Immutable | Mutable type table_type = TableType of Int32.t limits * elem_type type memory_type = MemoryType of Int32.t limits type global_type = GlobalType of value_type * mutability -type segment_type = PassiveType | ActiveType type extern_type = | ExternFuncType of func_type | ExternTableType of table_type diff --git a/interpreter/util/lib.ml b/interpreter/util/lib.ml index d8c33a1a0f..eeb198d3d6 100644 --- a/interpreter/util/lib.ml +++ b/interpreter/util/lib.ml @@ -125,6 +125,11 @@ struct | 0l, _ -> xs | n, _::xs' when n > 0l -> drop (Int32.sub n 1l) xs' | _ -> failwith "drop" + + let rec mapi f xs = mapi' f 0l xs + and mapi' f i = function + | [] -> [] + | x::xs -> f i x :: mapi' f (Int32.add i 1l) xs end module Array32 = diff --git a/interpreter/util/lib.mli b/interpreter/util/lib.mli index de24c295d4..a152e6e4d9 100644 --- a/interpreter/util/lib.mli +++ b/interpreter/util/lib.mli @@ -30,6 +30,7 @@ sig val nth : 'a list -> int32 -> 'a (* raises Failure *) val take : int32 -> 'a list -> 'a list (* raises Failure *) val drop : int32 -> 'a list -> 'a list (* raises Failure *) + val mapi : (int32 -> 'a -> 'b) -> 'a list -> 'b list end module Array32 : diff --git a/interpreter/valid/valid.ml b/interpreter/valid/valid.ml index 1a33d35d26..76e0d7153a 100644 --- a/interpreter/valid/valid.ml +++ b/interpreter/valid/valid.ml @@ -21,8 +21,8 @@ type context = tables : table_type list; memories : memory_type list; globals : global_type list; - datas : segment_type list; - elems : segment_type list; + datas : unit list; + elems : unit list; locals : value_type list; results : value_type list; labels : stack_type list; @@ -493,11 +493,6 @@ let check_export (c : context) (set : NameSet.t) (ex : export) : NameSet.t = require (not (NameSet.mem name set)) ex.at "duplicate export name"; NameSet.add name set -let segment_type mode = - match mode.it with - | Passive -> PassiveType - | Active _ -> ActiveType - let check_module (m : module_) = let { types; imports; tables; memories; globals; funcs; start; elems; datas; @@ -512,8 +507,8 @@ let check_module (m : module_) = funcs = c0.funcs @ List.map (fun f -> type_ c0 f.it.ftype) funcs; tables = c0.tables @ List.map (fun tab -> tab.it.ttype) tables; memories = c0.memories @ List.map (fun mem -> mem.it.mtype) memories; - elems = List.map (fun elem -> segment_type elem.it.emode) elems; - datas = List.map (fun data -> segment_type data.it.dmode) datas; + elems = List.map (fun _ -> ()) elems; + datas = List.map (fun _ -> ()) datas; } in let c = diff --git a/test/core/data.wast b/test/core/data.wast index bc94a8f217..80a2704e3c 100644 --- a/test/core/data.wast +++ b/test/core/data.wast @@ -158,28 +158,28 @@ ;; Invalid bounds for data -(assert_unlinkable +(assert_trap (module (memory 0) (data (i32.const 0) "a") ) - "data segment does not fit" + "out of bounds" ) -(assert_unlinkable +(assert_trap (module (memory 0 0) (data (i32.const 0) "a") ) - "data segment does not fit" + "out of bounds" ) -(assert_unlinkable +(assert_trap (module (memory 0 1) (data (i32.const 0) "a") ) - "data segment does not fit" + "out of bounds" ) ;; Writing 0 bytes outside of bounds is allowed now. @@ -199,77 +199,77 @@ (memory 0x10000) (data (i32.const 0xffffffff) "ab") ) - "" ;; either out of memory or segment does not fit + "" ;; either out of memory or out of bounds ;) -(assert_unlinkable +(assert_trap (module (global (import "spectest" "global_i32") i32) (memory 0) (data (global.get 0) "a") ) - "data segment does not fit" + "out of bounds" ) -(assert_unlinkable +(assert_trap (module (memory 1 2) (data (i32.const 0x1_0000) "a") ) - "data segment does not fit" + "out of bounds" ) -(assert_unlinkable +(assert_trap (module (import "spectest" "memory" (memory 1)) (data (i32.const 0x1_0000) "a") ) - "data segment does not fit" + "out of bounds" ) -(assert_unlinkable +(assert_trap (module (memory 2) (data (i32.const 0x2_0000) "a") ) - "data segment does not fit" + "out of bounds" ) -(assert_unlinkable +(assert_trap (module (memory 2 3) (data (i32.const 0x2_0000) "a") ) - "data segment does not fit" + "out of bounds" ) -(assert_unlinkable +(assert_trap (module (memory 1) (data (i32.const -1) "a") ) - "data segment does not fit" + "out of bounds" ) -(assert_unlinkable +(assert_trap (module (import "spectest" "memory" (memory 1)) (data (i32.const -1) "a") ) - "data segment does not fit" + "out of bounds" ) -(assert_unlinkable +(assert_trap (module (memory 2) (data (i32.const -100) "a") ) - "data segment does not fit" + "out of bounds" ) -(assert_unlinkable +(assert_trap (module (import "spectest" "memory" (memory 1)) (data (i32.const -100) "a") ) - "data segment does not fit" + "out of bounds" ) ;; Data without memory diff --git a/test/core/elem.wast b/test/core/elem.wast index 4dd3e7822c..7d2e42490e 100644 --- a/test/core/elem.wast +++ b/test/core/elem.wast @@ -162,31 +162,31 @@ ;; Invalid bounds for elements -(assert_unlinkable +(assert_trap (module (table 0 funcref) (func $f) (elem (i32.const 0) $f) ) - "elements segment does not fit" + "out of bounds" ) -(assert_unlinkable +(assert_trap (module (table 0 0 funcref) (func $f) (elem (i32.const 0) $f) ) - "elements segment does not fit" + "out of bounds" ) -(assert_unlinkable +(assert_trap (module (table 0 1 funcref) (func $f) (elem (i32.const 0) $f) ) - "elements segment does not fit" + "out of bounds" ) ;; Writing 0 elems outside of bounds is allowed now. @@ -195,72 +195,72 @@ (elem (i32.const 1)) ) -(assert_unlinkable +(assert_trap (module (table 10 funcref) (func $f) (elem (i32.const 10) $f) ) - "elements segment does not fit" + "out of bounds" ) -(assert_unlinkable +(assert_trap (module (import "spectest" "table" (table 10 funcref)) (func $f) (elem (i32.const 10) $f) ) - "elements segment does not fit" + "out of bounds" ) -(assert_unlinkable +(assert_trap (module (table 10 20 funcref) (func $f) (elem (i32.const 10) $f) ) - "elements segment does not fit" + "out of bounds" ) -(assert_unlinkable +(assert_trap (module (import "spectest" "table" (table 10 funcref)) (func $f) (elem (i32.const 10) $f) ) - "elements segment does not fit" + "out of bounds" ) -(assert_unlinkable +(assert_trap (module (table 10 funcref) (func $f) (elem (i32.const -1) $f) ) - "elements segment does not fit" + "out of bounds" ) -(assert_unlinkable +(assert_trap (module (import "spectest" "table" (table 10 funcref)) (func $f) (elem (i32.const -1) $f) ) - "elements segment does not fit" + "out of bounds" ) -(assert_unlinkable +(assert_trap (module (table 10 funcref) (func $f) (elem (i32.const -10) $f) ) - "elements segment does not fit" + "out of bounds" ) -(assert_unlinkable +(assert_trap (module (import "spectest" "table" (table 10 funcref)) (func $f) (elem (i32.const -10) $f) ) - "elements segment does not fit" + "out of bounds" ) ;; Element without table diff --git a/test/core/linking.wast b/test/core/linking.wast index 5edb6eb87d..2d92078f9a 100644 --- a/test/core/linking.wast +++ b/test/core/linking.wast @@ -203,13 +203,13 @@ ) (assert_return (get $G2 "g") (i32.const 5)) -(assert_unlinkable +(assert_trap (module (table (import "Mt" "tab") 0 funcref) (elem (i32.const 10) $f) (func $f) ) - "elements segment does not fit" + "out of bounds" ) (assert_unlinkable @@ -226,26 +226,26 @@ ;; Unlike in the v1 spec, the elements stored before an out-of-bounds access ;; persist after the instantiation failure. -(assert_unlinkable +(assert_trap (module (table (import "Mt" "tab") 10 funcref) (func $f (result i32) (i32.const 0)) (elem (i32.const 7) $f) (elem (i32.const 12) $f) ;; out of bounds ) - "elements segment does not fit" + "out of bounds" ) (assert_return (invoke $Mt "call" (i32.const 7)) (i32.const 0)) -(assert_unlinkable +(assert_trap (module (table (import "Mt" "tab") 10 funcref) (func $f (result i32) (i32.const 0)) (elem (i32.const 7) $f) (memory 1) - (data (i32.const 0x10000) "d") ;; out of bounds + (data (i32.const 0x10000) "d") ;; out of bounds ) - "data segment does not fit" + "out of bounds" ) (assert_return (invoke $Mt "call" (i32.const 7)) (i32.const 0)) @@ -297,12 +297,12 @@ (data (i32.const 0xffff) "a") ) -(assert_unlinkable +(assert_trap (module (memory (import "Mm" "mem") 0) (data (i32.const 0x10000) "a") ) - "data segment does not fit" + "out of bounds" ) (module $Pm @@ -335,25 +335,25 @@ ;; Unlike in v1 spec, bytes written before an out-of-bounds access persist ;; after the instantiation failure. -(assert_unlinkable +(assert_trap (module (memory (import "Mm" "mem") 1) (data (i32.const 0) "abc") (data (i32.const 0x50000) "d") ;; out of bounds ) - "data segment does not fit" + "out of bounds" ) (assert_return (invoke $Mm "load" (i32.const 0)) (i32.const 97)) -(assert_unlinkable +(assert_trap (module (memory (import "Mm" "mem") 1) (data (i32.const 0) "abc") (table 0 funcref) (func) - (elem (i32.const 0) 0) ;; out of bounds + (elem (i32.const 0) 0) ;; out of bounds ) - "elements segment does not fit" + "out of bounds" ) (assert_return (invoke $Mm "load" (i32.const 0)) (i32.const 97)) From 8db23a96b01510a49b69a50499517b1f6ead0d26 Mon Sep 17 00:00:00 2001 From: Andreas Rossberg Date: Mon, 7 Oct 2019 11:53:53 +0200 Subject: [PATCH 126/199] [interpreter] Use small-step semantics (#115) Implement bulk memory operations in small-step semantics, as in spec. Minor fixes: - In spec, memory.copy was missing use of \vconst in the backwards case - In interpreter & test, memory.init still trapped if segment has been dropped but length parameter was 0. --- document/core/exec/instructions.rst | 7 +- interpreter/exec/eval.ml | 109 +++++++++++++++++++++++----- interpreter/runtime/memory.ml | 31 -------- interpreter/runtime/memory.mli | 5 -- interpreter/util/source.ml | 1 + interpreter/util/source.mli | 1 + test/core/bulk.wast | 20 ++--- 7 files changed, 109 insertions(+), 65 deletions(-) diff --git a/document/core/exec/instructions.rst b/document/core/exec/instructions.rst index db73b5bee8..d2b339044f 100644 --- a/document/core/exec/instructions.rst +++ b/document/core/exec/instructions.rst @@ -695,6 +695,9 @@ Memory Instructions (\iff n > 1) \\ \end{array} +.. note:: + The use of the :math:`\vconst_t` meta function in the rules for this and the following instructions ensures that an overflowing index turns into a :ref:`trap `. + .. _exec-memory.init: @@ -936,12 +939,12 @@ Memory Instructions \end{array} \\ \end{array} \\ \qquad - (\iff dst <= src \wedge cnt > 1) + (\iff dst \leq src \wedge cnt > 1) \\[1ex] \begin{array}{lcl@{\qquad}l} S; F; (\I32.\CONST~dst)~(\I32.\CONST~src)~(\I32.\CONST~cnt)~\MEMORYCOPY &\stepto& S; F; \begin{array}[t]{@{}l@{}} - (\I32.\CONST~(dst+cnt-1))~(\I32.\CONST~(src+cnt-1))~(\I32.\CONST~1)~\MEMORYCOPY \\ + (\vconst_{\I32}(dst+cnt-1))~(\vconst_{\I32}(src+cnt-1))~(\I32.\CONST~1)~\MEMORYCOPY \\ (\I32.\CONST~dst)~(\I32.\CONST~src)~(\I32.\CONST~(cnt-1))~\MEMORYCOPY \\ \end{array} \\ \end{array} diff --git a/interpreter/exec/eval.ml b/interpreter/exec/eval.ml index 5aaf42ad54..48e923cd46 100644 --- a/interpreter/exec/eval.ml +++ b/interpreter/exec/eval.ml @@ -117,6 +117,10 @@ let drop n (vs : 'a stack) at = * c : config *) +let const_i32_add i j at msg = + let k = I32.add i j in + if I32.lt_u k i then Trapping msg else Plain (Const (I32 k @@ at)) + let rec step (c : config) : config = let {frame; code = vs, es; _} = c in let e = List.hd es in @@ -198,11 +202,13 @@ let rec step (c : config) : config = with Global.NotMutable -> Crash.error e.at "write to immutable global" | Global.Type -> Crash.error e.at "type mismatch at global write") + (* TODO: turn into small-step, but needs reference values *) | TableCopy, I32 n :: I32 s :: I32 d :: vs' -> let tab = table frame.inst (0l @@ e.at) in (try Table.copy tab d s n; vs', [] with exn -> vs', [Trapping (table_error e.at exn) @@ e.at]) + (* TODO: turn into small-step, but needs reference values *) | TableInit x, I32 n :: I32 s :: I32 d :: vs' -> let tab = table frame.inst (0l @@ e.at) in (match !(elem frame.inst x) with @@ -253,30 +259,97 @@ let rec step (c : config) : config = with Memory.SizeOverflow | Memory.SizeLimit | Memory.OutOfMemory -> -1l in I32 result :: vs', [] - | MemoryFill, I32 n :: I32 b :: I32 i :: vs' -> - let mem = memory frame.inst (0l @@ e.at) in - let addr = I64_convert.extend_i32_u i in - (try Memory.fill mem addr (Int32.to_int b) n; vs', [] - with exn -> vs', [Trapping (memory_error e.at exn) @@ e.at]) + | MemoryFill, I32 0l :: v :: I32 i :: vs' -> + vs', [] - | MemoryCopy, I32 n :: I32 s :: I32 d :: vs' -> - let mem = memory frame.inst (0l @@ e.at) in - let dst = I64_convert.extend_i32_u d in - let src = I64_convert.extend_i32_u s in - (try Memory.copy mem dst src n; vs', [] - with exn -> vs', [Trapping (memory_error e.at exn) @@ e.at]) + | MemoryFill, I32 1l :: v :: I32 i :: vs' -> + vs', List.map (at e.at) [ + Plain (Const (I32 i @@ e.at)); + Plain (Const (v @@ e.at)); + Plain (Store + {ty = I32Type; align = 0; offset = 0l; sz = Some Memory.Pack8}); + ] + + | MemoryFill, I32 n :: v :: I32 i :: vs' -> + vs', List.map (at e.at) [ + Plain (Const (I32 i @@ e.at)); + Plain (Const (v @@ e.at)); + Plain (Const (I32 1l @@ e.at)); + Plain (MemoryFill); + const_i32_add i 1l e.at (memory_error e.at Memory.Bounds); + Plain (Const (v @@ e.at)); + Plain (Const (I32 (I32.sub n 1l) @@ e.at)); + Plain (MemoryFill); + ] + + | MemoryCopy, I32 0l :: I32 s :: I32 d :: vs' -> + vs', [] - | MemoryInit x, I32 n :: I32 s :: I32 d :: vs' -> - let mem = memory frame.inst (0l @@ e.at) in + | MemoryCopy, I32 1l :: I32 s :: I32 d :: vs' -> + vs', List.map (at e.at) [ + Plain (Const (I32 d @@ e.at)); + Plain (Const (I32 s @@ e.at)); + Plain (Load + {ty = I32Type; align = 0; offset = 0l; sz = Some Memory.(Pack8, ZX)}); + Plain (Store + {ty = I32Type; align = 0; offset = 0l; sz = Some Memory.Pack8}); + ] + + | MemoryCopy, I32 n :: I32 s :: I32 d :: vs' when d <= s -> + vs', List.map (at e.at) [ + Plain (Const (I32 d @@ e.at)); + Plain (Const (I32 s @@ e.at)); + Plain (Const (I32 1l @@ e.at)); + Plain (MemoryCopy); + const_i32_add d 1l e.at (memory_error e.at Memory.Bounds); + const_i32_add s 1l e.at (memory_error e.at Memory.Bounds); + Plain (Const (I32 (I32.sub n 1l) @@ e.at)); + Plain (MemoryCopy); + ] + + | MemoryCopy, I32 n :: I32 s :: I32 d :: vs' when s < d -> + vs', List.map (at e.at) [ + const_i32_add d (I32.sub n 1l) e.at (memory_error e.at Memory.Bounds); + const_i32_add s (I32.sub n 1l) e.at (memory_error e.at Memory.Bounds); + Plain (Const (I32 1l @@ e.at)); + Plain (MemoryCopy); + Plain (Const (I32 d @@ e.at)); + Plain (Const (I32 s @@ e.at)); + Plain (Const (I32 (I32.sub n 1l) @@ e.at)); + Plain (MemoryCopy); + ] + + | MemoryInit x, I32 0l :: I32 s :: I32 d :: vs' -> + vs', [] + + | MemoryInit x, I32 1l :: I32 s :: I32 d :: vs' -> (match !(data frame.inst x) with + | None -> + vs', [Trapping "data segment dropped" @@ e.at] + | Some bs when Int32.to_int s >= String.length bs -> + vs', [Trapping "out of bounds data segment access" @@ e.at] | Some bs -> - let dst = I64_convert.extend_i32_u d in - let src = I64_convert.extend_i32_u s in - (try Memory.init mem bs dst src n; vs', [] - with exn -> vs', [Trapping (memory_error e.at exn) @@ e.at]) - | None -> vs', [Trapping "data segment dropped" @@ e.at] + let b = Int32.of_int (Char.code bs.[Int32.to_int s]) in + vs', List.map (at e.at) [ + Plain (Const (I32 d @@ e.at)); + Plain (Const (I32 b @@ e.at)); + Plain ( + Store {ty = I32Type; align = 0; offset = 0l; sz = Some Memory.Pack8}); + ] ) + | MemoryInit x, I32 n :: I32 s :: I32 d :: vs' -> + vs', List.map (at e.at) [ + Plain (Const (I32 d @@ e.at)); + Plain (Const (I32 s @@ e.at)); + Plain (Const (I32 1l @@ e.at)); + Plain (MemoryInit x); + const_i32_add d 1l e.at (memory_error e.at Memory.Bounds); + const_i32_add s 1l e.at (memory_error e.at Memory.Bounds); + Plain (Const (I32 (I32.sub n 1l) @@ e.at)); + Plain (MemoryInit x); + ] + | DataDrop x, vs -> let seg = data frame.inst x in (match !seg with diff --git a/interpreter/runtime/memory.ml b/interpreter/runtime/memory.ml index 27a8e6a52d..889aa7071d 100644 --- a/interpreter/runtime/memory.ml +++ b/interpreter/runtime/memory.ml @@ -144,34 +144,3 @@ let store_packed sz mem a o v = | I64 x -> x | _ -> raise Type in storen mem a o n x - -let init mem bs d s n = - let load_str_byte a = - try Char.code bs.[Int64.to_int a] - with _ -> raise Bounds - in let rec loop d s n = - if I32.gt_u n 0l then begin - store_byte mem d (load_str_byte s); - loop (Int64.add d 1L) (Int64.add s 1L) (Int32.sub n 1l) - end - in loop d s n - -let copy mem d s n = - let n' = I64_convert.extend_i32_u n in - let rec loop d s n dx = - if I32.gt_u n 0l then begin - store_byte mem d (load_byte mem s); - loop (Int64.add d dx) (Int64.add s dx) (Int32.sub n 1l) dx - end - in (if s < d then - loop Int64.(add d (sub n' 1L)) Int64.(add s (sub n' 1L)) n (-1L) - else - loop d s n 1L) - -let fill mem a v n = - let rec loop a n = - if I32.gt_u n 0l then begin - store_byte mem a v; - loop (Int64.add a 1L) (Int32.sub n 1l) - end - in loop a n diff --git a/interpreter/runtime/memory.mli b/interpreter/runtime/memory.mli index a20714418d..0c42124ab2 100644 --- a/interpreter/runtime/memory.mli +++ b/interpreter/runtime/memory.mli @@ -43,8 +43,3 @@ val load_packed : val store_packed : pack_size -> memory -> address -> offset -> value -> unit (* raises Type, Bounds *) - -val init : - memory -> string -> address -> address -> count -> unit (* raises Bounds *) -val copy : memory -> address -> address -> count -> unit (* raises Bounds *) -val fill : memory -> address -> int -> count -> unit (* raises Bounds *) diff --git a/interpreter/util/source.ml b/interpreter/util/source.ml index 0115825c87..f659f6f235 100644 --- a/interpreter/util/source.ml +++ b/interpreter/util/source.ml @@ -3,6 +3,7 @@ type region = {left : pos; right : pos} type 'a phrase = {at : region; it : 'a} let (@@) x region = {it = x; at = region} +let at region x = x @@ region (* Positions and regions *) diff --git a/interpreter/util/source.mli b/interpreter/util/source.mli index 8cab3db869..240fe64138 100644 --- a/interpreter/util/source.mli +++ b/interpreter/util/source.mli @@ -9,3 +9,4 @@ val string_of_pos : pos -> string val string_of_region : region -> string val (@@) : 'a -> region -> 'a phrase +val at : region -> 'a -> 'a phrase diff --git a/test/core/bulk.wast b/test/core/bulk.wast index 98c4a49a61..b2359d8f94 100644 --- a/test/core/bulk.wast +++ b/test/core/bulk.wast @@ -148,24 +148,26 @@ ;; data.drop (module (memory 1) - (data $p "") - (data $a 0 (i32.const 0) "") + (data $p "x") + (data $a 0 (i32.const 0) "x") (func (export "drop_passive") (data.drop $p)) - (func (export "init_passive") - (memory.init $p (i32.const 0) (i32.const 0) (i32.const 0))) + (func (export "init_passive") (param $len i32) + (memory.init $p (i32.const 0) (i32.const 0) (local.get $len))) (func (export "drop_active") (data.drop $a)) - (func (export "init_active") - (memory.init $a (i32.const 0) (i32.const 0) (i32.const 0))) + (func (export "init_active") (param $len i32) + (memory.init $a (i32.const 0) (i32.const 0) (local.get $len))) ) -(invoke "init_passive") +(invoke "init_passive" (i32.const 1)) (invoke "drop_passive") (assert_trap (invoke "drop_passive") "data segment dropped") -(assert_trap (invoke "init_passive") "data segment dropped") +(assert_return (invoke "init_passive" (i32.const 0))) +(assert_trap (invoke "init_passive" (i32.const 1)) "data segment dropped") (assert_trap (invoke "drop_active") "data segment dropped") -(assert_trap (invoke "init_active") "data segment dropped") +(assert_return (invoke "init_active" (i32.const 0))) +(assert_trap (invoke "init_active" (i32.const 1)) "data segment dropped") ;; table.init From b95f821f3901e8fb3ab509ab0cef9f7a3fd51001 Mon Sep 17 00:00:00 2001 From: Andreas Rossberg Date: Mon, 7 Oct 2019 12:11:55 +0200 Subject: [PATCH 127/199] Polish text format (#119) Fix a couple of parser omissions regarding elem & data syntax. Refactor grammar in spec slightly for more clarity. Adjust tests. --- document/core/text/modules.rst | 35 +++++++++++--------- document/core/util/macros.def | 2 ++ interpreter/text/parser.mly | 36 ++++++++++---------- test/core/bulk.wast | 2 +- test/core/data.wast | 28 +++++++++++----- test/core/elem.wast | 60 +++++++++++++++++++++++++--------- test/core/imports.wast | 4 +-- 7 files changed, 107 insertions(+), 60 deletions(-) diff --git a/document/core/text/modules.rst b/document/core/text/modules.rst index 91ebbd5628..b77889b746 100644 --- a/document/core/text/modules.rst +++ b/document/core/text/modules.rst @@ -486,6 +486,7 @@ A :ref:`start function ` is defined in terms of its index. .. _text-elem: .. _text-elemlist: .. _text-elemexpr: +.. _text-tableuse: Element Segments ~~~~~~~~~~~~~~~~ @@ -497,13 +498,16 @@ Element segments allow for an optional :ref:`table index ` to ide \production{element segment} & \Telem_I &::=& \text{(}~\text{elem}~~\Tid^?~~(et, y^\ast){:}\Telemlist~\text{)} \\ &&& \qquad \Rightarrow\quad \{ \ETYPE~et, \EINIT~y^\ast, \EMODE~\EPASSIVE \} \\ &&|& - \text{(}~\text{elem}~~\Tid^?~~\text{(}~\text{table}~~x{:}\Ttableidx_I ~\text{)}~~\text{(}~\text{offset}~~e{:}\Texpr_I~\text{)}~~(et, y^\ast){:}\Telemlist~\text{)} \\ &&& \qquad + \text{(}~\text{elem}~~\Tid^?~~x{:}\Ttableuse_I~~\text{(}~\text{offset}~~e{:}\Texpr_I~\text{)}~~(et, y^\ast){:}\Telemlist~\text{)} \\ &&& \qquad \Rightarrow\quad \{ \ETYPE~et, \EINIT~y^\ast, \EMODE~\EACTIVE~\{ \ETABLE~x, \EOFFSET~e \} \} \\ \production{element list} & \Telemlist &::=& et{:}\Telemtype~~y^\ast{:}\Tvec(\Telemexpr_I) \qquad\Rightarrow\quad ( \ETYPE~et, \EINIT~y^\ast ) \\ \production{element expression} & \Telemexpr &::=& \text{(}~\text{ref.null}~\text{)} \\ &&|& \text{(}~\text{ref.func}~~\Tfuncidx_I~\text{)} \\ + \production{table use} & \Ttableuse_I &::=& + \text{(}~\text{table}~~x{:}\Ttableidx_I ~\text{)} + \quad\Rightarrow\quad x \\ \end{array} .. note:: @@ -532,17 +536,16 @@ Also, the element list may be written as just a sequence of :ref:`function indic \text{funcref}~~\Tvec(\text{(}~\text{ref.func}~~\Tfuncidx_I~\text{)}) \end{array} -Also, the table index can be omitted, defaulting to :math:`\T{0}`. -Furthermore, for backwards compatibility with earlier versions of WebAssembly, if the table index is omitted, the :math:`\text{func}` keyword can be omitted as well. +Also, a table use can be omitted, defaulting to :math:`\T{0}`. +Furthermore, for backwards compatibility with earlier versions of WebAssembly, if the table use is omitted, the :math:`\text{func}` keyword can be omitted as well. .. math:: - \begin{array}{ll} + \begin{array}{llclll} + \production{table use} & + \epsilon &\equiv& \text{(}~\text{table}~~\text{0}~\text{)} \\ \production{element segment} & - \text{(}~\text{elem}~~\Tid^?~~\text{(}~\text{offset}~~\Texpr_I~\text{)}~~\Telemlist~\text{)} - \quad\equiv \\& - \text{(}~\text{elem}~~\Tid^?~~\text{(}~\text{table}~~\text{0}~\text{)}~~\text{(}~\text{offset}~~\Texpr_I~\text{)}~~\Telemlist~\text{)} \\ - \text{(}~\text{elem}~~\Tid^?~~\text{(}~\text{offset}~~\Texpr_I~\text{)}~~\Tvec(\Tfuncidx_I)~\text{)} - \quad\equiv \\& + \text{(}~\text{elem}~~\Tid^?~~\text{(}~\text{offset}~~\Texpr_I~\text{)}~~\Tvec(\Tfuncidx_I)~\text{)} + &\equiv& \text{(}~\text{elem}~~\Tid^?~~\text{(}~\text{table}~~\text{0}~\text{)}~~\text{(}~\text{offset}~~\Texpr_I~\text{)}~~\text{func}~~\Tvec(\Tfuncidx_I)~\text{)} \end{array} @@ -555,6 +558,7 @@ As another abbreviation, element segments may also be specified inline with :ref single: data; segment .. _text-datastring: .. _text-data: +.. _test-memuse: Data Segments ~~~~~~~~~~~~~ @@ -567,10 +571,13 @@ The data is written as a :ref:`string `, which may be split up into \production{data segment} & \Tdata_I &::=& \text{(}~\text{data}~~\Tid^?~~b^\ast{:}\Tdatastring~\text{)} \\ &&& \qquad \Rightarrow\quad \{ \DINIT~b^\ast, \DMODE~\DPASSIVE \} \\ &&|& - \text{(}~\text{data}~~\Tid^?~~\text{(}~\text{memory}~~x{:}\Tmemidx_I ~\text{)}~~\text{(}~\text{offset}~~e{:}\Texpr_I~\text{)}~~b^\ast{:}\Tdatastring~\text{)} \\ &&& \qquad + \text{(}~\text{data}~~\Tid^?~~x{:}\Tmemuse_I~~\text{(}~\text{offset}~~e{:}\Texpr_I~\text{)}~~b^\ast{:}\Tdatastring~\text{)} \\ &&& \qquad \Rightarrow\quad \{ \DINIT~b^\ast, \DMODE~\DACTIVE~\{ \DMEM~x', \DOFFSET~e \} \} \\ \production{data string} & \Tdatastring &::=& (b^\ast{:}\Tstring)^\ast \quad\Rightarrow\quad \concat((b^\ast)^\ast) \\ + \production{memory use} & \Tmemuse_I &::=& + \text{(}~\text{memory}~~x{:}\Tmemidx_I ~\text{)} + \quad\Rightarrow\quad x \\ \end{array} .. note:: @@ -590,14 +597,12 @@ As an abbreviation, a single instruction may occur in place of the offset of an \text{(}~\text{offset}~~\Tinstr~\text{)} \end{array} -Also, the memory index can be omitted, defaulting to :math:`\T{0}`. +Also, a memory use can be omitted, defaulting to :math:`\T{0}`. .. math:: \begin{array}{llclll} - \production{data segment} & - \text{(}~\text{data}~~\Tid^?~~\text{(}~\text{offset}~~\Texpr_I~\text{)}~~\dots~\text{)} - &\equiv& - \text{(}~\text{data}~~\Tid^?~~\text{(}~\text{memory}~~\text{0}~\text{)}~~\text{(}~\text{offset}~~\Texpr_I~\text{)}~~\dots~\text{)} + \production{memory use} & + \epsilon &\equiv& \text{(}~\text{memory}~~\text{0}~\text{)} \\ \end{array} As another abbreviation, data segments may also be specified inline with :ref:`memory ` definitions; see the respective section. diff --git a/document/core/util/macros.def b/document/core/util/macros.def index 967c4d0b6b..68108bcaa1 100644 --- a/document/core/util/macros.def +++ b/document/core/util/macros.def @@ -696,11 +696,13 @@ .. |Telem| mathdef:: \xref{text/modules}{text-elem}{\T{elem}} .. |Telemlist| mathdef:: \xref{text/modules}{text-elemlist}{\T{elemlist}} .. |Telemexpr| mathdef:: \xref{text/modules}{text-elemexpr}{\X{elemexpr}} +.. |Ttableuse| mathdef:: \xref{text/modules}{text-tableuse}{\T{tableuse}} .. |Tcode| mathdef:: \xref{text/modules}{text-code}{\T{code}} .. |Tlocal| mathdef:: \xref{text/modules}{text-local}{\T{local}} .. |Tlocals| mathdef:: \xref{text/modules}{text-local}{\T{locals}} .. |Tdata| mathdef:: \xref{text/modules}{text-data}{\T{data}} .. |Tdatastring| mathdef:: \xref{text/modules}{text-datastring}{\T{datastring}} +.. |Tmemuse| mathdef:: \xref{text/modules}{text-memuse}{\T{memuse}} .. |Tstart| mathdef:: \xref{text/modules}{text-start}{\T{start}} diff --git a/interpreter/text/parser.mly b/interpreter/text/parser.mly index 81b01939f0..3b9379183b 100644 --- a/interpreter/text/parser.mly +++ b/interpreter/text/parser.mly @@ -569,6 +569,9 @@ func_body : table_use : | LPAR TABLE var RPAR { fun c -> $3 c } +memory_use : + | LPAR MEMORY var RPAR { fun c -> $3 c } + offset : | LPAR OFFSET const_expr RPAR { $3 } | expr { let at = at () in fun c -> $1 c @@ at } /* Sugar */ @@ -597,29 +600,29 @@ elem_list : elem : - | LPAR ELEM bind_var_opt offset elem_var_list RPAR /* Sugar */ - { let at = at () in - fun c -> ignore ($3 c anon_elem bind_elem); - fun () -> - { etype = FuncRefType; einit = $5 c func; - emode = Active {index = 0l @@ at; offset = $4 c} @@ at} @@ at } | LPAR ELEM bind_var_opt elem_list RPAR { let at = at () in fun c -> ignore ($3 c anon_elem bind_elem); fun () -> - {etype = (fst $4); einit = (snd $4) c; emode = Passive @@ at} @@ at } + { etype = (fst $4); einit = (snd $4) c; emode = Passive @@ at } @@ at } | LPAR ELEM bind_var_opt table_use offset elem_list RPAR { let at = at () in fun c -> ignore ($3 c anon_elem bind_elem); fun () -> { etype = (fst $6); einit = (snd $6) c; - emode = Active {index = $4 c table; offset = $5 c} @@ at} @@ at } + emode = Active {index = $4 c table; offset = $5 c} @@ at } @@ at } | LPAR ELEM bind_var_opt offset elem_list RPAR /* Sugar */ { let at = at () in fun c -> ignore ($3 c anon_elem bind_elem); fun () -> { etype = (fst $5); einit = (snd $5) c; - emode = Active {index = 0l @@ at; offset = $4 c} @@ at} @@ at } + emode = Active {index = 0l @@ at; offset = $4 c} @@ at } @@ at } + | LPAR ELEM bind_var_opt offset elem_var_list RPAR /* Sugar */ + { let at = at () in + fun c -> ignore ($3 c anon_elem bind_elem); + fun () -> + { etype = FuncRefType; einit = $5 c func; + emode = Active {index = 0l @@ at; offset = $4 c} @@ at } @@ at } table : | LPAR TABLE bind_var_opt table_fields RPAR @@ -662,21 +665,16 @@ data : { let at = at () in fun c -> ignore ($3 c anon_data bind_data); fun () -> {dinit = $4; dmode = Passive @@ at} @@ at } - | LPAR DATA bind_var var offset string_list RPAR + | LPAR DATA bind_var_opt memory_use offset string_list RPAR { let at = at () in - fun c -> ignore (bind_data c $3); + fun c -> ignore ($3 c anon_data bind_data); fun () -> {dinit = $6; dmode = Active {index = $4 c memory; offset = $5 c} @@ at} @@ at } - | LPAR DATA var offset string_list RPAR - { let at = at () in - fun c -> ignore (anon_data c); - fun () -> - {dinit = $5; dmode = Active {index = $3 c memory; offset = $4 c} @@ at} @@ at } - | LPAR DATA offset string_list RPAR /* Sugar */ + | LPAR DATA bind_var_opt offset string_list RPAR /* Sugar */ { let at = at () in - fun c -> ignore (anon_data c); + fun c -> ignore ($3 c anon_data bind_data); fun () -> - {dinit = $4; dmode = Active {index = 0l @@ at; offset = $3 c} @@ at} @@ at } + {dinit = $5; dmode = Active {index = 0l @@ at; offset = $4 c} @@ at} @@ at } memory : | LPAR MEMORY bind_var_opt memory_fields RPAR diff --git a/test/core/bulk.wast b/test/core/bulk.wast index b2359d8f94..f197009f35 100644 --- a/test/core/bulk.wast +++ b/test/core/bulk.wast @@ -149,7 +149,7 @@ (module (memory 1) (data $p "x") - (data $a 0 (i32.const 0) "x") + (data $a (memory 0) (i32.const 0) "x") (func (export "drop_passive") (data.drop $p)) (func (export "init_passive") (param $len i32) diff --git a/test/core/data.wast b/test/core/data.wast index 80a2704e3c..d95cc6da41 100644 --- a/test/core/data.wast +++ b/test/core/data.wast @@ -8,14 +8,26 @@ (data (i32.const 1) "a" "" "bcd") (data (offset (i32.const 0))) (data (offset (i32.const 0)) "" "a" "bc" "") - (data 0 (i32.const 0)) - (data 0x0 (i32.const 1) "a" "" "bcd") - (data 0x000 (offset (i32.const 0))) - (data 0 (offset (i32.const 0)) "" "a" "bc" "") - (data $m (i32.const 0)) - (data $m (i32.const 1) "a" "" "bcd") - (data $m (offset (i32.const 0))) - (data $m (offset (i32.const 0)) "" "a" "bc" "") + (data (memory 0) (i32.const 0)) + (data (memory 0x0) (i32.const 1) "a" "" "bcd") + (data (memory 0x000) (offset (i32.const 0))) + (data (memory 0) (offset (i32.const 0)) "" "a" "bc" "") + (data (memory $m) (i32.const 0)) + (data (memory $m) (i32.const 1) "a" "" "bcd") + (data (memory $m) (offset (i32.const 0))) + (data (memory $m) (offset (i32.const 0)) "" "a" "bc" "") + (data $d1 (i32.const 0)) + (data $d2 (i32.const 1) "a" "" "bcd") + (data $d3 (offset (i32.const 0))) + (data $d4 (offset (i32.const 0)) "" "a" "bc" "") + (data $d5 (memory 0) (i32.const 0)) + (data $d6 (memory 0x0) (i32.const 1) "a" "" "bcd") + (data $d7 (memory 0x000) (offset (i32.const 0))) + (data $d8 (memory 0) (offset (i32.const 0)) "" "a" "bc" "") + (data $d9 (memory $m) (i32.const 0)) + (data $d10 (memory $m) (i32.const 1) "a" "" "bcd") + (data $d11 (memory $m) (offset (i32.const 0))) + (data $d12 (memory $m) (offset (i32.const 0)) "" "a" "bc" "") ) ;; Basic use diff --git a/test/core/elem.wast b/test/core/elem.wast index 7d2e42490e..c512d9b9ff 100644 --- a/test/core/elem.wast +++ b/test/core/elem.wast @@ -5,17 +5,25 @@ (table $t 10 funcref) (func $f) (func $g) - (elem (table $t) (i32.const 0) func) - (elem (i32.const 0)) - (elem (i32.const 0) $f $f) - (elem (offset (i32.const 0))) - (elem (offset (i32.const 0)) $f $f) + ;; Passive + (elem funcref) + (elem funcref (ref.func $f) (ref.func $f) (ref.null) (ref.func $g)) (elem func) - (elem $s func) (elem func $f $f $g $g) - (elem $x func $f $f $g $g) + (elem $p1 funcref) + (elem $p2 funcref (ref.func $f) (ref.func $f) (ref.null) (ref.func $g)) + (elem $p3 func) + (elem $p4 func $f $f $g $g) + + ;; Active + (elem (table $t) (i32.const 0) funcref) + (elem (table $t) (i32.const 0) funcref (ref.func $f) (ref.null)) + (elem (table $t) (i32.const 0) func) + (elem (table $t) (i32.const 0) func $f $g) + (elem (table $t) (offset (i32.const 0)) funcref) + (elem (table $t) (offset (i32.const 0)) func $f $g) (elem (table 0) (i32.const 0) func) (elem (table 0x0) (i32.const 0) func $f $f) (elem (table 0x000) (offset (i32.const 0)) func) @@ -24,15 +32,37 @@ (elem (table $t) (i32.const 0) func $f $f) (elem (table $t) (offset (i32.const 0)) func) (elem (table $t) (offset (i32.const 0)) func $f $f) + (elem (offset (i32.const 0))) + (elem (offset (i32.const 0)) funcref (ref.func $f) (ref.null)) + (elem (offset (i32.const 0)) func $f $f) + (elem (offset (i32.const 0)) $f $f) + (elem (i32.const 0)) + (elem (i32.const 0) funcref (ref.func $f) (ref.null)) + (elem (i32.const 0) func $f $f) + (elem (i32.const 0) $f $f) - (elem (i32.const 3) funcref (ref.func $f) (ref.func $g) (ref.func $f)) - (elem (i32.const 3) funcref (ref.func $f) (ref.null) (ref.func $f)) - - (elem funcref (ref.func $f) (ref.func $g) (ref.func $f)) - (elem funcref (ref.func $f) (ref.func $g) (ref.null)) - - (elem (table $t) (i32.const 3) funcref (ref.func $f) (ref.func $g) (ref.func $f)) - (elem (table $t) (i32.const 3) funcref (ref.func $f) (ref.null) (ref.func $g)) + (elem $a1 (table $t) (i32.const 0) funcref) + (elem $a2 (table $t) (i32.const 0) funcref (ref.func $f) (ref.null)) + (elem $a3 (table $t) (i32.const 0) func) + (elem $a4 (table $t) (i32.const 0) func $f $g) + (elem $a9 (table $t) (offset (i32.const 0)) funcref) + (elem $a10 (table $t) (offset (i32.const 0)) func $f $g) + (elem $a11 (table 0) (i32.const 0) func) + (elem $a12 (table 0x0) (i32.const 0) func $f $f) + (elem $a13 (table 0x000) (offset (i32.const 0)) func) + (elem $a14 (table 0) (offset (i32.const 0)) func $f $f) + (elem $a15 (table $t) (i32.const 0) func) + (elem $a16 (table $t) (i32.const 0) func $f $f) + (elem $a17 (table $t) (offset (i32.const 0)) func) + (elem $a18 (table $t) (offset (i32.const 0)) func $f $f) + (elem $a19 (offset (i32.const 0))) + (elem $a20 (offset (i32.const 0)) funcref (ref.func $f) (ref.null)) + (elem $a21 (offset (i32.const 0)) func $f $f) + (elem $a22 (offset (i32.const 0)) $f $f) + (elem $a23 (i32.const 0)) + (elem $a24 (i32.const 0) funcref (ref.func $f) (ref.null)) + (elem $a25 (i32.const 0) func $f $f) + (elem $a26 (i32.const 0) $f $f) ) (module diff --git a/test/core/imports.wast b/test/core/imports.wast index bbb96e053b..d987775ecb 100644 --- a/test/core/imports.wast +++ b/test/core/imports.wast @@ -380,7 +380,7 @@ (module (import "spectest" "memory" (memory 1 2)) - (data 0 (i32.const 10) "\10") + (data (memory 0) (i32.const 10) "\10") (func (export "load") (param i32) (result i32) (i32.load (local.get 0))) ) @@ -392,7 +392,7 @@ (module (memory (import "spectest" "memory") 1 2) - (data 0 (i32.const 10) "\10") + (data (memory 0) (i32.const 10) "\10") (func (export "load") (param i32) (result i32) (i32.load (local.get 0))) ) From 9aef0c541cce299cea0cecbee30bfc46755e464c Mon Sep 17 00:00:00 2001 From: Andreas Rossberg Date: Mon, 7 Oct 2019 20:11:06 +0200 Subject: [PATCH 128/199] [interpreter/test] Update table.init semantics as well (#120) --- interpreter/exec/eval.ml | 6 ++++++ test/core/bulk.wast | 18 +++++++++++------- 2 files changed, 17 insertions(+), 7 deletions(-) diff --git a/interpreter/exec/eval.ml b/interpreter/exec/eval.ml index 48e923cd46..3fb6dc3110 100644 --- a/interpreter/exec/eval.ml +++ b/interpreter/exec/eval.ml @@ -202,12 +202,18 @@ let rec step (c : config) : config = with Global.NotMutable -> Crash.error e.at "write to immutable global" | Global.Type -> Crash.error e.at "type mismatch at global write") + | TableCopy, I32 0l :: I32 s :: I32 d :: vs' -> + vs', [] + (* TODO: turn into small-step, but needs reference values *) | TableCopy, I32 n :: I32 s :: I32 d :: vs' -> let tab = table frame.inst (0l @@ e.at) in (try Table.copy tab d s n; vs', [] with exn -> vs', [Trapping (table_error e.at exn) @@ e.at]) + | TableInit x, I32 0l :: I32 s :: I32 d :: vs' -> + vs', [] + (* TODO: turn into small-step, but needs reference values *) | TableInit x, I32 n :: I32 s :: I32 d :: vs' -> let tab = table frame.inst (0l @@ e.at) in diff --git a/test/core/bulk.wast b/test/core/bulk.wast index f197009f35..0324fb20a4 100644 --- a/test/core/bulk.wast +++ b/test/core/bulk.wast @@ -220,20 +220,24 @@ (elem $a (table 0) (i32.const 0) func $f) (func (export "drop_passive") (elem.drop $p)) - (func (export "init_passive") - (table.init $p (i32.const 0) (i32.const 0) (i32.const 0))) + (func (export "init_passive") (param $len i32) + (table.init $p (i32.const 0) (i32.const 0) (local.get $len)) + ) (func (export "drop_active") (elem.drop $a)) - (func (export "init_active") - (table.init $a (i32.const 0) (i32.const 0) (i32.const 0))) + (func (export "init_active") (param $len i32) + (table.init $a (i32.const 0) (i32.const 0) (local.get $len)) + ) ) -(invoke "init_passive") +(invoke "init_passive" (i32.const 1)) (invoke "drop_passive") (assert_trap (invoke "drop_passive") "element segment dropped") -(assert_trap (invoke "init_passive") "element segment dropped") +(assert_return (invoke "init_passive" (i32.const 0))) +(assert_trap (invoke "init_passive" (i32.const 1)) "element segment dropped") (assert_trap (invoke "drop_active") "element segment dropped") -(assert_trap (invoke "init_active") "element segment dropped") +(assert_return (invoke "init_active" (i32.const 0))) +(assert_trap (invoke "init_active" (i32.const 1)) "element segment dropped") ;; table.copy From 1e05d9bbfa9c5497ac1e95b59c48b3aacd50d88e Mon Sep 17 00:00:00 2001 From: gahaas Date: Tue, 29 Oct 2019 20:18:32 +0100 Subject: [PATCH 129/199] Fix test expectation (#58) --- test/core/binary.wast | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/core/binary.wast b/test/core/binary.wast index 4a85f08fad..9f27273e46 100644 --- a/test/core/binary.wast +++ b/test/core/binary.wast @@ -1023,7 +1023,7 @@ "\0a\04\01" ;; code section "\02\00\0b" ;; function body ) - "invalid value type" + "invalid segment kind" ) ;; 1 elem segment declared, 2 given @@ -1164,7 +1164,7 @@ "\02" ;; break depth for default "\0b\0b\0b" ;; end ) - "invalid value type" + "invalid reference type" ) ;; Start section From e66f53225f9be73a87d9b2251d187435d0564e98 Mon Sep 17 00:00:00 2001 From: Andreas Rossberg Date: Thu, 14 Nov 2019 07:58:10 +0100 Subject: [PATCH 130/199] Fix call_indirect immediates --- proposals/reference-types/Overview.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/proposals/reference-types/Overview.md b/proposals/reference-types/Overview.md index 716b2291a9..bc32ffd60b 100644 --- a/proposals/reference-types/Overview.md +++ b/proposals/reference-types/Overview.md @@ -114,7 +114,7 @@ New/extended instructions: - and `t' <: t` * The `call_indirect` instruction takes a table index as immediate. - - `call_indirect (type $t) $x : [t1* i32] -> [t2*]` + - `call_indirect $x (type $t) : [t1* i32] -> [t2*]` - iff `$t = [t1*] -> [t2*]` - and `$x : table t'` - and `t' <: funcref` @@ -260,7 +260,7 @@ Addition: Note: * Can decompose `call_indirect` (assuming multi-value proposal): - - `(call_indirect $t $x)` reduces to `(table.get $x) (cast $t anyref (ref $t) (then (call_ref (ref $t))) (else (unreachable)))` + - `(call_indirect $x (type $t))` reduces to `(table.get $x) (cast $t anyref (ref $t) (then (call_ref (ref $t))) (else (unreachable)))` ### GC Types From be7ce1b4401bf3f507b03bf450547531d127acd4 Mon Sep 17 00:00:00 2001 From: Ryan Hunt Date: Thu, 14 Nov 2019 04:21:01 -0600 Subject: [PATCH 131/199] [spec] Bounds check bulk-memory before execution (#123) Spec issue: https://github.com/webassembly/bulk-memory-operations/issues/111 This commit changes the semantics of bulk-memory instructions to perform an upfront bounds check and trap if any access would be out-of-bounds without writing. This affects the following: * memory.init/copy/fill * table.init/copy (fill requires reftypes) * data segment init (lowers to memory.init) * elem segment init (lowers to table.init) --- document/core/exec/instructions.rst | 40 +- interpreter/exec/eval.ml | 114 +- test/core/bulk.wast | 23 +- test/core/memory_copy.wast | 5805 +++++++++++++-------------- test/core/memory_fill.wast | 12 +- test/core/memory_init.wast | 36 +- test/core/table_copy.wast | 98 +- test/core/table_init.wast | 306 +- test/meta/generate_memory_copy.js | 31 +- test/meta/generate_memory_fill.js | 5 +- test/meta/generate_memory_init.js | 4 +- test/meta/generate_table_copy.js | 29 +- test/meta/generate_table_init.js | 8 +- 13 files changed, 3177 insertions(+), 3334 deletions(-) diff --git a/document/core/exec/instructions.rst b/document/core/exec/instructions.rst index a3fdaa5e4b..8dc36e7627 100644 --- a/document/core/exec/instructions.rst +++ b/document/core/exec/instructions.rst @@ -730,25 +730,25 @@ Memory Instructions 9. Let :math:`\X{data}^?` be the optional :ref:`data instance ` :math:`S.\SDATA[\X{da}]`. -10. If :math:`\X{data}^? = \epsilon`, then: +10. Assert: due to :ref:`validation `, a value of :ref:`value type ` |I32| is on the top of the stack. - a. Trap. +11. Pop the value :math:`\I32.\CONST~cnt` from the stack. -11. Assert: due to :ref:`validation `, a value of :ref:`value type ` |I32| is on the top of the stack. +12. Assert: due to :ref:`validation `, a value of :ref:`value type ` |I32| is on the top of the stack. -12. Pop the value :math:`\I32.\CONST~cnt` from the stack. +13. Pop the value :math:`\I32.\CONST~src` from the stack. -13. Assert: due to :ref:`validation `, a value of :ref:`value type ` |I32| is on the top of the stack. +14. Assert: due to :ref:`validation `, a value of :ref:`value type ` |I32| is on the top of the stack. -14. Pop the value :math:`\I32.\CONST~src` from the stack. +15. Pop the value :math:`\I32.\CONST~dst` from the stack. -15. Assert: due to :ref:`validation `, a value of :ref:`value type ` |I32| is on the top of the stack. +16. If :math:`cnt = 0`, then: -16. Pop the value :math:`\I32.\CONST~dst` from the stack. + a. Return. -17. If :math:`cnt = 0`, then: +17. If :math:`\X{data}^? = \epsilon`, then: - a. Return. + a. Trap. 18. If :math:`cnt = 1`, then: @@ -1091,25 +1091,25 @@ Table Instructions 9. Let :math:`\X{elem}^?` be the optional :ref:`element instance ` :math:`S.\SELEM[\X{ea}]`. -10. If :math:`\X{elem}^? = \epsilon`, then: +10. Assert: due to :ref:`validation `, a value of :ref:`value type ` |I32| is on the top of the stack. - a. Trap. +11. Pop the value :math:`\I32.\CONST~cnt` from the stack. -11. Assert: due to :ref:`validation `, a value of :ref:`value type ` |I32| is on the top of the stack. +12. Assert: due to :ref:`validation `, a value of :ref:`value type ` |I32| is on the top of the stack. -12. Pop the value :math:`\I32.\CONST~cnt` from the stack. +13. Pop the value :math:`\I32.\CONST~src` from the stack. -13. Assert: due to :ref:`validation `, a value of :ref:`value type ` |I32| is on the top of the stack. +14. Assert: due to :ref:`validation `, a value of :ref:`value type ` |I32| is on the top of the stack. -14. Pop the value :math:`\I32.\CONST~src` from the stack. +15. Pop the value :math:`\I32.\CONST~dst` from the stack. -15. Assert: due to :ref:`validation `, a value of :ref:`value type ` |I32| is on the top of the stack. +16. If :math:`cnt = 0`, then: -16. Pop the value :math:`\I32.\CONST~dst` from the stack. + a. Return. -17. If :math:`cnt = 0`, then: +17. If :math:`\X{elem}^? = \epsilon`, then: - a. Return. + a. Trap. 18. If :math:`cnt = 1`, then: diff --git a/interpreter/exec/eval.ml b/interpreter/exec/eval.ml index 3fb6dc3110..a56f8b9919 100644 --- a/interpreter/exec/eval.ml +++ b/interpreter/exec/eval.ml @@ -117,9 +117,27 @@ let drop n (vs : 'a stack) at = * c : config *) -let const_i32_add i j at msg = - let k = I32.add i j in - if I32.lt_u k i then Trapping msg else Plain (Const (I32 k @@ at)) +let mem_oob frame x i n = + I64.gt_u (I64.add (I64_convert.extend_i32_u i) (I64_convert.extend_i32_u n)) + (Memory.bound (memory frame.inst x)) + +let data_oob frame x i n = + match !(data frame.inst x) with + | None -> false + | Some bs -> + I64.gt_u (I64.add (I64_convert.extend_i32_u i) (I64_convert.extend_i32_u n)) + (I64.of_int_u (String.length bs)) + +let table_oob frame x i n = + I64.gt_u (I64.add (I64_convert.extend_i32_u i) (I64_convert.extend_i32_u n)) + (I64_convert.extend_i32_u (Table.size (table frame.inst x))) + +let elem_oob frame x i n = + match !(elem frame.inst x) with + | None -> false + | Some es -> + I64.gt_u (I64.add (I64_convert.extend_i32_u i) (I64_convert.extend_i32_u n)) + (I64.of_int_u (List.length es)) let rec step (c : config) : config = let {frame; code = vs, es; _} = c in @@ -205,6 +223,10 @@ let rec step (c : config) : config = | TableCopy, I32 0l :: I32 s :: I32 d :: vs' -> vs', [] + | TableCopy, I32 n :: I32 s :: I32 d :: vs' + when table_oob frame (0l @@ e.at) s n || table_oob frame (0l @@ e.at) d n -> + vs', [Trapping (table_error e.at Table.Bounds) @@ e.at] + (* TODO: turn into small-step, but needs reference values *) | TableCopy, I32 n :: I32 s :: I32 d :: vs' -> let tab = table frame.inst (0l @@ e.at) in @@ -214,6 +236,10 @@ let rec step (c : config) : config = | TableInit x, I32 0l :: I32 s :: I32 d :: vs' -> vs', [] + | TableInit x, I32 n :: I32 s :: I32 d :: vs' + when table_oob frame (0l @@ e.at) d n || elem_oob frame x s n -> + vs', [Trapping (table_error e.at Table.Bounds) @@ e.at] + (* TODO: turn into small-step, but needs reference values *) | TableInit x, I32 n :: I32 s :: I32 d :: vs' -> let tab = table frame.inst (0l @@ e.at) in @@ -233,22 +259,22 @@ let rec step (c : config) : config = | Load {offset; ty; sz; _}, I32 i :: vs' -> let mem = memory frame.inst (0l @@ e.at) in - let addr = I64_convert.extend_i32_u i in + let a = I64_convert.extend_i32_u i in (try let v = match sz with - | None -> Memory.load_value mem addr offset ty - | Some (sz, ext) -> Memory.load_packed sz ext mem addr offset ty + | None -> Memory.load_value mem a offset ty + | Some (sz, ext) -> Memory.load_packed sz ext mem a offset ty in v :: vs', [] with exn -> vs', [Trapping (memory_error e.at exn) @@ e.at]) | Store {offset; sz; _}, v :: I32 i :: vs' -> let mem = memory frame.inst (0l @@ e.at) in - let addr = I64_convert.extend_i32_u i in + let a = I64_convert.extend_i32_u i in (try (match sz with - | None -> Memory.store_value mem addr offset v - | Some sz -> Memory.store_packed sz mem addr offset v + | None -> Memory.store_value mem a offset v + | Some sz -> Memory.store_packed sz mem a offset v ); vs', [] with exn -> vs', [Trapping (memory_error e.at exn) @@ e.at]); @@ -268,21 +294,17 @@ let rec step (c : config) : config = | MemoryFill, I32 0l :: v :: I32 i :: vs' -> vs', [] - | MemoryFill, I32 1l :: v :: I32 i :: vs' -> - vs', List.map (at e.at) [ - Plain (Const (I32 i @@ e.at)); - Plain (Const (v @@ e.at)); - Plain (Store - {ty = I32Type; align = 0; offset = 0l; sz = Some Memory.Pack8}); - ] + | MemoryFill, I32 n :: v :: I32 i :: vs' + when mem_oob frame (0l @@ e.at) i n -> + vs', [Trapping (memory_error e.at Memory.Bounds) @@ e.at] | MemoryFill, I32 n :: v :: I32 i :: vs' -> vs', List.map (at e.at) [ Plain (Const (I32 i @@ e.at)); Plain (Const (v @@ e.at)); - Plain (Const (I32 1l @@ e.at)); - Plain (MemoryFill); - const_i32_add i 1l e.at (memory_error e.at Memory.Bounds); + Plain (Store + {ty = I32Type; align = 0; offset = 0l; sz = Some Memory.Pack8}); + Plain (Const (I32 (I32.add i 1l) @@ e.at)); Plain (Const (v @@ e.at)); Plain (Const (I32 (I32.sub n 1l) @@ e.at)); Plain (MemoryFill); @@ -291,7 +313,11 @@ let rec step (c : config) : config = | MemoryCopy, I32 0l :: I32 s :: I32 d :: vs' -> vs', [] - | MemoryCopy, I32 1l :: I32 s :: I32 d :: vs' -> + | MemoryCopy, I32 n :: I32 s :: I32 d :: vs' + when mem_oob frame (0l @@ e.at) s n || mem_oob frame (0l @@ e.at) d n -> + vs', [Trapping (memory_error e.at Memory.Bounds) @@ e.at] + + | MemoryCopy, I32 n :: I32 s :: I32 d :: vs' when d <= s -> vs', List.map (at e.at) [ Plain (Const (I32 d @@ e.at)); Plain (Const (I32 s @@ e.at)); @@ -299,41 +325,37 @@ let rec step (c : config) : config = {ty = I32Type; align = 0; offset = 0l; sz = Some Memory.(Pack8, ZX)}); Plain (Store {ty = I32Type; align = 0; offset = 0l; sz = Some Memory.Pack8}); - ] - - | MemoryCopy, I32 n :: I32 s :: I32 d :: vs' when d <= s -> - vs', List.map (at e.at) [ - Plain (Const (I32 d @@ e.at)); - Plain (Const (I32 s @@ e.at)); - Plain (Const (I32 1l @@ e.at)); - Plain (MemoryCopy); - const_i32_add d 1l e.at (memory_error e.at Memory.Bounds); - const_i32_add s 1l e.at (memory_error e.at Memory.Bounds); + Plain (Const (I32 (I32.add d 1l) @@ e.at)); + Plain (Const (I32 (I32.add s 1l) @@ e.at)); Plain (Const (I32 (I32.sub n 1l) @@ e.at)); Plain (MemoryCopy); ] | MemoryCopy, I32 n :: I32 s :: I32 d :: vs' when s < d -> vs', List.map (at e.at) [ - const_i32_add d (I32.sub n 1l) e.at (memory_error e.at Memory.Bounds); - const_i32_add s (I32.sub n 1l) e.at (memory_error e.at Memory.Bounds); - Plain (Const (I32 1l @@ e.at)); + Plain (Const (I32 (I32.add d 1l) @@ e.at)); + Plain (Const (I32 (I32.add s 1l) @@ e.at)); + Plain (Const (I32 (I32.sub n 1l) @@ e.at)); Plain (MemoryCopy); Plain (Const (I32 d @@ e.at)); Plain (Const (I32 s @@ e.at)); - Plain (Const (I32 (I32.sub n 1l) @@ e.at)); - Plain (MemoryCopy); + Plain (Load + {ty = I32Type; align = 0; offset = 0l; sz = Some Memory.(Pack8, ZX)}); + Plain (Store + {ty = I32Type; align = 0; offset = 0l; sz = Some Memory.Pack8}); ] | MemoryInit x, I32 0l :: I32 s :: I32 d :: vs' -> vs', [] - | MemoryInit x, I32 1l :: I32 s :: I32 d :: vs' -> + | MemoryInit x, I32 n :: I32 s :: I32 d :: vs' + when mem_oob frame (0l @@ e.at) d n || data_oob frame x s n -> + vs', [Trapping (memory_error e.at Memory.Bounds) @@ e.at] + + | MemoryInit x, I32 n :: I32 s :: I32 d :: vs' -> (match !(data frame.inst x) with | None -> vs', [Trapping "data segment dropped" @@ e.at] - | Some bs when Int32.to_int s >= String.length bs -> - vs', [Trapping "out of bounds data segment access" @@ e.at] | Some bs -> let b = Int32.of_int (Char.code bs.[Int32.to_int s]) in vs', List.map (at e.at) [ @@ -341,21 +363,13 @@ let rec step (c : config) : config = Plain (Const (I32 b @@ e.at)); Plain ( Store {ty = I32Type; align = 0; offset = 0l; sz = Some Memory.Pack8}); + Plain (Const (I32 (I32.add d 1l) @@ e.at)); + Plain (Const (I32 (I32.add s 1l) @@ e.at)); + Plain (Const (I32 (I32.sub n 1l) @@ e.at)); + Plain (MemoryInit x); ] ) - | MemoryInit x, I32 n :: I32 s :: I32 d :: vs' -> - vs', List.map (at e.at) [ - Plain (Const (I32 d @@ e.at)); - Plain (Const (I32 s @@ e.at)); - Plain (Const (I32 1l @@ e.at)); - Plain (MemoryInit x); - const_i32_add d 1l e.at (memory_error e.at Memory.Bounds); - const_i32_add s 1l e.at (memory_error e.at Memory.Bounds); - Plain (Const (I32 (I32.sub n 1l) @@ e.at)); - Plain (MemoryInit x); - ] - | DataDrop x, vs -> let seg = data frame.inst x in (match !seg with diff --git a/test/core/bulk.wast b/test/core/bulk.wast index 0324fb20a4..9e26519e0c 100644 --- a/test/core/bulk.wast +++ b/test/core/bulk.wast @@ -39,11 +39,11 @@ ;; Fill all of memory (invoke "fill" (i32.const 0) (i32.const 0) (i32.const 0x10000)) -;; Out-of-bounds writes trap, but all previous writes succeed. +;; Out-of-bounds writes trap, and nothing is written (assert_trap (invoke "fill" (i32.const 0xff00) (i32.const 1) (i32.const 0x101)) "out of bounds memory access") -(assert_return (invoke "load8_u" (i32.const 0xff00)) (i32.const 1)) -(assert_return (invoke "load8_u" (i32.const 0xffff)) (i32.const 1)) +(assert_return (invoke "load8_u" (i32.const 0xff00)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 0xffff)) (i32.const 0)) ;; Succeed when writing 0 bytes at the end of the region. (invoke "fill" (i32.const 0x10000) (i32.const 0) (i32.const 0)) @@ -131,11 +131,11 @@ ;; Init ending at memory limit and segment limit is ok. (invoke "init" (i32.const 0xfffc) (i32.const 0) (i32.const 4)) -;; Out-of-bounds writes trap, but all previous writes succeed. +;; Out-of-bounds writes trap, and nothing is written. (assert_trap (invoke "init" (i32.const 0xfffe) (i32.const 0) (i32.const 3)) "out of bounds memory access") -(assert_return (invoke "load8_u" (i32.const 0xfffe)) (i32.const 0xaa)) -(assert_return (invoke "load8_u" (i32.const 0xffff)) (i32.const 0xbb)) +(assert_return (invoke "load8_u" (i32.const 0xfffe)) (i32.const 0xcc)) +(assert_return (invoke "load8_u" (i32.const 0xffff)) (i32.const 0xdd)) ;; Succeed when writing 0 bytes at the end of either region. (invoke "init" (i32.const 0x10000) (i32.const 0) (i32.const 0)) @@ -190,6 +190,12 @@ (local.get 0))) ) +;; Out-of-bounds stores trap, and nothing is written. +(assert_trap (invoke "init" (i32.const 2) (i32.const 0) (i32.const 2)) + "out of bounds table access") +(assert_trap (invoke "call" (i32.const 2)) + "uninitialized element 2") + (invoke "init" (i32.const 0) (i32.const 1) (i32.const 2)) (assert_return (invoke "call" (i32.const 0)) (i32.const 1)) (assert_return (invoke "call" (i32.const 1)) (i32.const 0)) @@ -198,11 +204,6 @@ ;; Init ending at table limit and segment limit is ok. (invoke "init" (i32.const 1) (i32.const 2) (i32.const 2)) -;; Out-of-bounds stores trap, but all previous stores succeed. -(assert_trap (invoke "init" (i32.const 2) (i32.const 0) (i32.const 2)) - "out of bounds table access") -(assert_return (invoke "call" (i32.const 2)) (i32.const 0)) - ;; Succeed when storing 0 elements at the end of either region. (invoke "init" (i32.const 3) (i32.const 0) (i32.const 0)) (invoke "init" (i32.const 0) (i32.const 4) (i32.const 0)) diff --git a/test/core/memory_copy.wast b/test/core/memory_copy.wast index 55bbaf9c0b..cb46144d35 100644 --- a/test/core/memory_copy.wast +++ b/test/core/memory_copy.wast @@ -1072,2954 +1072,2863 @@ (assert_trap (invoke "run" (i32.const 0) (i32.const 65516) (i32.const 40)) "out of bounds") -(assert_return (invoke "load8_u" (i32.const 0)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 1)) (i32.const 1)) -(assert_return (invoke "load8_u" (i32.const 2)) (i32.const 2)) -(assert_return (invoke "load8_u" (i32.const 3)) (i32.const 3)) -(assert_return (invoke "load8_u" (i32.const 4)) (i32.const 4)) -(assert_return (invoke "load8_u" (i32.const 5)) (i32.const 5)) -(assert_return (invoke "load8_u" (i32.const 6)) (i32.const 6)) -(assert_return (invoke "load8_u" (i32.const 7)) (i32.const 7)) -(assert_return (invoke "load8_u" (i32.const 8)) (i32.const 8)) -(assert_return (invoke "load8_u" (i32.const 9)) (i32.const 9)) -(assert_return (invoke "load8_u" (i32.const 10)) (i32.const 10)) -(assert_return (invoke "load8_u" (i32.const 11)) (i32.const 11)) -(assert_return (invoke "load8_u" (i32.const 12)) (i32.const 12)) -(assert_return (invoke "load8_u" (i32.const 13)) (i32.const 13)) -(assert_return (invoke "load8_u" (i32.const 14)) (i32.const 14)) -(assert_return (invoke "load8_u" (i32.const 15)) (i32.const 15)) -(assert_return (invoke "load8_u" (i32.const 16)) (i32.const 16)) -(assert_return (invoke "load8_u" (i32.const 17)) (i32.const 17)) -(assert_return (invoke "load8_u" (i32.const 18)) (i32.const 18)) -(assert_return (invoke "load8_u" (i32.const 19)) (i32.const 19)) -(assert_return (invoke "load8_u" (i32.const 218)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 417)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 616)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 815)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 1014)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 1213)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 1412)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 1611)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 1810)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 2009)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 2208)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 2407)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 2606)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 2805)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 3004)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 3203)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 3402)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 3601)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 3800)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 3999)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 4198)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 4397)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 4596)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 4795)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 4994)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 5193)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 5392)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 5591)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 5790)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 5989)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 6188)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 6387)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 6586)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 6785)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 6984)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 7183)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 7382)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 7581)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 7780)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 7979)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 8178)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 8377)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 8576)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 8775)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 8974)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 9173)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 9372)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 9571)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 9770)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 9969)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 10168)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 10367)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 10566)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 10765)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 10964)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 11163)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 11362)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 11561)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 11760)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 11959)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 12158)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 12357)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 12556)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 12755)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 12954)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 13153)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 13352)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 13551)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 13750)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 13949)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 14148)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 14347)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 14546)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 14745)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 14944)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 15143)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 15342)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 15541)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 15740)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 15939)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 16138)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 16337)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 16536)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 16735)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 16934)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 17133)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 17332)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 17531)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 17730)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 17929)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 18128)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 18327)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 18526)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 18725)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 18924)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 19123)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 19322)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 19521)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 19720)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 19919)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 20118)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 20317)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 20516)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 20715)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 20914)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 21113)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 21312)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 21511)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 21710)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 21909)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 22108)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 22307)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 22506)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 22705)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 22904)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 23103)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 23302)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 23501)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 23700)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 23899)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 24098)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 24297)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 24496)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 24695)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 24894)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 25093)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 25292)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 25491)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 25690)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 25889)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 26088)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 26287)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 26486)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 26685)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 26884)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 27083)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 27282)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 27481)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 27680)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 27879)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 28078)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 28277)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 28476)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 28675)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 28874)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 29073)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 29272)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 29471)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 29670)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 29869)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 30068)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 30267)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 30466)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 30665)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 30864)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 31063)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 31262)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 31461)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 31660)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 31859)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 32058)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 32257)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 32456)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 32655)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 32854)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 33053)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 33252)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 33451)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 33650)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 33849)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 34048)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 34247)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 34446)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 34645)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 34844)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 35043)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 35242)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 35441)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 35640)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 35839)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 36038)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 36237)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 36436)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 36635)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 36834)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 37033)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 37232)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 37431)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 37630)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 37829)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 38028)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 38227)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 38426)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 38625)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 38824)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 39023)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 39222)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 39421)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 39620)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 39819)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 40018)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 40217)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 40416)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 40615)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 40814)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 41013)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 41212)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 41411)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 41610)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 41809)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 42008)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 42207)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 42406)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 42605)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 42804)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 43003)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 43202)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 43401)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 43600)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 43799)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 43998)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 44197)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 44396)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 44595)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 44794)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 44993)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 45192)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 45391)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 45590)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 45789)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 45988)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 46187)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 46386)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 46585)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 46784)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 46983)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 47182)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 47381)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 47580)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 47779)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 47978)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 48177)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 48376)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 48575)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 48774)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 48973)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 49172)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 49371)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 49570)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 49769)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 49968)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 50167)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 50366)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 50565)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 50764)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 50963)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 51162)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 51361)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 51560)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 51759)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 51958)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 52157)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 52356)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 52555)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 52754)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 52953)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 53152)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 53351)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 53550)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 53749)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 53948)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 54147)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 54346)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 54545)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 54744)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 54943)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 55142)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 55341)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 55540)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 55739)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 55938)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 56137)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 56336)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 56535)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 56734)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 56933)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 57132)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 57331)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 57530)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 57729)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 57928)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 58127)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 58326)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 58525)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 58724)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 58923)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 59122)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 59321)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 59520)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 59719)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 59918)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 60117)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 60316)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 60515)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 60714)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 60913)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 61112)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 61311)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 61510)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 61709)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 61908)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 62107)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 62306)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 62505)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 62704)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 62903)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 63102)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 63301)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 63500)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 63699)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 63898)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 64097)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 64296)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 64495)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 64694)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 64893)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 65092)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 65291)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 65490)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 65516)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 65517)) (i32.const 1)) -(assert_return (invoke "load8_u" (i32.const 65518)) (i32.const 2)) -(assert_return (invoke "load8_u" (i32.const 65519)) (i32.const 3)) -(assert_return (invoke "load8_u" (i32.const 65520)) (i32.const 4)) -(assert_return (invoke "load8_u" (i32.const 65521)) (i32.const 5)) -(assert_return (invoke "load8_u" (i32.const 65522)) (i32.const 6)) -(assert_return (invoke "load8_u" (i32.const 65523)) (i32.const 7)) -(assert_return (invoke "load8_u" (i32.const 65524)) (i32.const 8)) -(assert_return (invoke "load8_u" (i32.const 65525)) (i32.const 9)) -(assert_return (invoke "load8_u" (i32.const 65526)) (i32.const 10)) -(assert_return (invoke "load8_u" (i32.const 65527)) (i32.const 11)) -(assert_return (invoke "load8_u" (i32.const 65528)) (i32.const 12)) -(assert_return (invoke "load8_u" (i32.const 65529)) (i32.const 13)) -(assert_return (invoke "load8_u" (i32.const 65530)) (i32.const 14)) -(assert_return (invoke "load8_u" (i32.const 65531)) (i32.const 15)) -(assert_return (invoke "load8_u" (i32.const 65532)) (i32.const 16)) -(assert_return (invoke "load8_u" (i32.const 65533)) (i32.const 17)) -(assert_return (invoke "load8_u" (i32.const 65534)) (i32.const 18)) -(assert_return (invoke "load8_u" (i32.const 65535)) (i32.const 19)) - -(module - (memory (export "mem") 1 1 ) - (data (i32.const 65515) "\00\01\02\03\04\05\06\07\08\09\0a\0b\0c\0d\0e\0f\10\11\12\13\14") - (func (export "run") (param $targetOffs i32) (param $srcOffs i32) (param $len i32) - (memory.copy (local.get $targetOffs) (local.get $srcOffs) (local.get $len))) - (func (export "load8_u") (param i32) (result i32) - (i32.load8_u (local.get 0)))) - -(assert_trap (invoke "run" (i32.const 0) (i32.const 65515) (i32.const 39)) - "out of bounds") - -(assert_return (invoke "load8_u" (i32.const 0)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 1)) (i32.const 1)) -(assert_return (invoke "load8_u" (i32.const 2)) (i32.const 2)) -(assert_return (invoke "load8_u" (i32.const 3)) (i32.const 3)) -(assert_return (invoke "load8_u" (i32.const 4)) (i32.const 4)) -(assert_return (invoke "load8_u" (i32.const 5)) (i32.const 5)) -(assert_return (invoke "load8_u" (i32.const 6)) (i32.const 6)) -(assert_return (invoke "load8_u" (i32.const 7)) (i32.const 7)) -(assert_return (invoke "load8_u" (i32.const 8)) (i32.const 8)) -(assert_return (invoke "load8_u" (i32.const 9)) (i32.const 9)) -(assert_return (invoke "load8_u" (i32.const 10)) (i32.const 10)) -(assert_return (invoke "load8_u" (i32.const 11)) (i32.const 11)) -(assert_return (invoke "load8_u" (i32.const 12)) (i32.const 12)) -(assert_return (invoke "load8_u" (i32.const 13)) (i32.const 13)) -(assert_return (invoke "load8_u" (i32.const 14)) (i32.const 14)) -(assert_return (invoke "load8_u" (i32.const 15)) (i32.const 15)) -(assert_return (invoke "load8_u" (i32.const 16)) (i32.const 16)) -(assert_return (invoke "load8_u" (i32.const 17)) (i32.const 17)) -(assert_return (invoke "load8_u" (i32.const 18)) (i32.const 18)) -(assert_return (invoke "load8_u" (i32.const 19)) (i32.const 19)) -(assert_return (invoke "load8_u" (i32.const 20)) (i32.const 20)) -(assert_return (invoke "load8_u" (i32.const 219)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 418)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 617)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 816)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 1015)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 1214)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 1413)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 1612)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 1811)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 2010)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 2209)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 2408)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 2607)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 2806)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 3005)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 3204)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 3403)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 3602)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 3801)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 4000)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 4199)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 4398)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 4597)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 4796)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 4995)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 5194)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 5393)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 5592)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 5791)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 5990)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 6189)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 6388)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 6587)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 6786)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 6985)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 7184)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 7383)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 7582)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 7781)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 7980)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 8179)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 8378)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 8577)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 8776)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 8975)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 9174)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 9373)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 9572)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 9771)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 9970)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 10169)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 10368)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 10567)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 10766)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 10965)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 11164)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 11363)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 11562)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 11761)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 11960)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 12159)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 12358)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 12557)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 12756)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 12955)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 13154)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 13353)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 13552)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 13751)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 13950)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 14149)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 14348)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 14547)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 14746)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 14945)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 15144)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 15343)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 15542)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 15741)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 15940)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 16139)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 16338)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 16537)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 16736)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 16935)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 17134)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 17333)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 17532)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 17731)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 17930)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 18129)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 18328)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 18527)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 18726)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 18925)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 19124)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 19323)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 19522)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 19721)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 19920)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 20119)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 20318)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 20517)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 20716)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 20915)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 21114)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 21313)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 21512)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 21711)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 21910)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 22109)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 22308)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 22507)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 22706)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 22905)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 23104)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 23303)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 23502)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 23701)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 23900)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 24099)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 24298)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 24497)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 24696)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 24895)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 25094)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 25293)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 25492)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 25691)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 25890)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 26089)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 26288)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 26487)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 26686)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 26885)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 27084)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 27283)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 27482)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 27681)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 27880)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 28079)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 28278)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 28477)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 28676)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 28875)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 29074)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 29273)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 29472)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 29671)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 29870)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 30069)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 30268)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 30467)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 30666)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 30865)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 31064)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 31263)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 31462)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 31661)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 31860)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 32059)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 32258)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 32457)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 32656)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 32855)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 33054)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 33253)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 33452)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 33651)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 33850)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 34049)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 34248)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 34447)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 34646)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 34845)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 35044)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 35243)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 35442)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 35641)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 35840)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 36039)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 36238)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 36437)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 36636)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 36835)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 37034)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 37233)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 37432)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 37631)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 37830)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 38029)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 38228)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 38427)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 38626)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 38825)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 39024)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 39223)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 39422)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 39621)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 39820)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 40019)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 40218)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 40417)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 40616)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 40815)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 41014)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 41213)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 41412)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 41611)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 41810)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 42009)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 42208)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 42407)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 42606)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 42805)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 43004)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 43203)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 43402)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 43601)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 43800)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 43999)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 44198)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 44397)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 44596)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 44795)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 44994)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 45193)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 45392)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 45591)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 45790)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 45989)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 46188)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 46387)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 46586)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 46785)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 46984)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 47183)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 47382)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 47581)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 47780)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 47979)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 48178)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 48377)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 48576)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 48775)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 48974)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 49173)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 49372)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 49571)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 49770)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 49969)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 50168)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 50367)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 50566)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 50765)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 50964)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 51163)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 51362)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 51561)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 51760)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 51959)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 52158)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 52357)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 52556)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 52755)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 52954)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 53153)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 53352)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 53551)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 53750)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 53949)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 54148)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 54347)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 54546)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 54745)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 54944)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 55143)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 55342)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 55541)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 55740)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 55939)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 56138)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 56337)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 56536)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 56735)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 56934)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 57133)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 57332)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 57531)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 57730)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 57929)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 58128)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 58327)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 58526)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 58725)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 58924)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 59123)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 59322)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 59521)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 59720)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 59919)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 60118)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 60317)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 60516)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 60715)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 60914)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 61113)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 61312)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 61511)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 61710)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 61909)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 62108)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 62307)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 62506)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 62705)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 62904)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 63103)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 63302)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 63501)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 63700)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 63899)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 64098)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 64297)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 64496)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 64695)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 64894)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 65093)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 65292)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 65491)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 65515)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 65516)) (i32.const 1)) -(assert_return (invoke "load8_u" (i32.const 65517)) (i32.const 2)) -(assert_return (invoke "load8_u" (i32.const 65518)) (i32.const 3)) -(assert_return (invoke "load8_u" (i32.const 65519)) (i32.const 4)) -(assert_return (invoke "load8_u" (i32.const 65520)) (i32.const 5)) -(assert_return (invoke "load8_u" (i32.const 65521)) (i32.const 6)) -(assert_return (invoke "load8_u" (i32.const 65522)) (i32.const 7)) -(assert_return (invoke "load8_u" (i32.const 65523)) (i32.const 8)) -(assert_return (invoke "load8_u" (i32.const 65524)) (i32.const 9)) -(assert_return (invoke "load8_u" (i32.const 65525)) (i32.const 10)) -(assert_return (invoke "load8_u" (i32.const 65526)) (i32.const 11)) -(assert_return (invoke "load8_u" (i32.const 65527)) (i32.const 12)) -(assert_return (invoke "load8_u" (i32.const 65528)) (i32.const 13)) -(assert_return (invoke "load8_u" (i32.const 65529)) (i32.const 14)) -(assert_return (invoke "load8_u" (i32.const 65530)) (i32.const 15)) -(assert_return (invoke "load8_u" (i32.const 65531)) (i32.const 16)) -(assert_return (invoke "load8_u" (i32.const 65532)) (i32.const 17)) -(assert_return (invoke "load8_u" (i32.const 65533)) (i32.const 18)) -(assert_return (invoke "load8_u" (i32.const 65534)) (i32.const 19)) -(assert_return (invoke "load8_u" (i32.const 65535)) (i32.const 20)) - -(module - (memory (export "mem") 1 1 ) - (data (i32.const 65486) "\00\01\02\03\04\05\06\07\08\09\0a\0b\0c\0d\0e\0f\10\11\12\13") - (func (export "run") (param $targetOffs i32) (param $srcOffs i32) (param $len i32) - (memory.copy (local.get $targetOffs) (local.get $srcOffs) (local.get $len))) - (func (export "load8_u") (param i32) (result i32) - (i32.load8_u (local.get 0)))) - -(assert_trap (invoke "run" (i32.const 65516) (i32.const 65486) (i32.const 40)) - "out of bounds") - -(assert_return (invoke "load8_u" (i32.const 198)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 397)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 596)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 795)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 994)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 1193)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 1392)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 1591)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 1790)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 1989)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 2188)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 2387)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 2586)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 2785)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 2984)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 3183)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 3382)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 3581)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 3780)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 3979)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 4178)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 4377)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 4576)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 4775)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 4974)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 5173)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 5372)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 5571)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 5770)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 5969)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 6168)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 6367)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 6566)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 6765)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 6964)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 7163)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 7362)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 7561)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 7760)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 7959)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 8158)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 8357)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 8556)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 8755)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 8954)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 9153)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 9352)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 9551)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 9750)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 9949)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 10148)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 10347)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 10546)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 10745)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 10944)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 11143)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 11342)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 11541)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 11740)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 11939)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 12138)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 12337)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 12536)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 12735)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 12934)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 13133)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 13332)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 13531)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 13730)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 13929)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 14128)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 14327)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 14526)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 14725)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 14924)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 15123)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 15322)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 15521)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 15720)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 15919)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 16118)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 16317)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 16516)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 16715)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 16914)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 17113)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 17312)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 17511)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 17710)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 17909)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 18108)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 18307)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 18506)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 18705)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 18904)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 19103)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 19302)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 19501)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 19700)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 19899)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 20098)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 20297)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 20496)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 20695)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 20894)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 21093)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 21292)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 21491)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 21690)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 21889)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 22088)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 22287)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 22486)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 22685)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 22884)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 23083)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 23282)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 23481)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 23680)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 23879)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 24078)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 24277)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 24476)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 24675)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 24874)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 25073)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 25272)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 25471)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 25670)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 25869)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 26068)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 26267)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 26466)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 26665)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 26864)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 27063)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 27262)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 27461)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 27660)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 27859)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 28058)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 28257)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 28456)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 28655)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 28854)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 29053)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 29252)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 29451)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 29650)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 29849)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 30048)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 30247)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 30446)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 30645)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 30844)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 31043)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 31242)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 31441)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 31640)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 31839)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 32038)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 32237)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 32436)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 32635)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 32834)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 33033)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 33232)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 33431)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 33630)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 33829)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 34028)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 34227)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 34426)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 34625)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 34824)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 35023)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 35222)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 35421)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 35620)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 35819)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 36018)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 36217)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 36416)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 36615)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 36814)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 37013)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 37212)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 37411)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 37610)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 37809)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 38008)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 38207)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 38406)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 38605)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 38804)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 39003)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 39202)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 39401)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 39600)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 39799)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 39998)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 40197)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 40396)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 40595)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 40794)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 40993)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 41192)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 41391)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 41590)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 41789)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 41988)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 42187)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 42386)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 42585)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 42784)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 42983)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 43182)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 43381)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 43580)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 43779)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 43978)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 44177)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 44376)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 44575)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 44774)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 44973)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 45172)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 45371)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 45570)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 45769)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 45968)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 46167)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 46366)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 46565)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 46764)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 46963)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 47162)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 47361)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 47560)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 47759)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 47958)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 48157)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 48356)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 48555)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 48754)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 48953)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 49152)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 49351)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 49550)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 49749)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 49948)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 50147)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 50346)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 50545)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 50744)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 50943)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 51142)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 51341)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 51540)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 51739)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 51938)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 52137)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 52336)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 52535)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 52734)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 52933)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 53132)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 53331)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 53530)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 53729)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 53928)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 54127)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 54326)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 54525)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 54724)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 54923)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 55122)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 55321)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 55520)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 55719)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 55918)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 56117)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 56316)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 56515)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 56714)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 56913)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 57112)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 57311)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 57510)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 57709)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 57908)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 58107)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 58306)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 58505)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 58704)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 58903)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 59102)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 59301)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 59500)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 59699)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 59898)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 60097)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 60296)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 60495)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 60694)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 60893)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 61092)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 61291)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 61490)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 61689)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 61888)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 62087)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 62286)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 62485)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 62684)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 62883)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 63082)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 63281)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 63480)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 63679)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 63878)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 64077)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 64276)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 64475)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 64674)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 64873)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 65072)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 65271)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 65470)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 65486)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 65487)) (i32.const 1)) -(assert_return (invoke "load8_u" (i32.const 65488)) (i32.const 2)) -(assert_return (invoke "load8_u" (i32.const 65489)) (i32.const 3)) -(assert_return (invoke "load8_u" (i32.const 65490)) (i32.const 4)) -(assert_return (invoke "load8_u" (i32.const 65491)) (i32.const 5)) -(assert_return (invoke "load8_u" (i32.const 65492)) (i32.const 6)) -(assert_return (invoke "load8_u" (i32.const 65493)) (i32.const 7)) -(assert_return (invoke "load8_u" (i32.const 65494)) (i32.const 8)) -(assert_return (invoke "load8_u" (i32.const 65495)) (i32.const 9)) -(assert_return (invoke "load8_u" (i32.const 65496)) (i32.const 10)) -(assert_return (invoke "load8_u" (i32.const 65497)) (i32.const 11)) -(assert_return (invoke "load8_u" (i32.const 65498)) (i32.const 12)) -(assert_return (invoke "load8_u" (i32.const 65499)) (i32.const 13)) -(assert_return (invoke "load8_u" (i32.const 65500)) (i32.const 14)) -(assert_return (invoke "load8_u" (i32.const 65501)) (i32.const 15)) -(assert_return (invoke "load8_u" (i32.const 65502)) (i32.const 16)) -(assert_return (invoke "load8_u" (i32.const 65503)) (i32.const 17)) -(assert_return (invoke "load8_u" (i32.const 65504)) (i32.const 18)) -(assert_return (invoke "load8_u" (i32.const 65505)) (i32.const 19)) - -(module - (memory (export "mem") 1 1 ) - (data (i32.const 65516) "\00\01\02\03\04\05\06\07\08\09\0a\0b\0c\0d\0e\0f\10\11\12\13") - (func (export "run") (param $targetOffs i32) (param $srcOffs i32) (param $len i32) - (memory.copy (local.get $targetOffs) (local.get $srcOffs) (local.get $len))) - (func (export "load8_u") (param i32) (result i32) - (i32.load8_u (local.get 0)))) - -(assert_trap (invoke "run" (i32.const 65486) (i32.const 65516) (i32.const 40)) - "out of bounds") - -(assert_return (invoke "load8_u" (i32.const 198)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 397)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 596)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 795)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 994)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 1193)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 1392)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 1591)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 1790)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 1989)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 2188)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 2387)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 2586)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 2785)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 2984)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 3183)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 3382)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 3581)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 3780)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 3979)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 4178)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 4377)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 4576)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 4775)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 4974)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 5173)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 5372)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 5571)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 5770)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 5969)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 6168)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 6367)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 6566)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 6765)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 6964)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 7163)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 7362)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 7561)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 7760)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 7959)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 8158)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 8357)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 8556)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 8755)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 8954)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 9153)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 9352)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 9551)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 9750)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 9949)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 10148)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 10347)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 10546)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 10745)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 10944)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 11143)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 11342)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 11541)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 11740)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 11939)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 12138)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 12337)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 12536)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 12735)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 12934)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 13133)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 13332)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 13531)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 13730)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 13929)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 14128)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 14327)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 14526)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 14725)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 14924)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 15123)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 15322)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 15521)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 15720)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 15919)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 16118)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 16317)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 16516)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 16715)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 16914)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 17113)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 17312)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 17511)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 17710)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 17909)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 18108)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 18307)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 18506)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 18705)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 18904)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 19103)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 19302)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 19501)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 19700)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 19899)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 20098)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 20297)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 20496)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 20695)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 20894)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 21093)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 21292)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 21491)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 21690)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 21889)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 22088)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 22287)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 22486)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 22685)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 22884)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 23083)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 23282)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 23481)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 23680)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 23879)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 24078)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 24277)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 24476)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 24675)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 24874)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 25073)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 25272)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 25471)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 25670)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 25869)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 26068)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 26267)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 26466)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 26665)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 26864)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 27063)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 27262)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 27461)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 27660)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 27859)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 28058)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 28257)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 28456)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 28655)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 28854)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 29053)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 29252)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 29451)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 29650)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 29849)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 30048)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 30247)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 30446)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 30645)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 30844)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 31043)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 31242)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 31441)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 31640)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 31839)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 32038)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 32237)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 32436)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 32635)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 32834)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 33033)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 33232)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 33431)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 33630)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 33829)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 34028)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 34227)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 34426)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 34625)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 34824)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 35023)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 35222)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 35421)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 35620)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 35819)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 36018)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 36217)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 36416)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 36615)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 36814)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 37013)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 37212)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 37411)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 37610)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 37809)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 38008)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 38207)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 38406)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 38605)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 38804)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 39003)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 39202)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 39401)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 39600)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 39799)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 39998)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 40197)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 40396)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 40595)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 40794)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 40993)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 41192)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 41391)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 41590)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 41789)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 41988)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 42187)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 42386)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 42585)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 42784)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 42983)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 43182)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 43381)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 43580)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 43779)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 43978)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 44177)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 44376)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 44575)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 44774)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 44973)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 45172)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 45371)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 45570)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 45769)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 45968)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 46167)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 46366)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 46565)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 46764)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 46963)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 47162)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 47361)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 47560)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 47759)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 47958)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 48157)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 48356)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 48555)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 48754)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 48953)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 49152)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 49351)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 49550)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 49749)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 49948)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 50147)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 50346)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 50545)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 50744)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 50943)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 51142)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 51341)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 51540)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 51739)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 51938)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 52137)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 52336)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 52535)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 52734)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 52933)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 53132)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 53331)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 53530)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 53729)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 53928)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 54127)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 54326)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 54525)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 54724)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 54923)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 55122)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 55321)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 55520)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 55719)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 55918)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 56117)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 56316)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 56515)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 56714)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 56913)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 57112)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 57311)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 57510)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 57709)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 57908)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 58107)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 58306)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 58505)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 58704)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 58903)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 59102)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 59301)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 59500)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 59699)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 59898)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 60097)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 60296)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 60495)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 60694)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 60893)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 61092)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 61291)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 61490)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 61689)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 61888)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 62087)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 62286)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 62485)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 62684)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 62883)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 63082)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 63281)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 63480)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 63679)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 63878)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 64077)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 64276)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 64475)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 64674)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 64873)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 65072)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 65271)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 65470)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 65486)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 65487)) (i32.const 1)) -(assert_return (invoke "load8_u" (i32.const 65488)) (i32.const 2)) -(assert_return (invoke "load8_u" (i32.const 65489)) (i32.const 3)) -(assert_return (invoke "load8_u" (i32.const 65490)) (i32.const 4)) -(assert_return (invoke "load8_u" (i32.const 65491)) (i32.const 5)) -(assert_return (invoke "load8_u" (i32.const 65492)) (i32.const 6)) -(assert_return (invoke "load8_u" (i32.const 65493)) (i32.const 7)) -(assert_return (invoke "load8_u" (i32.const 65494)) (i32.const 8)) -(assert_return (invoke "load8_u" (i32.const 65495)) (i32.const 9)) -(assert_return (invoke "load8_u" (i32.const 65496)) (i32.const 10)) -(assert_return (invoke "load8_u" (i32.const 65497)) (i32.const 11)) -(assert_return (invoke "load8_u" (i32.const 65498)) (i32.const 12)) -(assert_return (invoke "load8_u" (i32.const 65499)) (i32.const 13)) -(assert_return (invoke "load8_u" (i32.const 65500)) (i32.const 14)) -(assert_return (invoke "load8_u" (i32.const 65501)) (i32.const 15)) -(assert_return (invoke "load8_u" (i32.const 65502)) (i32.const 16)) -(assert_return (invoke "load8_u" (i32.const 65503)) (i32.const 17)) -(assert_return (invoke "load8_u" (i32.const 65504)) (i32.const 18)) -(assert_return (invoke "load8_u" (i32.const 65505)) (i32.const 19)) -(assert_return (invoke "load8_u" (i32.const 65516)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 65517)) (i32.const 1)) -(assert_return (invoke "load8_u" (i32.const 65518)) (i32.const 2)) -(assert_return (invoke "load8_u" (i32.const 65519)) (i32.const 3)) -(assert_return (invoke "load8_u" (i32.const 65520)) (i32.const 4)) -(assert_return (invoke "load8_u" (i32.const 65521)) (i32.const 5)) -(assert_return (invoke "load8_u" (i32.const 65522)) (i32.const 6)) -(assert_return (invoke "load8_u" (i32.const 65523)) (i32.const 7)) -(assert_return (invoke "load8_u" (i32.const 65524)) (i32.const 8)) -(assert_return (invoke "load8_u" (i32.const 65525)) (i32.const 9)) -(assert_return (invoke "load8_u" (i32.const 65526)) (i32.const 10)) -(assert_return (invoke "load8_u" (i32.const 65527)) (i32.const 11)) -(assert_return (invoke "load8_u" (i32.const 65528)) (i32.const 12)) -(assert_return (invoke "load8_u" (i32.const 65529)) (i32.const 13)) -(assert_return (invoke "load8_u" (i32.const 65530)) (i32.const 14)) -(assert_return (invoke "load8_u" (i32.const 65531)) (i32.const 15)) -(assert_return (invoke "load8_u" (i32.const 65532)) (i32.const 16)) -(assert_return (invoke "load8_u" (i32.const 65533)) (i32.const 17)) -(assert_return (invoke "load8_u" (i32.const 65534)) (i32.const 18)) -(assert_return (invoke "load8_u" (i32.const 65535)) (i32.const 19)) - -(module - (memory (export "mem") 1 1 ) - (data (i32.const 65506) "\00\01\02\03\04\05\06\07\08\09\0a\0b\0c\0d\0e\0f\10\11\12\13") - (func (export "run") (param $targetOffs i32) (param $srcOffs i32) (param $len i32) - (memory.copy (local.get $targetOffs) (local.get $srcOffs) (local.get $len))) - (func (export "load8_u") (param i32) (result i32) - (i32.load8_u (local.get 0)))) - -(assert_trap (invoke "run" (i32.const 65516) (i32.const 65506) (i32.const 40)) - "out of bounds") - -(assert_return (invoke "load8_u" (i32.const 198)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 397)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 596)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 795)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 994)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 1193)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 1392)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 1591)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 1790)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 1989)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 2188)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 2387)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 2586)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 2785)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 2984)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 3183)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 3382)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 3581)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 3780)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 3979)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 4178)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 4377)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 4576)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 4775)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 4974)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 5173)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 5372)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 5571)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 5770)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 5969)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 6168)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 6367)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 6566)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 6765)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 6964)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 7163)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 7362)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 7561)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 7760)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 7959)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 8158)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 8357)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 8556)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 8755)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 8954)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 9153)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 9352)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 9551)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 9750)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 9949)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 10148)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 10347)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 10546)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 10745)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 10944)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 11143)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 11342)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 11541)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 11740)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 11939)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 12138)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 12337)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 12536)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 12735)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 12934)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 13133)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 13332)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 13531)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 13730)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 13929)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 14128)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 14327)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 14526)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 14725)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 14924)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 15123)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 15322)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 15521)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 15720)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 15919)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 16118)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 16317)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 16516)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 16715)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 16914)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 17113)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 17312)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 17511)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 17710)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 17909)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 18108)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 18307)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 18506)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 18705)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 18904)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 19103)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 19302)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 19501)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 19700)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 19899)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 20098)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 20297)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 20496)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 20695)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 20894)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 21093)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 21292)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 21491)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 21690)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 21889)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 22088)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 22287)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 22486)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 22685)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 22884)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 23083)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 23282)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 23481)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 23680)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 23879)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 24078)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 24277)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 24476)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 24675)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 24874)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 25073)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 25272)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 25471)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 25670)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 25869)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 26068)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 26267)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 26466)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 26665)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 26864)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 27063)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 27262)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 27461)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 27660)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 27859)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 28058)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 28257)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 28456)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 28655)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 28854)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 29053)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 29252)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 29451)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 29650)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 29849)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 30048)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 30247)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 30446)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 30645)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 30844)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 31043)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 31242)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 31441)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 31640)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 31839)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 32038)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 32237)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 32436)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 32635)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 32834)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 33033)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 33232)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 33431)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 33630)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 33829)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 34028)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 34227)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 34426)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 34625)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 34824)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 35023)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 35222)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 35421)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 35620)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 35819)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 36018)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 36217)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 36416)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 36615)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 36814)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 37013)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 37212)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 37411)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 37610)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 37809)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 38008)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 38207)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 38406)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 38605)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 38804)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 39003)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 39202)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 39401)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 39600)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 39799)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 39998)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 40197)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 40396)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 40595)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 40794)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 40993)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 41192)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 41391)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 41590)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 41789)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 41988)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 42187)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 42386)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 42585)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 42784)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 42983)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 43182)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 43381)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 43580)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 43779)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 43978)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 44177)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 44376)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 44575)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 44774)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 44973)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 45172)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 45371)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 45570)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 45769)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 45968)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 46167)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 46366)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 46565)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 46764)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 46963)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 47162)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 47361)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 47560)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 47759)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 47958)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 48157)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 48356)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 48555)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 48754)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 48953)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 49152)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 49351)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 49550)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 49749)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 49948)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 50147)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 50346)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 50545)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 50744)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 50943)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 51142)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 51341)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 51540)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 51739)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 51938)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 52137)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 52336)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 52535)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 52734)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 52933)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 53132)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 53331)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 53530)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 53729)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 53928)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 54127)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 54326)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 54525)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 54724)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 54923)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 55122)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 55321)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 55520)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 55719)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 55918)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 56117)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 56316)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 56515)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 56714)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 56913)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 57112)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 57311)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 57510)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 57709)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 57908)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 58107)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 58306)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 58505)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 58704)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 58903)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 59102)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 59301)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 59500)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 59699)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 59898)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 60097)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 60296)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 60495)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 60694)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 60893)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 61092)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 61291)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 61490)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 61689)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 61888)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 62087)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 62286)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 62485)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 62684)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 62883)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 63082)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 63281)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 63480)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 63679)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 63878)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 64077)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 64276)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 64475)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 64674)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 64873)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 65072)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 65271)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 65470)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 65506)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 65507)) (i32.const 1)) -(assert_return (invoke "load8_u" (i32.const 65508)) (i32.const 2)) -(assert_return (invoke "load8_u" (i32.const 65509)) (i32.const 3)) -(assert_return (invoke "load8_u" (i32.const 65510)) (i32.const 4)) -(assert_return (invoke "load8_u" (i32.const 65511)) (i32.const 5)) -(assert_return (invoke "load8_u" (i32.const 65512)) (i32.const 6)) -(assert_return (invoke "load8_u" (i32.const 65513)) (i32.const 7)) -(assert_return (invoke "load8_u" (i32.const 65514)) (i32.const 8)) -(assert_return (invoke "load8_u" (i32.const 65515)) (i32.const 9)) -(assert_return (invoke "load8_u" (i32.const 65516)) (i32.const 10)) -(assert_return (invoke "load8_u" (i32.const 65517)) (i32.const 11)) -(assert_return (invoke "load8_u" (i32.const 65518)) (i32.const 12)) -(assert_return (invoke "load8_u" (i32.const 65519)) (i32.const 13)) -(assert_return (invoke "load8_u" (i32.const 65520)) (i32.const 14)) -(assert_return (invoke "load8_u" (i32.const 65521)) (i32.const 15)) -(assert_return (invoke "load8_u" (i32.const 65522)) (i32.const 16)) -(assert_return (invoke "load8_u" (i32.const 65523)) (i32.const 17)) -(assert_return (invoke "load8_u" (i32.const 65524)) (i32.const 18)) -(assert_return (invoke "load8_u" (i32.const 65525)) (i32.const 19)) - -(module - (memory (export "mem") 1 1 ) - (data (i32.const 65516) "\00\01\02\03\04\05\06\07\08\09\0a\0b\0c\0d\0e\0f\10\11\12\13") - (func (export "run") (param $targetOffs i32) (param $srcOffs i32) (param $len i32) - (memory.copy (local.get $targetOffs) (local.get $srcOffs) (local.get $len))) - (func (export "load8_u") (param i32) (result i32) - (i32.load8_u (local.get 0)))) - -(assert_trap (invoke "run" (i32.const 65506) (i32.const 65516) (i32.const 40)) - "out of bounds") - -(assert_return (invoke "load8_u" (i32.const 198)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 397)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 596)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 795)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 994)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 1193)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 1392)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 1591)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 1790)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 1989)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 2188)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 2387)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 2586)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 2785)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 2984)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 3183)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 3382)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 3581)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 3780)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 3979)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 4178)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 4377)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 4576)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 4775)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 4974)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 5173)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 5372)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 5571)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 5770)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 5969)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 6168)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 6367)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 6566)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 6765)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 6964)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 7163)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 7362)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 7561)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 7760)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 7959)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 8158)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 8357)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 8556)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 8755)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 8954)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 9153)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 9352)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 9551)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 9750)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 9949)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 10148)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 10347)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 10546)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 10745)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 10944)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 11143)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 11342)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 11541)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 11740)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 11939)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 12138)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 12337)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 12536)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 12735)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 12934)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 13133)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 13332)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 13531)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 13730)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 13929)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 14128)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 14327)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 14526)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 14725)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 14924)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 15123)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 15322)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 15521)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 15720)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 15919)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 16118)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 16317)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 16516)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 16715)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 16914)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 17113)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 17312)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 17511)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 17710)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 17909)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 18108)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 18307)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 18506)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 18705)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 18904)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 19103)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 19302)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 19501)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 19700)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 19899)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 20098)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 20297)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 20496)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 20695)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 20894)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 21093)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 21292)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 21491)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 21690)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 21889)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 22088)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 22287)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 22486)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 22685)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 22884)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 23083)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 23282)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 23481)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 23680)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 23879)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 24078)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 24277)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 24476)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 24675)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 24874)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 25073)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 25272)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 25471)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 25670)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 25869)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 26068)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 26267)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 26466)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 26665)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 26864)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 27063)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 27262)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 27461)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 27660)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 27859)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 28058)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 28257)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 28456)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 28655)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 28854)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 29053)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 29252)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 29451)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 29650)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 29849)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 30048)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 30247)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 30446)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 30645)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 30844)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 31043)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 31242)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 31441)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 31640)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 31839)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 32038)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 32237)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 32436)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 32635)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 32834)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 33033)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 33232)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 33431)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 33630)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 33829)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 34028)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 34227)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 34426)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 34625)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 34824)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 35023)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 35222)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 35421)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 35620)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 35819)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 36018)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 36217)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 36416)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 36615)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 36814)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 37013)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 37212)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 37411)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 37610)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 37809)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 38008)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 38207)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 38406)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 38605)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 38804)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 39003)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 39202)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 39401)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 39600)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 39799)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 39998)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 40197)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 40396)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 40595)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 40794)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 40993)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 41192)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 41391)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 41590)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 41789)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 41988)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 42187)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 42386)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 42585)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 42784)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 42983)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 43182)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 43381)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 43580)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 43779)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 43978)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 44177)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 44376)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 44575)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 44774)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 44973)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 45172)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 45371)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 45570)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 45769)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 45968)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 46167)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 46366)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 46565)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 46764)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 46963)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 47162)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 47361)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 47560)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 47759)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 47958)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 48157)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 48356)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 48555)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 48754)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 48953)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 49152)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 49351)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 49550)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 49749)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 49948)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 50147)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 50346)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 50545)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 50744)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 50943)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 51142)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 51341)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 51540)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 51739)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 51938)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 52137)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 52336)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 52535)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 52734)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 52933)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 53132)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 53331)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 53530)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 53729)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 53928)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 54127)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 54326)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 54525)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 54724)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 54923)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 55122)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 55321)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 55520)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 55719)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 55918)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 56117)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 56316)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 56515)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 56714)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 56913)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 57112)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 57311)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 57510)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 57709)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 57908)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 58107)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 58306)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 58505)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 58704)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 58903)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 59102)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 59301)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 59500)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 59699)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 59898)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 60097)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 60296)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 60495)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 60694)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 60893)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 61092)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 61291)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 61490)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 61689)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 61888)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 62087)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 62286)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 62485)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 62684)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 62883)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 63082)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 63281)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 63480)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 63679)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 63878)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 64077)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 64276)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 64475)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 64674)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 64873)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 65072)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 65271)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 65470)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 65506)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 65507)) (i32.const 1)) -(assert_return (invoke "load8_u" (i32.const 65508)) (i32.const 2)) -(assert_return (invoke "load8_u" (i32.const 65509)) (i32.const 3)) -(assert_return (invoke "load8_u" (i32.const 65510)) (i32.const 4)) -(assert_return (invoke "load8_u" (i32.const 65511)) (i32.const 5)) -(assert_return (invoke "load8_u" (i32.const 65512)) (i32.const 6)) -(assert_return (invoke "load8_u" (i32.const 65513)) (i32.const 7)) -(assert_return (invoke "load8_u" (i32.const 65514)) (i32.const 8)) -(assert_return (invoke "load8_u" (i32.const 65515)) (i32.const 9)) -(assert_return (invoke "load8_u" (i32.const 65516)) (i32.const 10)) -(assert_return (invoke "load8_u" (i32.const 65517)) (i32.const 11)) -(assert_return (invoke "load8_u" (i32.const 65518)) (i32.const 12)) -(assert_return (invoke "load8_u" (i32.const 65519)) (i32.const 13)) -(assert_return (invoke "load8_u" (i32.const 65520)) (i32.const 14)) -(assert_return (invoke "load8_u" (i32.const 65521)) (i32.const 15)) -(assert_return (invoke "load8_u" (i32.const 65522)) (i32.const 16)) -(assert_return (invoke "load8_u" (i32.const 65523)) (i32.const 17)) -(assert_return (invoke "load8_u" (i32.const 65524)) (i32.const 18)) -(assert_return (invoke "load8_u" (i32.const 65525)) (i32.const 19)) -(assert_return (invoke "load8_u" (i32.const 65526)) (i32.const 10)) -(assert_return (invoke "load8_u" (i32.const 65527)) (i32.const 11)) -(assert_return (invoke "load8_u" (i32.const 65528)) (i32.const 12)) -(assert_return (invoke "load8_u" (i32.const 65529)) (i32.const 13)) -(assert_return (invoke "load8_u" (i32.const 65530)) (i32.const 14)) -(assert_return (invoke "load8_u" (i32.const 65531)) (i32.const 15)) -(assert_return (invoke "load8_u" (i32.const 65532)) (i32.const 16)) -(assert_return (invoke "load8_u" (i32.const 65533)) (i32.const 17)) -(assert_return (invoke "load8_u" (i32.const 65534)) (i32.const 18)) -(assert_return (invoke "load8_u" (i32.const 65535)) (i32.const 19)) - -(module - (memory (export "mem") 1 1 ) - (data (i32.const 65516) "\00\01\02\03\04\05\06\07\08\09\0a\0b\0c\0d\0e\0f\10\11\12\13") - (func (export "run") (param $targetOffs i32) (param $srcOffs i32) (param $len i32) - (memory.copy (local.get $targetOffs) (local.get $srcOffs) (local.get $len))) - (func (export "load8_u") (param i32) (result i32) - (i32.load8_u (local.get 0)))) - -(assert_trap (invoke "run" (i32.const 65516) (i32.const 65516) (i32.const 40)) - "out of bounds") - -(assert_return (invoke "load8_u" (i32.const 198)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 397)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 596)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 795)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 994)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 1193)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 1392)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 1591)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 1790)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 1989)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 2188)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 2387)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 2586)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 2785)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 2984)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 3183)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 3382)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 3581)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 3780)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 3979)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 4178)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 4377)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 4576)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 4775)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 4974)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 5173)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 5372)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 5571)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 5770)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 5969)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 6168)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 6367)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 6566)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 6765)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 6964)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 7163)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 7362)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 7561)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 7760)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 7959)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 8158)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 8357)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 8556)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 8755)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 8954)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 9153)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 9352)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 9551)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 9750)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 9949)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 10148)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 10347)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 10546)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 10745)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 10944)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 11143)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 11342)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 11541)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 11740)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 11939)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 12138)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 12337)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 12536)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 12735)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 12934)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 13133)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 13332)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 13531)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 13730)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 13929)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 14128)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 14327)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 14526)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 14725)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 14924)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 15123)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 15322)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 15521)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 15720)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 15919)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 16118)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 16317)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 16516)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 16715)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 16914)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 17113)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 17312)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 17511)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 17710)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 17909)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 18108)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 18307)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 18506)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 18705)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 18904)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 19103)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 19302)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 19501)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 19700)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 19899)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 20098)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 20297)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 20496)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 20695)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 20894)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 21093)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 21292)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 21491)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 21690)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 21889)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 22088)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 22287)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 22486)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 22685)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 22884)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 23083)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 23282)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 23481)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 23680)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 23879)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 24078)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 24277)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 24476)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 24675)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 24874)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 25073)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 25272)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 25471)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 25670)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 25869)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 26068)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 26267)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 26466)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 26665)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 26864)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 27063)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 27262)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 27461)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 27660)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 27859)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 28058)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 28257)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 28456)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 28655)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 28854)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 29053)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 29252)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 29451)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 29650)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 29849)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 30048)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 30247)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 30446)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 30645)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 30844)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 31043)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 31242)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 31441)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 31640)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 31839)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 32038)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 32237)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 32436)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 32635)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 32834)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 33033)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 33232)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 33431)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 33630)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 33829)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 34028)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 34227)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 34426)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 34625)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 34824)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 35023)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 35222)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 35421)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 35620)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 35819)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 36018)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 36217)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 36416)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 36615)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 36814)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 37013)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 37212)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 37411)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 37610)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 37809)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 38008)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 38207)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 38406)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 38605)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 38804)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 39003)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 39202)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 39401)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 39600)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 39799)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 39998)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 40197)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 40396)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 40595)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 40794)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 40993)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 41192)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 41391)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 41590)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 41789)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 41988)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 42187)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 42386)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 42585)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 42784)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 42983)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 43182)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 43381)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 43580)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 43779)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 43978)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 44177)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 44376)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 44575)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 44774)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 44973)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 45172)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 45371)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 45570)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 45769)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 45968)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 46167)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 46366)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 46565)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 46764)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 46963)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 47162)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 47361)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 47560)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 47759)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 47958)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 48157)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 48356)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 48555)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 48754)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 48953)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 49152)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 49351)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 49550)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 49749)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 49948)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 50147)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 50346)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 50545)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 50744)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 50943)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 51142)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 51341)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 51540)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 51739)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 51938)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 52137)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 52336)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 52535)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 52734)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 52933)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 53132)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 53331)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 53530)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 53729)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 53928)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 54127)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 54326)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 54525)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 54724)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 54923)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 55122)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 55321)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 55520)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 55719)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 55918)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 56117)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 56316)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 56515)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 56714)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 56913)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 57112)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 57311)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 57510)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 57709)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 57908)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 58107)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 58306)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 58505)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 58704)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 58903)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 59102)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 59301)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 59500)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 59699)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 59898)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 60097)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 60296)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 60495)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 60694)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 60893)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 61092)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 61291)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 61490)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 61689)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 61888)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 62087)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 62286)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 62485)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 62684)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 62883)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 63082)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 63281)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 63480)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 63679)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 63878)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 64077)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 64276)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 64475)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 64674)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 64873)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 65072)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 65271)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 65470)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 65516)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 65517)) (i32.const 1)) -(assert_return (invoke "load8_u" (i32.const 65518)) (i32.const 2)) -(assert_return (invoke "load8_u" (i32.const 65519)) (i32.const 3)) -(assert_return (invoke "load8_u" (i32.const 65520)) (i32.const 4)) -(assert_return (invoke "load8_u" (i32.const 65521)) (i32.const 5)) -(assert_return (invoke "load8_u" (i32.const 65522)) (i32.const 6)) -(assert_return (invoke "load8_u" (i32.const 65523)) (i32.const 7)) -(assert_return (invoke "load8_u" (i32.const 65524)) (i32.const 8)) -(assert_return (invoke "load8_u" (i32.const 65525)) (i32.const 9)) -(assert_return (invoke "load8_u" (i32.const 65526)) (i32.const 10)) -(assert_return (invoke "load8_u" (i32.const 65527)) (i32.const 11)) -(assert_return (invoke "load8_u" (i32.const 65528)) (i32.const 12)) -(assert_return (invoke "load8_u" (i32.const 65529)) (i32.const 13)) -(assert_return (invoke "load8_u" (i32.const 65530)) (i32.const 14)) -(assert_return (invoke "load8_u" (i32.const 65531)) (i32.const 15)) -(assert_return (invoke "load8_u" (i32.const 65532)) (i32.const 16)) -(assert_return (invoke "load8_u" (i32.const 65533)) (i32.const 17)) -(assert_return (invoke "load8_u" (i32.const 65534)) (i32.const 18)) -(assert_return (invoke "load8_u" (i32.const 65535)) (i32.const 19)) - -(module - (memory (export "mem") 1 ) - (data (i32.const 65516) "\00\01\02\03\04\05\06\07\08\09\0a\0b\0c\0d\0e\0f\10\11\12\13") - (func (export "run") (param $targetOffs i32) (param $srcOffs i32) (param $len i32) - (memory.copy (local.get $targetOffs) (local.get $srcOffs) (local.get $len))) - (func (export "load8_u") (param i32) (result i32) - (i32.load8_u (local.get 0)))) - -(assert_trap (invoke "run" (i32.const 0) (i32.const 65516) (i32.const 4294963200)) - "out of bounds") - -(assert_return (invoke "load8_u" (i32.const 0)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 1)) (i32.const 1)) -(assert_return (invoke "load8_u" (i32.const 2)) (i32.const 2)) -(assert_return (invoke "load8_u" (i32.const 3)) (i32.const 3)) -(assert_return (invoke "load8_u" (i32.const 4)) (i32.const 4)) -(assert_return (invoke "load8_u" (i32.const 5)) (i32.const 5)) -(assert_return (invoke "load8_u" (i32.const 6)) (i32.const 6)) -(assert_return (invoke "load8_u" (i32.const 7)) (i32.const 7)) -(assert_return (invoke "load8_u" (i32.const 8)) (i32.const 8)) -(assert_return (invoke "load8_u" (i32.const 9)) (i32.const 9)) -(assert_return (invoke "load8_u" (i32.const 10)) (i32.const 10)) -(assert_return (invoke "load8_u" (i32.const 11)) (i32.const 11)) -(assert_return (invoke "load8_u" (i32.const 12)) (i32.const 12)) -(assert_return (invoke "load8_u" (i32.const 13)) (i32.const 13)) -(assert_return (invoke "load8_u" (i32.const 14)) (i32.const 14)) -(assert_return (invoke "load8_u" (i32.const 15)) (i32.const 15)) -(assert_return (invoke "load8_u" (i32.const 16)) (i32.const 16)) -(assert_return (invoke "load8_u" (i32.const 17)) (i32.const 17)) -(assert_return (invoke "load8_u" (i32.const 18)) (i32.const 18)) -(assert_return (invoke "load8_u" (i32.const 19)) (i32.const 19)) -(assert_return (invoke "load8_u" (i32.const 218)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 417)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 616)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 815)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 1014)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 1213)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 1412)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 1611)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 1810)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 2009)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 2208)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 2407)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 2606)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 2805)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 3004)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 3203)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 3402)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 3601)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 3800)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 3999)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 4198)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 4397)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 4596)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 4795)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 4994)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 5193)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 5392)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 5591)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 5790)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 5989)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 6188)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 6387)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 6586)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 6785)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 6984)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 7183)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 7382)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 7581)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 7780)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 7979)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 8178)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 8377)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 8576)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 8775)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 8974)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 9173)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 9372)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 9571)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 9770)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 9969)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 10168)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 10367)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 10566)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 10765)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 10964)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 11163)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 11362)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 11561)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 11760)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 11959)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 12158)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 12357)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 12556)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 12755)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 12954)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 13153)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 13352)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 13551)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 13750)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 13949)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 14148)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 14347)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 14546)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 14745)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 14944)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 15143)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 15342)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 15541)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 15740)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 15939)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 16138)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 16337)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 16536)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 16735)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 16934)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 17133)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 17332)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 17531)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 17730)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 17929)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 18128)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 18327)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 18526)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 18725)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 18924)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 19123)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 19322)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 19521)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 19720)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 19919)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 20118)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 20317)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 20516)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 20715)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 20914)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 21113)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 21312)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 21511)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 21710)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 21909)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 22108)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 22307)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 22506)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 22705)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 22904)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 23103)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 23302)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 23501)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 23700)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 23899)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 24098)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 24297)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 24496)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 24695)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 24894)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 25093)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 25292)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 25491)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 25690)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 25889)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 26088)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 26287)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 26486)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 26685)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 26884)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 27083)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 27282)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 27481)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 27680)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 27879)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 28078)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 28277)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 28476)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 28675)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 28874)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 29073)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 29272)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 29471)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 29670)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 29869)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 30068)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 30267)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 30466)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 30665)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 30864)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 31063)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 31262)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 31461)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 31660)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 31859)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 32058)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 32257)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 32456)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 32655)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 32854)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 33053)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 33252)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 33451)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 33650)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 33849)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 34048)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 34247)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 34446)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 34645)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 34844)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 35043)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 35242)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 35441)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 35640)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 35839)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 36038)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 36237)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 36436)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 36635)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 36834)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 37033)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 37232)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 37431)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 37630)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 37829)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 38028)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 38227)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 38426)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 38625)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 38824)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 39023)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 39222)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 39421)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 39620)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 39819)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 40018)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 40217)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 40416)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 40615)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 40814)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 41013)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 41212)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 41411)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 41610)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 41809)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 42008)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 42207)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 42406)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 42605)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 42804)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 43003)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 43202)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 43401)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 43600)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 43799)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 43998)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 44197)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 44396)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 44595)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 44794)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 44993)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 45192)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 45391)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 45590)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 45789)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 45988)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 46187)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 46386)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 46585)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 46784)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 46983)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 47182)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 47381)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 47580)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 47779)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 47978)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 48177)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 48376)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 48575)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 48774)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 48973)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 49172)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 49371)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 49570)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 49769)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 49968)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 50167)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 50366)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 50565)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 50764)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 50963)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 51162)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 51361)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 51560)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 51759)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 51958)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 52157)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 52356)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 52555)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 52754)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 52953)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 53152)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 53351)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 53550)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 53749)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 53948)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 54147)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 54346)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 54545)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 54744)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 54943)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 55142)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 55341)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 55540)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 55739)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 55938)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 56137)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 56336)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 56535)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 56734)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 56933)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 57132)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 57331)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 57530)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 57729)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 57928)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 58127)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 58326)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 58525)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 58724)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 58923)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 59122)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 59321)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 59520)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 59719)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 59918)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 60117)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 60316)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 60515)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 60714)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 60913)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 61112)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 61311)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 61510)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 61709)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 61908)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 62107)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 62306)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 62505)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 62704)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 62903)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 63102)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 63301)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 63500)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 63699)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 63898)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 64097)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 64296)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 64495)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 64694)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 64893)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 65092)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 65291)) (i32.const 0)) -(assert_return (invoke "load8_u" (i32.const 65490)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 198)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 397)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 596)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 795)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 994)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 1193)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 1392)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 1591)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 1790)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 1989)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 2188)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 2387)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 2586)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 2785)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 2984)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 3183)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 3382)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 3581)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 3780)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 3979)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 4178)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 4377)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 4576)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 4775)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 4974)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 5173)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 5372)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 5571)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 5770)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 5969)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 6168)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 6367)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 6566)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 6765)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 6964)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 7163)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 7362)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 7561)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 7760)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 7959)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 8158)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 8357)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 8556)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 8755)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 8954)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 9153)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 9352)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 9551)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 9750)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 9949)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 10148)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 10347)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 10546)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 10745)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 10944)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 11143)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 11342)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 11541)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 11740)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 11939)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 12138)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 12337)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 12536)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 12735)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 12934)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 13133)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 13332)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 13531)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 13730)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 13929)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 14128)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 14327)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 14526)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 14725)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 14924)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 15123)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 15322)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 15521)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 15720)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 15919)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 16118)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 16317)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 16516)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 16715)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 16914)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 17113)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 17312)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 17511)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 17710)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 17909)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 18108)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 18307)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 18506)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 18705)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 18904)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 19103)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 19302)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 19501)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 19700)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 19899)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 20098)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 20297)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 20496)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 20695)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 20894)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 21093)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 21292)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 21491)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 21690)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 21889)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 22088)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 22287)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 22486)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 22685)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 22884)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 23083)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 23282)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 23481)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 23680)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 23879)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 24078)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 24277)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 24476)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 24675)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 24874)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 25073)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 25272)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 25471)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 25670)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 25869)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 26068)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 26267)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 26466)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 26665)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 26864)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 27063)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 27262)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 27461)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 27660)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 27859)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 28058)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 28257)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 28456)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 28655)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 28854)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 29053)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 29252)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 29451)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 29650)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 29849)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 30048)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 30247)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 30446)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 30645)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 30844)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 31043)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 31242)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 31441)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 31640)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 31839)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 32038)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 32237)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 32436)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 32635)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 32834)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 33033)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 33232)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 33431)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 33630)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 33829)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 34028)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 34227)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 34426)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 34625)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 34824)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 35023)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 35222)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 35421)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 35620)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 35819)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 36018)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 36217)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 36416)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 36615)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 36814)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 37013)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 37212)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 37411)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 37610)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 37809)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 38008)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 38207)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 38406)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 38605)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 38804)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 39003)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 39202)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 39401)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 39600)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 39799)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 39998)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 40197)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 40396)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 40595)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 40794)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 40993)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 41192)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 41391)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 41590)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 41789)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 41988)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 42187)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 42386)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 42585)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 42784)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 42983)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 43182)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 43381)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 43580)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 43779)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 43978)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 44177)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 44376)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 44575)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 44774)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 44973)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 45172)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 45371)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 45570)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 45769)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 45968)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 46167)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 46366)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 46565)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 46764)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 46963)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 47162)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 47361)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 47560)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 47759)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 47958)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 48157)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 48356)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 48555)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 48754)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 48953)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 49152)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 49351)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 49550)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 49749)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 49948)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 50147)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 50346)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 50545)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 50744)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 50943)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 51142)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 51341)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 51540)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 51739)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 51938)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 52137)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 52336)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 52535)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 52734)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 52933)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 53132)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 53331)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 53530)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 53729)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 53928)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 54127)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 54326)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 54525)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 54724)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 54923)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 55122)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 55321)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 55520)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 55719)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 55918)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 56117)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 56316)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 56515)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 56714)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 56913)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 57112)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 57311)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 57510)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 57709)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 57908)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 58107)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 58306)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 58505)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 58704)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 58903)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 59102)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 59301)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 59500)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 59699)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 59898)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 60097)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 60296)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 60495)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 60694)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 60893)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 61092)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 61291)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 61490)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 61689)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 61888)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 62087)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 62286)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 62485)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 62684)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 62883)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 63082)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 63281)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 63480)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 63679)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 63878)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 64077)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 64276)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 64475)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 64674)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 64873)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 65072)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 65271)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 65470)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 65516)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 65517)) (i32.const 1)) +(assert_return (invoke "load8_u" (i32.const 65518)) (i32.const 2)) +(assert_return (invoke "load8_u" (i32.const 65519)) (i32.const 3)) +(assert_return (invoke "load8_u" (i32.const 65520)) (i32.const 4)) +(assert_return (invoke "load8_u" (i32.const 65521)) (i32.const 5)) +(assert_return (invoke "load8_u" (i32.const 65522)) (i32.const 6)) +(assert_return (invoke "load8_u" (i32.const 65523)) (i32.const 7)) +(assert_return (invoke "load8_u" (i32.const 65524)) (i32.const 8)) +(assert_return (invoke "load8_u" (i32.const 65525)) (i32.const 9)) +(assert_return (invoke "load8_u" (i32.const 65526)) (i32.const 10)) +(assert_return (invoke "load8_u" (i32.const 65527)) (i32.const 11)) +(assert_return (invoke "load8_u" (i32.const 65528)) (i32.const 12)) +(assert_return (invoke "load8_u" (i32.const 65529)) (i32.const 13)) +(assert_return (invoke "load8_u" (i32.const 65530)) (i32.const 14)) +(assert_return (invoke "load8_u" (i32.const 65531)) (i32.const 15)) +(assert_return (invoke "load8_u" (i32.const 65532)) (i32.const 16)) +(assert_return (invoke "load8_u" (i32.const 65533)) (i32.const 17)) +(assert_return (invoke "load8_u" (i32.const 65534)) (i32.const 18)) +(assert_return (invoke "load8_u" (i32.const 65535)) (i32.const 19)) + +(module + (memory (export "mem") 1 1 ) + (data (i32.const 65515) "\00\01\02\03\04\05\06\07\08\09\0a\0b\0c\0d\0e\0f\10\11\12\13\14") + (func (export "run") (param $targetOffs i32) (param $srcOffs i32) (param $len i32) + (memory.copy (local.get $targetOffs) (local.get $srcOffs) (local.get $len))) + (func (export "load8_u") (param i32) (result i32) + (i32.load8_u (local.get 0)))) + +(assert_trap (invoke "run" (i32.const 0) (i32.const 65515) (i32.const 39)) + "out of bounds") + +(assert_return (invoke "load8_u" (i32.const 198)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 397)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 596)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 795)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 994)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 1193)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 1392)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 1591)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 1790)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 1989)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 2188)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 2387)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 2586)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 2785)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 2984)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 3183)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 3382)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 3581)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 3780)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 3979)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 4178)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 4377)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 4576)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 4775)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 4974)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 5173)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 5372)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 5571)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 5770)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 5969)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 6168)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 6367)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 6566)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 6765)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 6964)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 7163)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 7362)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 7561)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 7760)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 7959)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 8158)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 8357)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 8556)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 8755)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 8954)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 9153)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 9352)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 9551)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 9750)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 9949)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 10148)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 10347)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 10546)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 10745)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 10944)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 11143)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 11342)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 11541)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 11740)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 11939)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 12138)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 12337)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 12536)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 12735)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 12934)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 13133)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 13332)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 13531)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 13730)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 13929)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 14128)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 14327)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 14526)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 14725)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 14924)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 15123)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 15322)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 15521)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 15720)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 15919)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 16118)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 16317)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 16516)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 16715)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 16914)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 17113)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 17312)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 17511)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 17710)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 17909)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 18108)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 18307)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 18506)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 18705)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 18904)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 19103)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 19302)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 19501)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 19700)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 19899)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 20098)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 20297)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 20496)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 20695)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 20894)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 21093)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 21292)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 21491)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 21690)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 21889)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 22088)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 22287)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 22486)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 22685)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 22884)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 23083)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 23282)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 23481)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 23680)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 23879)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 24078)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 24277)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 24476)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 24675)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 24874)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 25073)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 25272)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 25471)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 25670)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 25869)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 26068)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 26267)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 26466)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 26665)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 26864)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 27063)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 27262)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 27461)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 27660)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 27859)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 28058)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 28257)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 28456)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 28655)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 28854)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 29053)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 29252)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 29451)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 29650)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 29849)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 30048)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 30247)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 30446)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 30645)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 30844)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 31043)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 31242)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 31441)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 31640)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 31839)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 32038)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 32237)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 32436)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 32635)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 32834)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 33033)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 33232)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 33431)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 33630)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 33829)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 34028)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 34227)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 34426)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 34625)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 34824)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 35023)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 35222)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 35421)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 35620)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 35819)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 36018)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 36217)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 36416)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 36615)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 36814)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 37013)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 37212)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 37411)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 37610)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 37809)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 38008)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 38207)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 38406)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 38605)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 38804)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 39003)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 39202)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 39401)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 39600)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 39799)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 39998)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 40197)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 40396)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 40595)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 40794)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 40993)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 41192)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 41391)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 41590)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 41789)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 41988)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 42187)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 42386)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 42585)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 42784)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 42983)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 43182)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 43381)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 43580)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 43779)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 43978)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 44177)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 44376)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 44575)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 44774)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 44973)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 45172)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 45371)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 45570)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 45769)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 45968)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 46167)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 46366)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 46565)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 46764)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 46963)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 47162)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 47361)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 47560)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 47759)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 47958)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 48157)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 48356)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 48555)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 48754)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 48953)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 49152)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 49351)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 49550)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 49749)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 49948)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 50147)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 50346)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 50545)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 50744)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 50943)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 51142)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 51341)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 51540)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 51739)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 51938)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 52137)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 52336)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 52535)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 52734)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 52933)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 53132)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 53331)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 53530)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 53729)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 53928)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 54127)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 54326)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 54525)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 54724)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 54923)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 55122)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 55321)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 55520)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 55719)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 55918)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 56117)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 56316)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 56515)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 56714)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 56913)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 57112)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 57311)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 57510)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 57709)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 57908)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 58107)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 58306)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 58505)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 58704)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 58903)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 59102)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 59301)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 59500)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 59699)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 59898)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 60097)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 60296)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 60495)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 60694)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 60893)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 61092)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 61291)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 61490)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 61689)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 61888)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 62087)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 62286)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 62485)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 62684)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 62883)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 63082)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 63281)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 63480)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 63679)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 63878)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 64077)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 64276)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 64475)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 64674)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 64873)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 65072)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 65271)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 65470)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 65515)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 65516)) (i32.const 1)) +(assert_return (invoke "load8_u" (i32.const 65517)) (i32.const 2)) +(assert_return (invoke "load8_u" (i32.const 65518)) (i32.const 3)) +(assert_return (invoke "load8_u" (i32.const 65519)) (i32.const 4)) +(assert_return (invoke "load8_u" (i32.const 65520)) (i32.const 5)) +(assert_return (invoke "load8_u" (i32.const 65521)) (i32.const 6)) +(assert_return (invoke "load8_u" (i32.const 65522)) (i32.const 7)) +(assert_return (invoke "load8_u" (i32.const 65523)) (i32.const 8)) +(assert_return (invoke "load8_u" (i32.const 65524)) (i32.const 9)) +(assert_return (invoke "load8_u" (i32.const 65525)) (i32.const 10)) +(assert_return (invoke "load8_u" (i32.const 65526)) (i32.const 11)) +(assert_return (invoke "load8_u" (i32.const 65527)) (i32.const 12)) +(assert_return (invoke "load8_u" (i32.const 65528)) (i32.const 13)) +(assert_return (invoke "load8_u" (i32.const 65529)) (i32.const 14)) +(assert_return (invoke "load8_u" (i32.const 65530)) (i32.const 15)) +(assert_return (invoke "load8_u" (i32.const 65531)) (i32.const 16)) +(assert_return (invoke "load8_u" (i32.const 65532)) (i32.const 17)) +(assert_return (invoke "load8_u" (i32.const 65533)) (i32.const 18)) +(assert_return (invoke "load8_u" (i32.const 65534)) (i32.const 19)) +(assert_return (invoke "load8_u" (i32.const 65535)) (i32.const 20)) + +(module + (memory (export "mem") 1 1 ) + (data (i32.const 65486) "\00\01\02\03\04\05\06\07\08\09\0a\0b\0c\0d\0e\0f\10\11\12\13") + (func (export "run") (param $targetOffs i32) (param $srcOffs i32) (param $len i32) + (memory.copy (local.get $targetOffs) (local.get $srcOffs) (local.get $len))) + (func (export "load8_u") (param i32) (result i32) + (i32.load8_u (local.get 0)))) + +(assert_trap (invoke "run" (i32.const 65516) (i32.const 65486) (i32.const 40)) + "out of bounds") + +(assert_return (invoke "load8_u" (i32.const 198)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 397)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 596)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 795)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 994)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 1193)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 1392)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 1591)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 1790)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 1989)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 2188)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 2387)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 2586)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 2785)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 2984)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 3183)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 3382)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 3581)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 3780)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 3979)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 4178)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 4377)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 4576)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 4775)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 4974)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 5173)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 5372)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 5571)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 5770)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 5969)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 6168)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 6367)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 6566)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 6765)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 6964)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 7163)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 7362)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 7561)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 7760)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 7959)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 8158)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 8357)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 8556)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 8755)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 8954)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 9153)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 9352)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 9551)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 9750)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 9949)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 10148)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 10347)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 10546)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 10745)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 10944)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 11143)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 11342)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 11541)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 11740)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 11939)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 12138)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 12337)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 12536)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 12735)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 12934)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 13133)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 13332)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 13531)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 13730)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 13929)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 14128)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 14327)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 14526)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 14725)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 14924)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 15123)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 15322)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 15521)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 15720)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 15919)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 16118)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 16317)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 16516)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 16715)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 16914)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 17113)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 17312)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 17511)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 17710)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 17909)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 18108)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 18307)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 18506)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 18705)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 18904)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 19103)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 19302)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 19501)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 19700)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 19899)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 20098)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 20297)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 20496)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 20695)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 20894)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 21093)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 21292)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 21491)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 21690)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 21889)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 22088)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 22287)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 22486)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 22685)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 22884)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 23083)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 23282)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 23481)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 23680)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 23879)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 24078)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 24277)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 24476)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 24675)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 24874)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 25073)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 25272)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 25471)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 25670)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 25869)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 26068)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 26267)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 26466)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 26665)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 26864)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 27063)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 27262)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 27461)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 27660)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 27859)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 28058)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 28257)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 28456)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 28655)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 28854)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 29053)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 29252)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 29451)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 29650)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 29849)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 30048)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 30247)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 30446)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 30645)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 30844)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 31043)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 31242)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 31441)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 31640)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 31839)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 32038)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 32237)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 32436)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 32635)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 32834)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 33033)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 33232)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 33431)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 33630)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 33829)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 34028)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 34227)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 34426)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 34625)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 34824)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 35023)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 35222)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 35421)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 35620)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 35819)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 36018)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 36217)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 36416)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 36615)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 36814)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 37013)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 37212)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 37411)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 37610)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 37809)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 38008)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 38207)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 38406)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 38605)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 38804)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 39003)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 39202)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 39401)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 39600)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 39799)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 39998)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 40197)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 40396)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 40595)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 40794)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 40993)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 41192)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 41391)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 41590)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 41789)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 41988)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 42187)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 42386)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 42585)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 42784)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 42983)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 43182)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 43381)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 43580)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 43779)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 43978)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 44177)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 44376)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 44575)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 44774)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 44973)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 45172)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 45371)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 45570)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 45769)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 45968)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 46167)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 46366)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 46565)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 46764)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 46963)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 47162)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 47361)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 47560)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 47759)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 47958)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 48157)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 48356)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 48555)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 48754)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 48953)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 49152)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 49351)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 49550)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 49749)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 49948)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 50147)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 50346)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 50545)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 50744)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 50943)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 51142)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 51341)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 51540)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 51739)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 51938)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 52137)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 52336)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 52535)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 52734)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 52933)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 53132)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 53331)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 53530)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 53729)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 53928)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 54127)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 54326)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 54525)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 54724)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 54923)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 55122)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 55321)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 55520)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 55719)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 55918)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 56117)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 56316)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 56515)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 56714)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 56913)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 57112)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 57311)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 57510)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 57709)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 57908)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 58107)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 58306)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 58505)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 58704)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 58903)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 59102)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 59301)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 59500)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 59699)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 59898)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 60097)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 60296)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 60495)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 60694)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 60893)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 61092)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 61291)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 61490)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 61689)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 61888)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 62087)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 62286)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 62485)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 62684)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 62883)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 63082)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 63281)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 63480)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 63679)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 63878)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 64077)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 64276)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 64475)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 64674)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 64873)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 65072)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 65271)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 65470)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 65486)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 65487)) (i32.const 1)) +(assert_return (invoke "load8_u" (i32.const 65488)) (i32.const 2)) +(assert_return (invoke "load8_u" (i32.const 65489)) (i32.const 3)) +(assert_return (invoke "load8_u" (i32.const 65490)) (i32.const 4)) +(assert_return (invoke "load8_u" (i32.const 65491)) (i32.const 5)) +(assert_return (invoke "load8_u" (i32.const 65492)) (i32.const 6)) +(assert_return (invoke "load8_u" (i32.const 65493)) (i32.const 7)) +(assert_return (invoke "load8_u" (i32.const 65494)) (i32.const 8)) +(assert_return (invoke "load8_u" (i32.const 65495)) (i32.const 9)) +(assert_return (invoke "load8_u" (i32.const 65496)) (i32.const 10)) +(assert_return (invoke "load8_u" (i32.const 65497)) (i32.const 11)) +(assert_return (invoke "load8_u" (i32.const 65498)) (i32.const 12)) +(assert_return (invoke "load8_u" (i32.const 65499)) (i32.const 13)) +(assert_return (invoke "load8_u" (i32.const 65500)) (i32.const 14)) +(assert_return (invoke "load8_u" (i32.const 65501)) (i32.const 15)) +(assert_return (invoke "load8_u" (i32.const 65502)) (i32.const 16)) +(assert_return (invoke "load8_u" (i32.const 65503)) (i32.const 17)) +(assert_return (invoke "load8_u" (i32.const 65504)) (i32.const 18)) +(assert_return (invoke "load8_u" (i32.const 65505)) (i32.const 19)) + +(module + (memory (export "mem") 1 1 ) + (data (i32.const 65516) "\00\01\02\03\04\05\06\07\08\09\0a\0b\0c\0d\0e\0f\10\11\12\13") + (func (export "run") (param $targetOffs i32) (param $srcOffs i32) (param $len i32) + (memory.copy (local.get $targetOffs) (local.get $srcOffs) (local.get $len))) + (func (export "load8_u") (param i32) (result i32) + (i32.load8_u (local.get 0)))) + +(assert_trap (invoke "run" (i32.const 65486) (i32.const 65516) (i32.const 40)) + "out of bounds") + +(assert_return (invoke "load8_u" (i32.const 198)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 397)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 596)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 795)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 994)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 1193)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 1392)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 1591)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 1790)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 1989)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 2188)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 2387)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 2586)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 2785)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 2984)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 3183)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 3382)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 3581)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 3780)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 3979)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 4178)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 4377)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 4576)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 4775)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 4974)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 5173)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 5372)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 5571)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 5770)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 5969)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 6168)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 6367)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 6566)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 6765)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 6964)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 7163)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 7362)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 7561)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 7760)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 7959)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 8158)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 8357)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 8556)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 8755)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 8954)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 9153)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 9352)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 9551)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 9750)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 9949)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 10148)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 10347)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 10546)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 10745)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 10944)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 11143)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 11342)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 11541)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 11740)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 11939)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 12138)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 12337)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 12536)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 12735)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 12934)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 13133)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 13332)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 13531)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 13730)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 13929)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 14128)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 14327)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 14526)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 14725)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 14924)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 15123)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 15322)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 15521)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 15720)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 15919)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 16118)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 16317)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 16516)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 16715)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 16914)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 17113)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 17312)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 17511)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 17710)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 17909)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 18108)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 18307)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 18506)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 18705)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 18904)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 19103)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 19302)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 19501)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 19700)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 19899)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 20098)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 20297)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 20496)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 20695)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 20894)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 21093)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 21292)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 21491)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 21690)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 21889)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 22088)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 22287)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 22486)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 22685)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 22884)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 23083)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 23282)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 23481)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 23680)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 23879)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 24078)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 24277)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 24476)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 24675)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 24874)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 25073)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 25272)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 25471)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 25670)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 25869)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 26068)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 26267)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 26466)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 26665)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 26864)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 27063)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 27262)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 27461)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 27660)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 27859)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 28058)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 28257)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 28456)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 28655)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 28854)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 29053)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 29252)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 29451)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 29650)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 29849)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 30048)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 30247)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 30446)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 30645)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 30844)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 31043)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 31242)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 31441)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 31640)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 31839)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 32038)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 32237)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 32436)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 32635)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 32834)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 33033)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 33232)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 33431)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 33630)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 33829)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 34028)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 34227)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 34426)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 34625)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 34824)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 35023)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 35222)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 35421)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 35620)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 35819)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 36018)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 36217)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 36416)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 36615)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 36814)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 37013)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 37212)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 37411)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 37610)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 37809)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 38008)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 38207)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 38406)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 38605)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 38804)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 39003)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 39202)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 39401)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 39600)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 39799)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 39998)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 40197)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 40396)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 40595)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 40794)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 40993)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 41192)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 41391)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 41590)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 41789)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 41988)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 42187)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 42386)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 42585)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 42784)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 42983)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 43182)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 43381)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 43580)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 43779)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 43978)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 44177)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 44376)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 44575)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 44774)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 44973)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 45172)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 45371)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 45570)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 45769)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 45968)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 46167)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 46366)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 46565)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 46764)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 46963)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 47162)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 47361)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 47560)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 47759)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 47958)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 48157)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 48356)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 48555)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 48754)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 48953)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 49152)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 49351)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 49550)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 49749)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 49948)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 50147)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 50346)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 50545)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 50744)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 50943)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 51142)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 51341)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 51540)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 51739)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 51938)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 52137)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 52336)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 52535)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 52734)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 52933)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 53132)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 53331)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 53530)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 53729)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 53928)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 54127)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 54326)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 54525)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 54724)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 54923)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 55122)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 55321)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 55520)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 55719)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 55918)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 56117)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 56316)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 56515)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 56714)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 56913)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 57112)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 57311)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 57510)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 57709)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 57908)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 58107)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 58306)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 58505)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 58704)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 58903)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 59102)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 59301)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 59500)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 59699)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 59898)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 60097)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 60296)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 60495)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 60694)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 60893)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 61092)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 61291)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 61490)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 61689)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 61888)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 62087)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 62286)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 62485)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 62684)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 62883)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 63082)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 63281)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 63480)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 63679)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 63878)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 64077)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 64276)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 64475)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 64674)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 64873)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 65072)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 65271)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 65470)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 65516)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 65517)) (i32.const 1)) +(assert_return (invoke "load8_u" (i32.const 65518)) (i32.const 2)) +(assert_return (invoke "load8_u" (i32.const 65519)) (i32.const 3)) +(assert_return (invoke "load8_u" (i32.const 65520)) (i32.const 4)) +(assert_return (invoke "load8_u" (i32.const 65521)) (i32.const 5)) +(assert_return (invoke "load8_u" (i32.const 65522)) (i32.const 6)) +(assert_return (invoke "load8_u" (i32.const 65523)) (i32.const 7)) +(assert_return (invoke "load8_u" (i32.const 65524)) (i32.const 8)) +(assert_return (invoke "load8_u" (i32.const 65525)) (i32.const 9)) +(assert_return (invoke "load8_u" (i32.const 65526)) (i32.const 10)) +(assert_return (invoke "load8_u" (i32.const 65527)) (i32.const 11)) +(assert_return (invoke "load8_u" (i32.const 65528)) (i32.const 12)) +(assert_return (invoke "load8_u" (i32.const 65529)) (i32.const 13)) +(assert_return (invoke "load8_u" (i32.const 65530)) (i32.const 14)) +(assert_return (invoke "load8_u" (i32.const 65531)) (i32.const 15)) +(assert_return (invoke "load8_u" (i32.const 65532)) (i32.const 16)) +(assert_return (invoke "load8_u" (i32.const 65533)) (i32.const 17)) +(assert_return (invoke "load8_u" (i32.const 65534)) (i32.const 18)) +(assert_return (invoke "load8_u" (i32.const 65535)) (i32.const 19)) + +(module + (memory (export "mem") 1 1 ) + (data (i32.const 65506) "\00\01\02\03\04\05\06\07\08\09\0a\0b\0c\0d\0e\0f\10\11\12\13") + (func (export "run") (param $targetOffs i32) (param $srcOffs i32) (param $len i32) + (memory.copy (local.get $targetOffs) (local.get $srcOffs) (local.get $len))) + (func (export "load8_u") (param i32) (result i32) + (i32.load8_u (local.get 0)))) + +(assert_trap (invoke "run" (i32.const 65516) (i32.const 65506) (i32.const 40)) + "out of bounds") + +(assert_return (invoke "load8_u" (i32.const 198)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 397)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 596)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 795)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 994)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 1193)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 1392)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 1591)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 1790)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 1989)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 2188)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 2387)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 2586)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 2785)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 2984)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 3183)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 3382)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 3581)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 3780)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 3979)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 4178)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 4377)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 4576)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 4775)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 4974)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 5173)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 5372)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 5571)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 5770)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 5969)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 6168)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 6367)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 6566)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 6765)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 6964)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 7163)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 7362)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 7561)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 7760)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 7959)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 8158)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 8357)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 8556)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 8755)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 8954)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 9153)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 9352)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 9551)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 9750)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 9949)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 10148)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 10347)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 10546)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 10745)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 10944)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 11143)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 11342)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 11541)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 11740)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 11939)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 12138)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 12337)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 12536)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 12735)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 12934)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 13133)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 13332)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 13531)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 13730)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 13929)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 14128)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 14327)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 14526)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 14725)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 14924)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 15123)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 15322)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 15521)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 15720)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 15919)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 16118)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 16317)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 16516)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 16715)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 16914)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 17113)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 17312)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 17511)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 17710)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 17909)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 18108)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 18307)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 18506)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 18705)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 18904)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 19103)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 19302)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 19501)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 19700)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 19899)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 20098)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 20297)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 20496)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 20695)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 20894)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 21093)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 21292)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 21491)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 21690)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 21889)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 22088)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 22287)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 22486)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 22685)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 22884)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 23083)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 23282)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 23481)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 23680)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 23879)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 24078)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 24277)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 24476)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 24675)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 24874)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 25073)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 25272)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 25471)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 25670)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 25869)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 26068)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 26267)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 26466)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 26665)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 26864)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 27063)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 27262)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 27461)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 27660)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 27859)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 28058)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 28257)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 28456)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 28655)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 28854)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 29053)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 29252)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 29451)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 29650)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 29849)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 30048)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 30247)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 30446)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 30645)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 30844)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 31043)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 31242)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 31441)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 31640)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 31839)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 32038)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 32237)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 32436)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 32635)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 32834)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 33033)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 33232)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 33431)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 33630)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 33829)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 34028)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 34227)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 34426)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 34625)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 34824)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 35023)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 35222)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 35421)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 35620)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 35819)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 36018)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 36217)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 36416)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 36615)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 36814)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 37013)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 37212)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 37411)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 37610)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 37809)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 38008)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 38207)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 38406)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 38605)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 38804)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 39003)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 39202)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 39401)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 39600)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 39799)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 39998)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 40197)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 40396)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 40595)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 40794)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 40993)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 41192)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 41391)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 41590)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 41789)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 41988)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 42187)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 42386)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 42585)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 42784)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 42983)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 43182)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 43381)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 43580)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 43779)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 43978)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 44177)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 44376)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 44575)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 44774)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 44973)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 45172)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 45371)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 45570)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 45769)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 45968)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 46167)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 46366)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 46565)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 46764)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 46963)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 47162)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 47361)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 47560)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 47759)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 47958)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 48157)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 48356)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 48555)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 48754)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 48953)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 49152)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 49351)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 49550)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 49749)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 49948)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 50147)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 50346)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 50545)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 50744)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 50943)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 51142)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 51341)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 51540)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 51739)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 51938)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 52137)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 52336)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 52535)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 52734)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 52933)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 53132)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 53331)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 53530)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 53729)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 53928)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 54127)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 54326)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 54525)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 54724)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 54923)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 55122)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 55321)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 55520)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 55719)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 55918)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 56117)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 56316)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 56515)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 56714)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 56913)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 57112)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 57311)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 57510)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 57709)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 57908)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 58107)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 58306)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 58505)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 58704)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 58903)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 59102)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 59301)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 59500)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 59699)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 59898)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 60097)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 60296)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 60495)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 60694)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 60893)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 61092)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 61291)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 61490)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 61689)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 61888)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 62087)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 62286)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 62485)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 62684)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 62883)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 63082)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 63281)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 63480)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 63679)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 63878)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 64077)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 64276)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 64475)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 64674)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 64873)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 65072)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 65271)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 65470)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 65506)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 65507)) (i32.const 1)) +(assert_return (invoke "load8_u" (i32.const 65508)) (i32.const 2)) +(assert_return (invoke "load8_u" (i32.const 65509)) (i32.const 3)) +(assert_return (invoke "load8_u" (i32.const 65510)) (i32.const 4)) +(assert_return (invoke "load8_u" (i32.const 65511)) (i32.const 5)) +(assert_return (invoke "load8_u" (i32.const 65512)) (i32.const 6)) +(assert_return (invoke "load8_u" (i32.const 65513)) (i32.const 7)) +(assert_return (invoke "load8_u" (i32.const 65514)) (i32.const 8)) +(assert_return (invoke "load8_u" (i32.const 65515)) (i32.const 9)) +(assert_return (invoke "load8_u" (i32.const 65516)) (i32.const 10)) +(assert_return (invoke "load8_u" (i32.const 65517)) (i32.const 11)) +(assert_return (invoke "load8_u" (i32.const 65518)) (i32.const 12)) +(assert_return (invoke "load8_u" (i32.const 65519)) (i32.const 13)) +(assert_return (invoke "load8_u" (i32.const 65520)) (i32.const 14)) +(assert_return (invoke "load8_u" (i32.const 65521)) (i32.const 15)) +(assert_return (invoke "load8_u" (i32.const 65522)) (i32.const 16)) +(assert_return (invoke "load8_u" (i32.const 65523)) (i32.const 17)) +(assert_return (invoke "load8_u" (i32.const 65524)) (i32.const 18)) +(assert_return (invoke "load8_u" (i32.const 65525)) (i32.const 19)) + +(module + (memory (export "mem") 1 1 ) + (data (i32.const 65516) "\00\01\02\03\04\05\06\07\08\09\0a\0b\0c\0d\0e\0f\10\11\12\13") + (func (export "run") (param $targetOffs i32) (param $srcOffs i32) (param $len i32) + (memory.copy (local.get $targetOffs) (local.get $srcOffs) (local.get $len))) + (func (export "load8_u") (param i32) (result i32) + (i32.load8_u (local.get 0)))) + +(assert_trap (invoke "run" (i32.const 65506) (i32.const 65516) (i32.const 40)) + "out of bounds") + +(assert_return (invoke "load8_u" (i32.const 198)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 397)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 596)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 795)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 994)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 1193)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 1392)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 1591)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 1790)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 1989)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 2188)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 2387)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 2586)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 2785)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 2984)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 3183)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 3382)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 3581)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 3780)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 3979)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 4178)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 4377)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 4576)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 4775)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 4974)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 5173)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 5372)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 5571)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 5770)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 5969)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 6168)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 6367)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 6566)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 6765)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 6964)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 7163)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 7362)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 7561)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 7760)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 7959)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 8158)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 8357)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 8556)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 8755)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 8954)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 9153)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 9352)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 9551)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 9750)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 9949)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 10148)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 10347)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 10546)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 10745)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 10944)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 11143)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 11342)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 11541)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 11740)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 11939)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 12138)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 12337)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 12536)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 12735)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 12934)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 13133)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 13332)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 13531)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 13730)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 13929)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 14128)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 14327)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 14526)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 14725)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 14924)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 15123)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 15322)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 15521)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 15720)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 15919)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 16118)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 16317)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 16516)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 16715)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 16914)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 17113)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 17312)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 17511)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 17710)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 17909)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 18108)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 18307)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 18506)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 18705)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 18904)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 19103)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 19302)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 19501)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 19700)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 19899)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 20098)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 20297)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 20496)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 20695)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 20894)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 21093)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 21292)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 21491)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 21690)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 21889)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 22088)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 22287)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 22486)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 22685)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 22884)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 23083)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 23282)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 23481)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 23680)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 23879)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 24078)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 24277)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 24476)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 24675)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 24874)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 25073)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 25272)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 25471)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 25670)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 25869)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 26068)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 26267)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 26466)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 26665)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 26864)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 27063)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 27262)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 27461)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 27660)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 27859)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 28058)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 28257)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 28456)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 28655)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 28854)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 29053)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 29252)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 29451)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 29650)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 29849)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 30048)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 30247)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 30446)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 30645)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 30844)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 31043)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 31242)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 31441)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 31640)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 31839)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 32038)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 32237)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 32436)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 32635)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 32834)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 33033)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 33232)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 33431)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 33630)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 33829)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 34028)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 34227)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 34426)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 34625)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 34824)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 35023)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 35222)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 35421)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 35620)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 35819)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 36018)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 36217)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 36416)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 36615)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 36814)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 37013)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 37212)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 37411)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 37610)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 37809)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 38008)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 38207)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 38406)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 38605)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 38804)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 39003)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 39202)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 39401)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 39600)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 39799)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 39998)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 40197)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 40396)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 40595)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 40794)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 40993)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 41192)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 41391)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 41590)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 41789)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 41988)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 42187)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 42386)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 42585)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 42784)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 42983)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 43182)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 43381)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 43580)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 43779)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 43978)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 44177)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 44376)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 44575)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 44774)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 44973)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 45172)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 45371)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 45570)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 45769)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 45968)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 46167)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 46366)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 46565)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 46764)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 46963)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 47162)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 47361)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 47560)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 47759)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 47958)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 48157)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 48356)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 48555)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 48754)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 48953)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 49152)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 49351)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 49550)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 49749)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 49948)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 50147)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 50346)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 50545)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 50744)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 50943)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 51142)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 51341)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 51540)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 51739)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 51938)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 52137)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 52336)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 52535)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 52734)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 52933)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 53132)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 53331)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 53530)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 53729)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 53928)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 54127)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 54326)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 54525)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 54724)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 54923)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 55122)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 55321)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 55520)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 55719)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 55918)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 56117)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 56316)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 56515)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 56714)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 56913)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 57112)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 57311)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 57510)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 57709)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 57908)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 58107)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 58306)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 58505)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 58704)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 58903)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 59102)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 59301)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 59500)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 59699)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 59898)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 60097)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 60296)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 60495)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 60694)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 60893)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 61092)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 61291)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 61490)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 61689)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 61888)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 62087)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 62286)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 62485)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 62684)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 62883)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 63082)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 63281)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 63480)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 63679)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 63878)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 64077)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 64276)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 64475)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 64674)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 64873)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 65072)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 65271)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 65470)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 65516)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 65517)) (i32.const 1)) +(assert_return (invoke "load8_u" (i32.const 65518)) (i32.const 2)) +(assert_return (invoke "load8_u" (i32.const 65519)) (i32.const 3)) +(assert_return (invoke "load8_u" (i32.const 65520)) (i32.const 4)) +(assert_return (invoke "load8_u" (i32.const 65521)) (i32.const 5)) +(assert_return (invoke "load8_u" (i32.const 65522)) (i32.const 6)) +(assert_return (invoke "load8_u" (i32.const 65523)) (i32.const 7)) +(assert_return (invoke "load8_u" (i32.const 65524)) (i32.const 8)) +(assert_return (invoke "load8_u" (i32.const 65525)) (i32.const 9)) +(assert_return (invoke "load8_u" (i32.const 65526)) (i32.const 10)) +(assert_return (invoke "load8_u" (i32.const 65527)) (i32.const 11)) +(assert_return (invoke "load8_u" (i32.const 65528)) (i32.const 12)) +(assert_return (invoke "load8_u" (i32.const 65529)) (i32.const 13)) +(assert_return (invoke "load8_u" (i32.const 65530)) (i32.const 14)) +(assert_return (invoke "load8_u" (i32.const 65531)) (i32.const 15)) +(assert_return (invoke "load8_u" (i32.const 65532)) (i32.const 16)) +(assert_return (invoke "load8_u" (i32.const 65533)) (i32.const 17)) +(assert_return (invoke "load8_u" (i32.const 65534)) (i32.const 18)) +(assert_return (invoke "load8_u" (i32.const 65535)) (i32.const 19)) + +(module + (memory (export "mem") 1 1 ) + (data (i32.const 65516) "\00\01\02\03\04\05\06\07\08\09\0a\0b\0c\0d\0e\0f\10\11\12\13") + (func (export "run") (param $targetOffs i32) (param $srcOffs i32) (param $len i32) + (memory.copy (local.get $targetOffs) (local.get $srcOffs) (local.get $len))) + (func (export "load8_u") (param i32) (result i32) + (i32.load8_u (local.get 0)))) + +(assert_trap (invoke "run" (i32.const 65516) (i32.const 65516) (i32.const 40)) + "out of bounds") + +(assert_return (invoke "load8_u" (i32.const 198)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 397)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 596)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 795)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 994)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 1193)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 1392)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 1591)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 1790)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 1989)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 2188)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 2387)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 2586)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 2785)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 2984)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 3183)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 3382)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 3581)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 3780)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 3979)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 4178)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 4377)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 4576)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 4775)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 4974)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 5173)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 5372)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 5571)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 5770)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 5969)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 6168)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 6367)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 6566)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 6765)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 6964)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 7163)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 7362)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 7561)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 7760)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 7959)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 8158)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 8357)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 8556)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 8755)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 8954)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 9153)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 9352)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 9551)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 9750)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 9949)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 10148)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 10347)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 10546)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 10745)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 10944)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 11143)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 11342)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 11541)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 11740)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 11939)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 12138)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 12337)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 12536)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 12735)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 12934)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 13133)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 13332)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 13531)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 13730)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 13929)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 14128)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 14327)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 14526)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 14725)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 14924)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 15123)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 15322)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 15521)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 15720)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 15919)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 16118)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 16317)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 16516)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 16715)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 16914)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 17113)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 17312)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 17511)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 17710)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 17909)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 18108)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 18307)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 18506)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 18705)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 18904)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 19103)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 19302)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 19501)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 19700)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 19899)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 20098)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 20297)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 20496)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 20695)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 20894)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 21093)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 21292)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 21491)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 21690)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 21889)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 22088)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 22287)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 22486)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 22685)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 22884)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 23083)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 23282)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 23481)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 23680)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 23879)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 24078)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 24277)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 24476)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 24675)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 24874)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 25073)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 25272)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 25471)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 25670)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 25869)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 26068)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 26267)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 26466)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 26665)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 26864)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 27063)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 27262)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 27461)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 27660)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 27859)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 28058)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 28257)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 28456)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 28655)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 28854)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 29053)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 29252)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 29451)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 29650)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 29849)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 30048)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 30247)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 30446)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 30645)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 30844)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 31043)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 31242)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 31441)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 31640)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 31839)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 32038)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 32237)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 32436)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 32635)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 32834)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 33033)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 33232)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 33431)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 33630)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 33829)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 34028)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 34227)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 34426)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 34625)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 34824)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 35023)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 35222)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 35421)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 35620)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 35819)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 36018)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 36217)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 36416)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 36615)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 36814)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 37013)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 37212)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 37411)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 37610)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 37809)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 38008)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 38207)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 38406)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 38605)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 38804)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 39003)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 39202)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 39401)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 39600)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 39799)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 39998)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 40197)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 40396)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 40595)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 40794)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 40993)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 41192)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 41391)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 41590)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 41789)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 41988)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 42187)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 42386)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 42585)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 42784)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 42983)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 43182)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 43381)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 43580)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 43779)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 43978)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 44177)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 44376)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 44575)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 44774)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 44973)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 45172)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 45371)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 45570)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 45769)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 45968)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 46167)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 46366)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 46565)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 46764)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 46963)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 47162)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 47361)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 47560)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 47759)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 47958)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 48157)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 48356)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 48555)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 48754)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 48953)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 49152)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 49351)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 49550)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 49749)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 49948)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 50147)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 50346)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 50545)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 50744)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 50943)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 51142)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 51341)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 51540)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 51739)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 51938)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 52137)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 52336)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 52535)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 52734)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 52933)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 53132)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 53331)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 53530)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 53729)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 53928)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 54127)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 54326)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 54525)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 54724)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 54923)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 55122)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 55321)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 55520)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 55719)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 55918)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 56117)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 56316)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 56515)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 56714)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 56913)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 57112)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 57311)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 57510)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 57709)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 57908)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 58107)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 58306)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 58505)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 58704)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 58903)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 59102)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 59301)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 59500)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 59699)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 59898)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 60097)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 60296)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 60495)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 60694)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 60893)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 61092)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 61291)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 61490)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 61689)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 61888)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 62087)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 62286)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 62485)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 62684)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 62883)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 63082)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 63281)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 63480)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 63679)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 63878)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 64077)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 64276)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 64475)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 64674)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 64873)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 65072)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 65271)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 65470)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 65516)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 65517)) (i32.const 1)) +(assert_return (invoke "load8_u" (i32.const 65518)) (i32.const 2)) +(assert_return (invoke "load8_u" (i32.const 65519)) (i32.const 3)) +(assert_return (invoke "load8_u" (i32.const 65520)) (i32.const 4)) +(assert_return (invoke "load8_u" (i32.const 65521)) (i32.const 5)) +(assert_return (invoke "load8_u" (i32.const 65522)) (i32.const 6)) +(assert_return (invoke "load8_u" (i32.const 65523)) (i32.const 7)) +(assert_return (invoke "load8_u" (i32.const 65524)) (i32.const 8)) +(assert_return (invoke "load8_u" (i32.const 65525)) (i32.const 9)) +(assert_return (invoke "load8_u" (i32.const 65526)) (i32.const 10)) +(assert_return (invoke "load8_u" (i32.const 65527)) (i32.const 11)) +(assert_return (invoke "load8_u" (i32.const 65528)) (i32.const 12)) +(assert_return (invoke "load8_u" (i32.const 65529)) (i32.const 13)) +(assert_return (invoke "load8_u" (i32.const 65530)) (i32.const 14)) +(assert_return (invoke "load8_u" (i32.const 65531)) (i32.const 15)) +(assert_return (invoke "load8_u" (i32.const 65532)) (i32.const 16)) +(assert_return (invoke "load8_u" (i32.const 65533)) (i32.const 17)) +(assert_return (invoke "load8_u" (i32.const 65534)) (i32.const 18)) +(assert_return (invoke "load8_u" (i32.const 65535)) (i32.const 19)) + +(module + (memory (export "mem") 1 ) + (data (i32.const 65516) "\00\01\02\03\04\05\06\07\08\09\0a\0b\0c\0d\0e\0f\10\11\12\13") + (func (export "run") (param $targetOffs i32) (param $srcOffs i32) (param $len i32) + (memory.copy (local.get $targetOffs) (local.get $srcOffs) (local.get $len))) + (func (export "load8_u") (param i32) (result i32) + (i32.load8_u (local.get 0)))) + +(assert_trap (invoke "run" (i32.const 0) (i32.const 65516) (i32.const 4294963200)) + "out of bounds") + +(assert_return (invoke "load8_u" (i32.const 198)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 397)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 596)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 795)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 994)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 1193)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 1392)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 1591)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 1790)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 1989)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 2188)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 2387)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 2586)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 2785)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 2984)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 3183)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 3382)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 3581)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 3780)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 3979)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 4178)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 4377)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 4576)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 4775)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 4974)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 5173)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 5372)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 5571)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 5770)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 5969)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 6168)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 6367)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 6566)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 6765)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 6964)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 7163)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 7362)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 7561)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 7760)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 7959)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 8158)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 8357)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 8556)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 8755)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 8954)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 9153)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 9352)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 9551)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 9750)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 9949)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 10148)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 10347)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 10546)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 10745)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 10944)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 11143)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 11342)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 11541)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 11740)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 11939)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 12138)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 12337)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 12536)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 12735)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 12934)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 13133)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 13332)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 13531)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 13730)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 13929)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 14128)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 14327)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 14526)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 14725)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 14924)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 15123)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 15322)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 15521)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 15720)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 15919)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 16118)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 16317)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 16516)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 16715)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 16914)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 17113)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 17312)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 17511)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 17710)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 17909)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 18108)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 18307)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 18506)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 18705)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 18904)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 19103)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 19302)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 19501)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 19700)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 19899)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 20098)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 20297)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 20496)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 20695)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 20894)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 21093)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 21292)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 21491)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 21690)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 21889)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 22088)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 22287)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 22486)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 22685)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 22884)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 23083)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 23282)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 23481)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 23680)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 23879)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 24078)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 24277)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 24476)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 24675)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 24874)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 25073)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 25272)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 25471)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 25670)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 25869)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 26068)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 26267)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 26466)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 26665)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 26864)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 27063)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 27262)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 27461)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 27660)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 27859)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 28058)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 28257)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 28456)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 28655)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 28854)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 29053)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 29252)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 29451)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 29650)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 29849)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 30048)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 30247)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 30446)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 30645)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 30844)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 31043)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 31242)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 31441)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 31640)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 31839)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 32038)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 32237)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 32436)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 32635)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 32834)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 33033)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 33232)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 33431)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 33630)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 33829)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 34028)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 34227)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 34426)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 34625)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 34824)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 35023)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 35222)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 35421)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 35620)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 35819)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 36018)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 36217)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 36416)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 36615)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 36814)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 37013)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 37212)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 37411)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 37610)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 37809)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 38008)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 38207)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 38406)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 38605)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 38804)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 39003)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 39202)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 39401)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 39600)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 39799)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 39998)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 40197)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 40396)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 40595)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 40794)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 40993)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 41192)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 41391)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 41590)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 41789)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 41988)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 42187)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 42386)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 42585)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 42784)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 42983)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 43182)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 43381)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 43580)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 43779)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 43978)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 44177)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 44376)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 44575)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 44774)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 44973)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 45172)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 45371)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 45570)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 45769)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 45968)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 46167)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 46366)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 46565)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 46764)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 46963)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 47162)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 47361)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 47560)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 47759)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 47958)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 48157)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 48356)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 48555)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 48754)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 48953)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 49152)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 49351)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 49550)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 49749)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 49948)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 50147)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 50346)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 50545)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 50744)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 50943)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 51142)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 51341)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 51540)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 51739)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 51938)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 52137)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 52336)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 52535)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 52734)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 52933)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 53132)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 53331)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 53530)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 53729)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 53928)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 54127)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 54326)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 54525)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 54724)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 54923)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 55122)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 55321)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 55520)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 55719)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 55918)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 56117)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 56316)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 56515)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 56714)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 56913)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 57112)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 57311)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 57510)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 57709)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 57908)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 58107)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 58306)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 58505)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 58704)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 58903)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 59102)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 59301)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 59500)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 59699)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 59898)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 60097)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 60296)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 60495)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 60694)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 60893)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 61092)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 61291)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 61490)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 61689)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 61888)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 62087)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 62286)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 62485)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 62684)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 62883)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 63082)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 63281)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 63480)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 63679)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 63878)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 64077)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 64276)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 64475)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 64674)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 64873)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 65072)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 65271)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 65470)) (i32.const 0)) (assert_return (invoke "load8_u" (i32.const 65516)) (i32.const 0)) (assert_return (invoke "load8_u" (i32.const 65517)) (i32.const 1)) (assert_return (invoke "load8_u" (i32.const 65518)) (i32.const 2)) diff --git a/test/core/memory_fill.wast b/test/core/memory_fill.wast index bd4d598f9c..bbce9d8e3e 100644 --- a/test/core/memory_fill.wast +++ b/test/core/memory_fill.wast @@ -637,9 +637,7 @@ (assert_trap (invoke "run" (i32.const 65280) (i32.const 37) (i32.const 512)) "out of bounds") -(assert_return (invoke "checkRange" (i32.const 65280) (i32.const 65536) (i32.const 37)) - (i32.const -1)) -(assert_return (invoke "checkRange" (i32.const 0) (i32.const 65280) (i32.const 0)) +(assert_return (invoke "checkRange" (i32.const 0) (i32.const 1) (i32.const 0)) (i32.const -1)) (module (memory 1 1 ) @@ -661,9 +659,7 @@ (assert_trap (invoke "run" (i32.const 65279) (i32.const 37) (i32.const 514)) "out of bounds") -(assert_return (invoke "checkRange" (i32.const 65279) (i32.const 65536) (i32.const 37)) - (i32.const -1)) -(assert_return (invoke "checkRange" (i32.const 0) (i32.const 65279) (i32.const 0)) +(assert_return (invoke "checkRange" (i32.const 0) (i32.const 1) (i32.const 0)) (i32.const -1)) (module (memory 1 1 ) @@ -685,7 +681,5 @@ (assert_trap (invoke "run" (i32.const 65279) (i32.const 37) (i32.const 4294967295)) "out of bounds") -(assert_return (invoke "checkRange" (i32.const 65279) (i32.const 65536) (i32.const 37)) - (i32.const -1)) -(assert_return (invoke "checkRange" (i32.const 0) (i32.const 65279) (i32.const 0)) +(assert_return (invoke "checkRange" (i32.const 0) (i32.const 1) (i32.const 0)) (i32.const -1)) diff --git a/test/core/memory_init.wast b/test/core/memory_init.wast index 9a6fb7cd6c..670bddc28d 100644 --- a/test/core/memory_init.wast +++ b/test/core/memory_init.wast @@ -825,11 +825,7 @@ (assert_trap (invoke "run" (i32.const 65528) (i32.const 16)) "out of bounds") -(assert_return (invoke "checkRange" (i32.const 0) (i32.const 65528) (i32.const 0)) - (i32.const -1)) -(assert_return (invoke "checkRange" (i32.const 65528) (i32.const 65536) (i32.const 66)) - (i32.const -1)) -(assert_return (invoke "checkRange" (i32.const 65536) (i32.const 65536) (i32.const 0)) +(assert_return (invoke "checkRange" (i32.const 0) (i32.const 1) (i32.const 0)) (i32.const -1)) (module (memory 1 1 ) @@ -852,11 +848,7 @@ (assert_trap (invoke "run" (i32.const 65527) (i32.const 16)) "out of bounds") -(assert_return (invoke "checkRange" (i32.const 0) (i32.const 65527) (i32.const 0)) - (i32.const -1)) -(assert_return (invoke "checkRange" (i32.const 65527) (i32.const 65536) (i32.const 66)) - (i32.const -1)) -(assert_return (invoke "checkRange" (i32.const 65536) (i32.const 65536) (i32.const 0)) +(assert_return (invoke "checkRange" (i32.const 0) (i32.const 1) (i32.const 0)) (i32.const -1)) (module (memory 1 1 ) @@ -879,11 +871,7 @@ (assert_trap (invoke "run" (i32.const 65472) (i32.const 30)) "out of bounds") -(assert_return (invoke "checkRange" (i32.const 0) (i32.const 65472) (i32.const 0)) - (i32.const -1)) -(assert_return (invoke "checkRange" (i32.const 65472) (i32.const 65488) (i32.const 66)) - (i32.const -1)) -(assert_return (invoke "checkRange" (i32.const 65488) (i32.const 65536) (i32.const 0)) +(assert_return (invoke "checkRange" (i32.const 0) (i32.const 1) (i32.const 0)) (i32.const -1)) (module (memory 1 1 ) @@ -906,11 +894,7 @@ (assert_trap (invoke "run" (i32.const 65473) (i32.const 31)) "out of bounds") -(assert_return (invoke "checkRange" (i32.const 0) (i32.const 65473) (i32.const 0)) - (i32.const -1)) -(assert_return (invoke "checkRange" (i32.const 65473) (i32.const 65489) (i32.const 66)) - (i32.const -1)) -(assert_return (invoke "checkRange" (i32.const 65489) (i32.const 65536) (i32.const 0)) +(assert_return (invoke "checkRange" (i32.const 0) (i32.const 1) (i32.const 0)) (i32.const -1)) (module (memory 1 ) @@ -933,11 +917,7 @@ (assert_trap (invoke "run" (i32.const 65528) (i32.const 4294967040)) "out of bounds") -(assert_return (invoke "checkRange" (i32.const 0) (i32.const 65528) (i32.const 0)) - (i32.const -1)) -(assert_return (invoke "checkRange" (i32.const 65528) (i32.const 65536) (i32.const 66)) - (i32.const -1)) -(assert_return (invoke "checkRange" (i32.const 65536) (i32.const 65536) (i32.const 0)) +(assert_return (invoke "checkRange" (i32.const 0) (i32.const 1) (i32.const 0)) (i32.const -1)) (module (memory 1 ) @@ -960,9 +940,5 @@ (assert_trap (invoke "run" (i32.const 0) (i32.const 4294967292)) "out of bounds") -(assert_return (invoke "checkRange" (i32.const 0) (i32.const 0) (i32.const 0)) - (i32.const -1)) -(assert_return (invoke "checkRange" (i32.const 0) (i32.const 16) (i32.const 66)) - (i32.const -1)) -(assert_return (invoke "checkRange" (i32.const 16) (i32.const 65536) (i32.const 0)) +(assert_return (invoke "checkRange" (i32.const 0) (i32.const 1) (i32.const 0)) (i32.const -1)) diff --git a/test/core/table_copy.wast b/test/core/table_copy.wast index 2d0fb78039..20949b3061 100644 --- a/test/core/table_copy.wast +++ b/test/core/table_copy.wast @@ -857,14 +857,14 @@ (assert_trap (invoke "run" (i32.const 0) (i32.const 24) (i32.const 16)) "out of bounds") -(assert_return (invoke "test" (i32.const 0)) (i32.const 0)) -(assert_return (invoke "test" (i32.const 1)) (i32.const 1)) -(assert_return (invoke "test" (i32.const 2)) (i32.const 2)) -(assert_return (invoke "test" (i32.const 3)) (i32.const 3)) -(assert_return (invoke "test" (i32.const 4)) (i32.const 4)) -(assert_return (invoke "test" (i32.const 5)) (i32.const 5)) -(assert_return (invoke "test" (i32.const 6)) (i32.const 6)) -(assert_return (invoke "test" (i32.const 7)) (i32.const 7)) +(assert_trap (invoke "test" (i32.const 0)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 1)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 2)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 3)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 4)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 5)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 6)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 7)) "uninitialized element") (assert_trap (invoke "test" (i32.const 8)) "uninitialized element") (assert_trap (invoke "test" (i32.const 9)) "uninitialized element") (assert_trap (invoke "test" (i32.const 10)) "uninitialized element") @@ -918,15 +918,15 @@ (assert_trap (invoke "run" (i32.const 0) (i32.const 23) (i32.const 15)) "out of bounds") -(assert_return (invoke "test" (i32.const 0)) (i32.const 0)) -(assert_return (invoke "test" (i32.const 1)) (i32.const 1)) -(assert_return (invoke "test" (i32.const 2)) (i32.const 2)) -(assert_return (invoke "test" (i32.const 3)) (i32.const 3)) -(assert_return (invoke "test" (i32.const 4)) (i32.const 4)) -(assert_return (invoke "test" (i32.const 5)) (i32.const 5)) -(assert_return (invoke "test" (i32.const 6)) (i32.const 6)) -(assert_return (invoke "test" (i32.const 7)) (i32.const 7)) -(assert_return (invoke "test" (i32.const 8)) (i32.const 8)) +(assert_trap (invoke "test" (i32.const 0)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 1)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 2)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 3)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 4)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 5)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 6)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 7)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 8)) "uninitialized element") (assert_trap (invoke "test" (i32.const 9)) "uninitialized element") (assert_trap (invoke "test" (i32.const 10)) "uninitialized element") (assert_trap (invoke "test" (i32.const 11)) "uninitialized element") @@ -1051,14 +1051,14 @@ (assert_trap (invoke "test" (i32.const 8)) "uninitialized element") (assert_trap (invoke "test" (i32.const 9)) "uninitialized element") (assert_trap (invoke "test" (i32.const 10)) "uninitialized element") -(assert_return (invoke "test" (i32.const 11)) (i32.const 0)) -(assert_return (invoke "test" (i32.const 12)) (i32.const 1)) -(assert_return (invoke "test" (i32.const 13)) (i32.const 2)) -(assert_return (invoke "test" (i32.const 14)) (i32.const 3)) -(assert_return (invoke "test" (i32.const 15)) (i32.const 4)) -(assert_return (invoke "test" (i32.const 16)) (i32.const 5)) -(assert_return (invoke "test" (i32.const 17)) (i32.const 6)) -(assert_return (invoke "test" (i32.const 18)) (i32.const 7)) +(assert_trap (invoke "test" (i32.const 11)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 12)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 13)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 14)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 15)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 16)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 17)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 18)) "uninitialized element") (assert_trap (invoke "test" (i32.const 19)) "uninitialized element") (assert_trap (invoke "test" (i32.const 20)) "uninitialized element") (assert_trap (invoke "test" (i32.const 21)) "uninitialized element") @@ -1183,14 +1183,14 @@ (assert_trap (invoke "test" (i32.const 18)) "uninitialized element") (assert_trap (invoke "test" (i32.const 19)) "uninitialized element") (assert_trap (invoke "test" (i32.const 20)) "uninitialized element") -(assert_return (invoke "test" (i32.const 21)) (i32.const 0)) -(assert_return (invoke "test" (i32.const 22)) (i32.const 1)) -(assert_return (invoke "test" (i32.const 23)) (i32.const 2)) -(assert_return (invoke "test" (i32.const 24)) (i32.const 3)) -(assert_return (invoke "test" (i32.const 25)) (i32.const 4)) -(assert_return (invoke "test" (i32.const 26)) (i32.const 5)) -(assert_return (invoke "test" (i32.const 27)) (i32.const 6)) -(assert_return (invoke "test" (i32.const 28)) (i32.const 7)) +(assert_trap (invoke "test" (i32.const 21)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 22)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 23)) "uninitialized element") +(assert_return (invoke "test" (i32.const 24)) (i32.const 0)) +(assert_return (invoke "test" (i32.const 25)) (i32.const 1)) +(assert_return (invoke "test" (i32.const 26)) (i32.const 2)) +(assert_return (invoke "test" (i32.const 27)) (i32.const 3)) +(assert_return (invoke "test" (i32.const 28)) (i32.const 4)) (assert_return (invoke "test" (i32.const 29)) (i32.const 5)) (assert_return (invoke "test" (i32.const 30)) (i32.const 6)) (assert_return (invoke "test" (i32.const 31)) (i32.const 7)) @@ -1284,22 +1284,22 @@ (assert_trap (invoke "run" (i32.const 0) (i32.const 112) (i32.const 4294967264)) "out of bounds") -(assert_return (invoke "test" (i32.const 0)) (i32.const 0)) -(assert_return (invoke "test" (i32.const 1)) (i32.const 1)) -(assert_return (invoke "test" (i32.const 2)) (i32.const 2)) -(assert_return (invoke "test" (i32.const 3)) (i32.const 3)) -(assert_return (invoke "test" (i32.const 4)) (i32.const 4)) -(assert_return (invoke "test" (i32.const 5)) (i32.const 5)) -(assert_return (invoke "test" (i32.const 6)) (i32.const 6)) -(assert_return (invoke "test" (i32.const 7)) (i32.const 7)) -(assert_return (invoke "test" (i32.const 8)) (i32.const 8)) -(assert_return (invoke "test" (i32.const 9)) (i32.const 9)) -(assert_return (invoke "test" (i32.const 10)) (i32.const 10)) -(assert_return (invoke "test" (i32.const 11)) (i32.const 11)) -(assert_return (invoke "test" (i32.const 12)) (i32.const 12)) -(assert_return (invoke "test" (i32.const 13)) (i32.const 13)) -(assert_return (invoke "test" (i32.const 14)) (i32.const 14)) -(assert_return (invoke "test" (i32.const 15)) (i32.const 15)) +(assert_trap (invoke "test" (i32.const 0)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 1)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 2)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 3)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 4)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 5)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 6)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 7)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 8)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 9)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 10)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 11)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 12)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 13)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 14)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 15)) "uninitialized element") (assert_trap (invoke "test" (i32.const 16)) "uninitialized element") (assert_trap (invoke "test" (i32.const 17)) "uninitialized element") (assert_trap (invoke "test" (i32.const 18)) "uninitialized element") diff --git a/test/core/table_init.wast b/test/core/table_init.wast index 6cee47156e..658deb68f6 100644 --- a/test/core/table_init.wast +++ b/test/core/table_init.wast @@ -1113,14 +1113,6 @@ (func (export "run") (param $offs i32) (param $len i32) (table.init 0 (local.get $offs) (i32.const 0) (local.get $len)))) (assert_trap (invoke "run" (i32.const 24) (i32.const 16)) "out of bounds") -(assert_return (invoke "test" (i32.const 24)) (i32.const 0)) -(assert_return (invoke "test" (i32.const 25)) (i32.const 1)) -(assert_return (invoke "test" (i32.const 26)) (i32.const 2)) -(assert_return (invoke "test" (i32.const 27)) (i32.const 3)) -(assert_return (invoke "test" (i32.const 28)) (i32.const 4)) -(assert_return (invoke "test" (i32.const 29)) (i32.const 5)) -(assert_return (invoke "test" (i32.const 30)) (i32.const 6)) -(assert_return (invoke "test" (i32.const 31)) (i32.const 7)) (assert_trap (invoke "test" (i32.const 0)) "uninitialized element") (assert_trap (invoke "test" (i32.const 1)) "uninitialized element") (assert_trap (invoke "test" (i32.const 2)) "uninitialized element") @@ -1145,6 +1137,14 @@ (assert_trap (invoke "test" (i32.const 21)) "uninitialized element") (assert_trap (invoke "test" (i32.const 22)) "uninitialized element") (assert_trap (invoke "test" (i32.const 23)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 24)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 25)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 26)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 27)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 28)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 29)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 30)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 31)) "uninitialized element") (module (type (func (result i32))) @@ -1175,13 +1175,6 @@ (func (export "run") (param $offs i32) (param $len i32) (table.init 0 (local.get $offs) (i32.const 0) (local.get $len)))) (assert_trap (invoke "run" (i32.const 25) (i32.const 16)) "out of bounds") -(assert_return (invoke "test" (i32.const 25)) (i32.const 0)) -(assert_return (invoke "test" (i32.const 26)) (i32.const 1)) -(assert_return (invoke "test" (i32.const 27)) (i32.const 2)) -(assert_return (invoke "test" (i32.const 28)) (i32.const 3)) -(assert_return (invoke "test" (i32.const 29)) (i32.const 4)) -(assert_return (invoke "test" (i32.const 30)) (i32.const 5)) -(assert_return (invoke "test" (i32.const 31)) (i32.const 6)) (assert_trap (invoke "test" (i32.const 0)) "uninitialized element") (assert_trap (invoke "test" (i32.const 1)) "uninitialized element") (assert_trap (invoke "test" (i32.const 2)) "uninitialized element") @@ -1207,6 +1200,13 @@ (assert_trap (invoke "test" (i32.const 22)) "uninitialized element") (assert_trap (invoke "test" (i32.const 23)) "uninitialized element") (assert_trap (invoke "test" (i32.const 24)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 25)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 26)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 27)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 28)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 29)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 30)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 31)) "uninitialized element") (module (type (func (result i32))) @@ -1237,70 +1237,6 @@ (func (export "run") (param $offs i32) (param $len i32) (table.init 0 (local.get $offs) (i32.const 0) (local.get $len)))) (assert_trap (invoke "run" (i32.const 96) (i32.const 32)) "out of bounds") -(assert_return (invoke "test" (i32.const 96)) (i32.const 0)) -(assert_return (invoke "test" (i32.const 97)) (i32.const 1)) -(assert_return (invoke "test" (i32.const 98)) (i32.const 2)) -(assert_return (invoke "test" (i32.const 99)) (i32.const 3)) -(assert_return (invoke "test" (i32.const 100)) (i32.const 4)) -(assert_return (invoke "test" (i32.const 101)) (i32.const 5)) -(assert_return (invoke "test" (i32.const 102)) (i32.const 6)) -(assert_return (invoke "test" (i32.const 103)) (i32.const 7)) -(assert_return (invoke "test" (i32.const 104)) (i32.const 8)) -(assert_return (invoke "test" (i32.const 105)) (i32.const 9)) -(assert_return (invoke "test" (i32.const 106)) (i32.const 10)) -(assert_return (invoke "test" (i32.const 107)) (i32.const 11)) -(assert_return (invoke "test" (i32.const 108)) (i32.const 12)) -(assert_return (invoke "test" (i32.const 109)) (i32.const 13)) -(assert_return (invoke "test" (i32.const 110)) (i32.const 14)) -(assert_return (invoke "test" (i32.const 111)) (i32.const 15)) -(assert_trap (invoke "test" (i32.const 112)) "uninitialized element") -(assert_trap (invoke "test" (i32.const 113)) "uninitialized element") -(assert_trap (invoke "test" (i32.const 114)) "uninitialized element") -(assert_trap (invoke "test" (i32.const 115)) "uninitialized element") -(assert_trap (invoke "test" (i32.const 116)) "uninitialized element") -(assert_trap (invoke "test" (i32.const 117)) "uninitialized element") -(assert_trap (invoke "test" (i32.const 118)) "uninitialized element") -(assert_trap (invoke "test" (i32.const 119)) "uninitialized element") -(assert_trap (invoke "test" (i32.const 120)) "uninitialized element") -(assert_trap (invoke "test" (i32.const 121)) "uninitialized element") -(assert_trap (invoke "test" (i32.const 122)) "uninitialized element") -(assert_trap (invoke "test" (i32.const 123)) "uninitialized element") -(assert_trap (invoke "test" (i32.const 124)) "uninitialized element") -(assert_trap (invoke "test" (i32.const 125)) "uninitialized element") -(assert_trap (invoke "test" (i32.const 126)) "uninitialized element") -(assert_trap (invoke "test" (i32.const 127)) "uninitialized element") -(assert_trap (invoke "test" (i32.const 128)) "uninitialized element") -(assert_trap (invoke "test" (i32.const 129)) "uninitialized element") -(assert_trap (invoke "test" (i32.const 130)) "uninitialized element") -(assert_trap (invoke "test" (i32.const 131)) "uninitialized element") -(assert_trap (invoke "test" (i32.const 132)) "uninitialized element") -(assert_trap (invoke "test" (i32.const 133)) "uninitialized element") -(assert_trap (invoke "test" (i32.const 134)) "uninitialized element") -(assert_trap (invoke "test" (i32.const 135)) "uninitialized element") -(assert_trap (invoke "test" (i32.const 136)) "uninitialized element") -(assert_trap (invoke "test" (i32.const 137)) "uninitialized element") -(assert_trap (invoke "test" (i32.const 138)) "uninitialized element") -(assert_trap (invoke "test" (i32.const 139)) "uninitialized element") -(assert_trap (invoke "test" (i32.const 140)) "uninitialized element") -(assert_trap (invoke "test" (i32.const 141)) "uninitialized element") -(assert_trap (invoke "test" (i32.const 142)) "uninitialized element") -(assert_trap (invoke "test" (i32.const 143)) "uninitialized element") -(assert_trap (invoke "test" (i32.const 144)) "uninitialized element") -(assert_trap (invoke "test" (i32.const 145)) "uninitialized element") -(assert_trap (invoke "test" (i32.const 146)) "uninitialized element") -(assert_trap (invoke "test" (i32.const 147)) "uninitialized element") -(assert_trap (invoke "test" (i32.const 148)) "uninitialized element") -(assert_trap (invoke "test" (i32.const 149)) "uninitialized element") -(assert_trap (invoke "test" (i32.const 150)) "uninitialized element") -(assert_trap (invoke "test" (i32.const 151)) "uninitialized element") -(assert_trap (invoke "test" (i32.const 152)) "uninitialized element") -(assert_trap (invoke "test" (i32.const 153)) "uninitialized element") -(assert_trap (invoke "test" (i32.const 154)) "uninitialized element") -(assert_trap (invoke "test" (i32.const 155)) "uninitialized element") -(assert_trap (invoke "test" (i32.const 156)) "uninitialized element") -(assert_trap (invoke "test" (i32.const 157)) "uninitialized element") -(assert_trap (invoke "test" (i32.const 158)) "uninitialized element") -(assert_trap (invoke "test" (i32.const 159)) "uninitialized element") (assert_trap (invoke "test" (i32.const 0)) "uninitialized element") (assert_trap (invoke "test" (i32.const 1)) "uninitialized element") (assert_trap (invoke "test" (i32.const 2)) "uninitialized element") @@ -1397,52 +1333,23 @@ (assert_trap (invoke "test" (i32.const 93)) "uninitialized element") (assert_trap (invoke "test" (i32.const 94)) "uninitialized element") (assert_trap (invoke "test" (i32.const 95)) "uninitialized element") - -(module - (type (func (result i32))) - (table 160 320 funcref) - (elem funcref - (ref.func $f0) (ref.func $f1) (ref.func $f2) (ref.func $f3) - (ref.func $f4) (ref.func $f5) (ref.func $f6) (ref.func $f7) - (ref.func $f8) (ref.func $f9) (ref.func $f10) (ref.func $f11) - (ref.func $f12) (ref.func $f13) (ref.func $f14) (ref.func $f15)) - (func $f0 (export "f0") (result i32) (i32.const 0)) - (func $f1 (export "f1") (result i32) (i32.const 1)) - (func $f2 (export "f2") (result i32) (i32.const 2)) - (func $f3 (export "f3") (result i32) (i32.const 3)) - (func $f4 (export "f4") (result i32) (i32.const 4)) - (func $f5 (export "f5") (result i32) (i32.const 5)) - (func $f6 (export "f6") (result i32) (i32.const 6)) - (func $f7 (export "f7") (result i32) (i32.const 7)) - (func $f8 (export "f8") (result i32) (i32.const 8)) - (func $f9 (export "f9") (result i32) (i32.const 9)) - (func $f10 (export "f10") (result i32) (i32.const 10)) - (func $f11 (export "f11") (result i32) (i32.const 11)) - (func $f12 (export "f12") (result i32) (i32.const 12)) - (func $f13 (export "f13") (result i32) (i32.const 13)) - (func $f14 (export "f14") (result i32) (i32.const 14)) - (func $f15 (export "f15") (result i32) (i32.const 15)) - (func (export "test") (param $n i32) (result i32) - (call_indirect (type 0) (local.get $n))) - (func (export "run") (param $offs i32) (param $len i32) - (table.init 0 (local.get $offs) (i32.const 0) (local.get $len)))) -(assert_trap (invoke "run" (i32.const 97) (i32.const 31)) "out of bounds") -(assert_return (invoke "test" (i32.const 97)) (i32.const 0)) -(assert_return (invoke "test" (i32.const 98)) (i32.const 1)) -(assert_return (invoke "test" (i32.const 99)) (i32.const 2)) -(assert_return (invoke "test" (i32.const 100)) (i32.const 3)) -(assert_return (invoke "test" (i32.const 101)) (i32.const 4)) -(assert_return (invoke "test" (i32.const 102)) (i32.const 5)) -(assert_return (invoke "test" (i32.const 103)) (i32.const 6)) -(assert_return (invoke "test" (i32.const 104)) (i32.const 7)) -(assert_return (invoke "test" (i32.const 105)) (i32.const 8)) -(assert_return (invoke "test" (i32.const 106)) (i32.const 9)) -(assert_return (invoke "test" (i32.const 107)) (i32.const 10)) -(assert_return (invoke "test" (i32.const 108)) (i32.const 11)) -(assert_return (invoke "test" (i32.const 109)) (i32.const 12)) -(assert_return (invoke "test" (i32.const 110)) (i32.const 13)) -(assert_return (invoke "test" (i32.const 111)) (i32.const 14)) -(assert_return (invoke "test" (i32.const 112)) (i32.const 15)) +(assert_trap (invoke "test" (i32.const 96)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 97)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 98)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 99)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 100)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 101)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 102)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 103)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 104)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 105)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 106)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 107)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 108)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 109)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 110)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 111)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 112)) "uninitialized element") (assert_trap (invoke "test" (i32.const 113)) "uninitialized element") (assert_trap (invoke "test" (i32.const 114)) "uninitialized element") (assert_trap (invoke "test" (i32.const 115)) "uninitialized element") @@ -1490,6 +1397,36 @@ (assert_trap (invoke "test" (i32.const 157)) "uninitialized element") (assert_trap (invoke "test" (i32.const 158)) "uninitialized element") (assert_trap (invoke "test" (i32.const 159)) "uninitialized element") + +(module + (type (func (result i32))) + (table 160 320 funcref) + (elem funcref + (ref.func $f0) (ref.func $f1) (ref.func $f2) (ref.func $f3) + (ref.func $f4) (ref.func $f5) (ref.func $f6) (ref.func $f7) + (ref.func $f8) (ref.func $f9) (ref.func $f10) (ref.func $f11) + (ref.func $f12) (ref.func $f13) (ref.func $f14) (ref.func $f15)) + (func $f0 (export "f0") (result i32) (i32.const 0)) + (func $f1 (export "f1") (result i32) (i32.const 1)) + (func $f2 (export "f2") (result i32) (i32.const 2)) + (func $f3 (export "f3") (result i32) (i32.const 3)) + (func $f4 (export "f4") (result i32) (i32.const 4)) + (func $f5 (export "f5") (result i32) (i32.const 5)) + (func $f6 (export "f6") (result i32) (i32.const 6)) + (func $f7 (export "f7") (result i32) (i32.const 7)) + (func $f8 (export "f8") (result i32) (i32.const 8)) + (func $f9 (export "f9") (result i32) (i32.const 9)) + (func $f10 (export "f10") (result i32) (i32.const 10)) + (func $f11 (export "f11") (result i32) (i32.const 11)) + (func $f12 (export "f12") (result i32) (i32.const 12)) + (func $f13 (export "f13") (result i32) (i32.const 13)) + (func $f14 (export "f14") (result i32) (i32.const 14)) + (func $f15 (export "f15") (result i32) (i32.const 15)) + (func (export "test") (param $n i32) (result i32) + (call_indirect (type 0) (local.get $n))) + (func (export "run") (param $offs i32) (param $len i32) + (table.init 0 (local.get $offs) (i32.const 0) (local.get $len)))) +(assert_trap (invoke "run" (i32.const 97) (i32.const 31)) "out of bounds") (assert_trap (invoke "test" (i32.const 0)) "uninitialized element") (assert_trap (invoke "test" (i32.const 1)) "uninitialized element") (assert_trap (invoke "test" (i32.const 2)) "uninitialized element") @@ -1587,6 +1524,69 @@ (assert_trap (invoke "test" (i32.const 94)) "uninitialized element") (assert_trap (invoke "test" (i32.const 95)) "uninitialized element") (assert_trap (invoke "test" (i32.const 96)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 97)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 98)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 99)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 100)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 101)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 102)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 103)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 104)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 105)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 106)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 107)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 108)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 109)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 110)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 111)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 112)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 113)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 114)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 115)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 116)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 117)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 118)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 119)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 120)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 121)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 122)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 123)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 124)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 125)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 126)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 127)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 128)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 129)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 130)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 131)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 132)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 133)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 134)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 135)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 136)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 137)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 138)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 139)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 140)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 141)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 142)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 143)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 144)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 145)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 146)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 147)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 148)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 149)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 150)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 151)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 152)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 153)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 154)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 155)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 156)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 157)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 158)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 159)) "uninitialized element") (module (type (func (result i32))) @@ -1617,22 +1617,6 @@ (func (export "run") (param $offs i32) (param $len i32) (table.init 0 (local.get $offs) (i32.const 0) (local.get $len)))) (assert_trap (invoke "run" (i32.const 48) (i32.const 4294967280)) "out of bounds") -(assert_return (invoke "test" (i32.const 48)) (i32.const 0)) -(assert_return (invoke "test" (i32.const 49)) (i32.const 1)) -(assert_return (invoke "test" (i32.const 50)) (i32.const 2)) -(assert_return (invoke "test" (i32.const 51)) (i32.const 3)) -(assert_return (invoke "test" (i32.const 52)) (i32.const 4)) -(assert_return (invoke "test" (i32.const 53)) (i32.const 5)) -(assert_return (invoke "test" (i32.const 54)) (i32.const 6)) -(assert_return (invoke "test" (i32.const 55)) (i32.const 7)) -(assert_return (invoke "test" (i32.const 56)) (i32.const 8)) -(assert_return (invoke "test" (i32.const 57)) (i32.const 9)) -(assert_return (invoke "test" (i32.const 58)) (i32.const 10)) -(assert_return (invoke "test" (i32.const 59)) (i32.const 11)) -(assert_return (invoke "test" (i32.const 60)) (i32.const 12)) -(assert_return (invoke "test" (i32.const 61)) (i32.const 13)) -(assert_return (invoke "test" (i32.const 62)) (i32.const 14)) -(assert_return (invoke "test" (i32.const 63)) (i32.const 15)) (assert_trap (invoke "test" (i32.const 0)) "uninitialized element") (assert_trap (invoke "test" (i32.const 1)) "uninitialized element") (assert_trap (invoke "test" (i32.const 2)) "uninitialized element") @@ -1681,6 +1665,22 @@ (assert_trap (invoke "test" (i32.const 45)) "uninitialized element") (assert_trap (invoke "test" (i32.const 46)) "uninitialized element") (assert_trap (invoke "test" (i32.const 47)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 48)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 49)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 50)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 51)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 52)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 53)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 54)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 55)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 56)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 57)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 58)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 59)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 60)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 61)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 62)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 63)) "uninitialized element") (module (type (func (result i32))) @@ -1711,11 +1711,19 @@ (func (export "run") (param $offs i32) (param $len i32) (table.init 0 (local.get $offs) (i32.const 8) (local.get $len)))) (assert_trap (invoke "run" (i32.const 0) (i32.const 4294967292)) "out of bounds") -(assert_return (invoke "test" (i32.const 0)) (i32.const 8)) -(assert_return (invoke "test" (i32.const 1)) (i32.const 9)) -(assert_return (invoke "test" (i32.const 2)) (i32.const 10)) -(assert_return (invoke "test" (i32.const 3)) (i32.const 11)) -(assert_return (invoke "test" (i32.const 4)) (i32.const 12)) -(assert_return (invoke "test" (i32.const 5)) (i32.const 13)) -(assert_return (invoke "test" (i32.const 6)) (i32.const 14)) -(assert_return (invoke "test" (i32.const 7)) (i32.const 15)) +(assert_trap (invoke "test" (i32.const 0)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 1)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 2)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 3)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 4)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 5)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 6)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 7)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 8)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 9)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 10)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 11)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 12)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 13)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 14)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 15)) "uninitialized element") diff --git a/test/meta/generate_memory_copy.js b/test/meta/generate_memory_copy.js index 775b6dddb7..687ce6c7c8 100644 --- a/test/meta/generate_memory_copy.js +++ b/test/meta/generate_memory_copy.js @@ -108,38 +108,13 @@ function mem_copy(min, max, shared, srcOffs, targetOffs, len) { let immediateOOB = copyDown && (srcOffs + len > memLength || targetOffs + len > memLength); - var t = 0; var s = 0; var i = 0; - function checkTarget() { - if (i >= targetOffs && i < targetLim) { - print(`(assert_return (invoke "load8_u" (i32.const ${i})) (i32.const ${(t++) & 0xFF}))`); - if (i >= srcOffs && i < srcLim) - s++; - return true; - } - return false; - } - function checkSource() { - if (i >= srcOffs && i < srcLim) { - print(`(assert_return (invoke "load8_u" (i32.const ${i})) (i32.const ${(s++) & 0xFF}))`); - if (i >= targetOffs && i < targetLim) - t++; - return true; - } - return false; - } - let k = 0; for (i=0; i < memLength; i++ ) { - if (immediateOOB) { - if (checkSource()) - continue; - } else { - if (copyDown && (checkSource() || checkTarget())) - continue; - if (!copyDown && (checkTarget() || checkSource())) - continue; + if (i >= srcOffs && i < srcLim) { + print(`(assert_return (invoke "load8_u" (i32.const ${i})) (i32.const ${(s++) & 0xFF}))`); + continue; } // Only spot-check for zero, or we'll be here all night. if (++k == 199) { diff --git a/test/meta/generate_memory_fill.js b/test/meta/generate_memory_fill.js index dc94382598..cb048f6a11 100644 --- a/test/meta/generate_memory_fill.js +++ b/test/meta/generate_memory_fill.js @@ -123,7 +123,7 @@ print( }}} } -// memory.fill: out of bounds, but should perform a partial fill. +// memory.fill: out of bounds, and should not perform a partial fill. // // Arithmetic overflow of memory offset + len should not affect the behavior, we // should still fill up to the limit. @@ -143,8 +143,7 @@ function mem_fill(min, max, shared, backup, write=backup*2) { `(assert_trap (invoke "run" (i32.const ${offs}) (i32.const ${val}) (i32.const ${write})) "out of bounds") `); - checkRange(offs, offs+backup, val); - checkRange(0, offs, 0); + checkRange(0, min, 0); } mem_fill(1, 1, "", 256); diff --git a/test/meta/generate_memory_init.js b/test/meta/generate_memory_init.js index e06055476c..eccbabfecc 100644 --- a/test/meta/generate_memory_init.js +++ b/test/meta/generate_memory_init.js @@ -257,9 +257,7 @@ function mem_init(min, max, shared, backup, write) { `(assert_trap (invoke "run" (i32.const ${offs}) (i32.const ${write})) "out of bounds") `); - checkRange(0, offs, 0); - checkRange(offs, offs+Math.min(backup, mem_init_len), 0x42); - checkRange(offs+Math.min(backup, mem_init_len), offs+backup, 0); + checkRange(0, min, 0); } // We exceed the bounds of the memory but not of the data segment diff --git a/test/meta/generate_table_copy.js b/test/meta/generate_table_copy.js index a14c59f825..d399fdc42a 100644 --- a/test/meta/generate_table_copy.js +++ b/test/meta/generate_table_copy.js @@ -275,37 +275,12 @@ function tbl_copy(min, max, srcOffs, targetOffs, len) { print(`(assert_trap (invoke "run" (i32.const ${targetOffs}) (i32.const ${srcOffs}) (i32.const ${len})) "out of bounds")`); - var t = 0; var s = 0; var i = 0; - function checkTarget() { - if (i >= targetOffs && i < targetLim) { - print(`(assert_return (invoke "test" (i32.const ${i})) (i32.const ${t++}))`); - if (i >= srcOffs && i < srcLim) - s++; - return true; - } - return false; - } - function checkSource() { + for (i=0; i < tblLength; i++ ) { if (i >= srcOffs && i < srcLim) { print(`(assert_return (invoke "test" (i32.const ${i})) (i32.const ${s++}))`); - if (i >= targetOffs && i < targetLim) - t++; - return true; - } - return false; - } - - for (i=0; i < tblLength; i++ ) { - if (immediateOOB) { - if (checkSource()) - continue; - } else { - if (copyDown && (checkSource() || checkTarget())) - continue; - if (!copyDown && (checkTarget() || checkSource())) - continue; + continue; } print(`(assert_trap (invoke "test" (i32.const ${i})) "uninitialized element")`); } diff --git a/test/meta/generate_table_init.js b/test/meta/generate_table_init.js index 8366d19ec7..bc59409035 100644 --- a/test/meta/generate_table_init.js +++ b/test/meta/generate_table_init.js @@ -315,13 +315,7 @@ function tbl_init(min, max, backup, write, segoffs=0) { // table with as much data as was available. let offs = min - backup; print(`(assert_trap (invoke "run" (i32.const ${offs}) (i32.const ${write})) "out of bounds")`); - for (let i=0; i < Math.min(backup, tbl_init_len - segoffs); i++) { - print(`(assert_return (invoke "test" (i32.const ${offs + i})) (i32.const ${i + segoffs}))`); - } - for (let i=Math.min(backup, tbl_init_len); i < backup; i++) { - print(`(assert_trap (invoke "test" (i32.const ${offs + i})) "uninitialized element")`); - } - for (let i=0; i < offs; i++) { + for (let i=0; i < min; i++) { print(`(assert_trap (invoke "test" (i32.const ${i})) "uninitialized element")`); } } From 34a7ebea715aa0644ebb98300eb13ebda4f1a9cd Mon Sep 17 00:00:00 2001 From: Andreas Rossberg Date: Thu, 14 Nov 2019 19:03:41 +0100 Subject: [PATCH 132/199] Fix layout --- document/core/text/instructions.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/document/core/text/instructions.rst b/document/core/text/instructions.rst index d5901a87a9..021b11f2fb 100644 --- a/document/core/text/instructions.rst +++ b/document/core/text/instructions.rst @@ -144,7 +144,7 @@ Reference Instructions \begin{array}{llclll} \production{instruction} & \Tplaininstr_I &::=& \dots \\ &&|& \text{ref.null} &\Rightarrow& \REFNULL \\ &&|& - \text{ref.is\_null} &\Rightarrow& \REFISNULL \\ + \text{ref.is\_null} &\Rightarrow& \REFISNULL \\ &&|& \text{ref.func}~~x{:}\Tfuncidx &\Rightarrow& \REFFUNC~x \\ &&|& \end{array} From b2a5c4fb62f67451a469f299476fcdff6498db8a Mon Sep 17 00:00:00 2001 From: Andreas Rossberg Date: Fri, 22 Nov 2019 19:16:02 +0100 Subject: [PATCH 133/199] [interpreter] Simplify zero-len and drop semantics (#126) * [interpreter] Simplify zero-len and drop semantics * Update overview * [spec] Change drop semantics * [spec] Forgot to adjust prose for *.init ops * [test] Update generated tests for OOBs and dropping changes (#131) --- document/core/exec/instructions.rst | 86 +++++------------ document/core/exec/runtime.rst | 5 +- interpreter/exec/eval.ml | 97 ++++++++------------ interpreter/runtime/instance.ml | 4 +- proposals/bulk-memory-operations/Overview.md | 12 +-- test/core/bulk.wast | 55 ++++++----- test/core/data.wast | 21 +++-- test/core/elem.wast | 11 ++- test/core/memory_copy.wast | 10 +- test/core/memory_fill.wast | 2 +- test/core/memory_init.wast | 17 +++- test/core/table_copy.wast | 28 +++++- test/core/table_init.wast | 35 +++++-- test/meta/generate_memory_copy.js | 17 +++- test/meta/generate_memory_fill.js | 6 +- test/meta/generate_memory_init.js | 24 +++-- test/meta/generate_table_copy.js | 13 ++- test/meta/generate_table_init.js | 30 +++--- 18 files changed, 260 insertions(+), 213 deletions(-) diff --git a/document/core/exec/instructions.rst b/document/core/exec/instructions.rst index 8dc36e7627..eecf0f8d41 100644 --- a/document/core/exec/instructions.rst +++ b/document/core/exec/instructions.rst @@ -728,7 +728,7 @@ Memory Instructions 8. Assert: due to :ref:`validation `, :math:`S.\SDATA[\X{da}]` exists. -9. Let :math:`\X{data}^?` be the optional :ref:`data instance ` :math:`S.\SDATA[\X{da}]`. +9. Let :math:`\X{data}` be the :ref:`data instance ` :math:`S.\SDATA[\X{da}]`. 10. Assert: due to :ref:`validation `, a value of :ref:`value type ` |I32| is on the top of the stack. @@ -746,11 +746,7 @@ Memory Instructions a. Return. -17. If :math:`\X{data}^? = \epsilon`, then: - - a. Trap. - -18. If :math:`cnt = 1`, then: +17. If :math:`cnt = 1`, then: a. Push the value :math:`\I32.\CONST~dst` to the stack. @@ -766,21 +762,21 @@ Memory Instructions f. Return. -19. Push the value :math:`\I32.\CONST~dst` to the stack. +18. Push the value :math:`\I32.\CONST~dst` to the stack. -20. Push the value :math:`\I32.\CONST~src` to the stack. +19. Push the value :math:`\I32.\CONST~src` to the stack. -21. Push the value :math:`\I32.\CONST~1` to the stack. +20. Push the value :math:`\I32.\CONST~1` to the stack. -22. Execute the instruction :math:`\MEMORYINIT~x`. +21. Execute the instruction :math:`\MEMORYINIT~x`. -23. Push the value :math:`\vconst_{\I32}(dst+1)` to the stack. +22. Push the value :math:`\vconst_{\I32}(dst+1)` to the stack. -24. Push the value :math:`\vconst_{\I32}(src+1)` to the stack. +23. Push the value :math:`\vconst_{\I32}(src+1)` to the stack. -25. Push the value :math:`\I32.\CONST~(cnt-1)` to the stack. +24. Push the value :math:`\I32.\CONST~(cnt-1)` to the stack. -26. Execute the instruction :math:`\MEMORYINIT~x`. +25. Execute the instruction :math:`\MEMORYINIT~x`. .. math:: ~\\[-1ex] @@ -830,13 +826,7 @@ Memory Instructions 4. Assert: due to :ref:`validation `, :math:`S.\SDATA[a]` exists. -5. Let :math:`\X{data}^?` be the optional :ref:`data instance ` :math:`S.\SDATA[a]`. - -6. If :math:`\X{data}^? = \epsilon`, then: - - a. Trap. - -7. Replace :math:`S.\SDATA[a]` with :math:`\epsilon`. +5. Replace :math:`S.\SDATA[a]` with the :ref:`data instance ` :math:`\{\DIINIT~\epsilon\}`. .. math:: ~\\[-1ex] @@ -845,16 +835,7 @@ Memory Instructions S; F; (\DATADROP~x) &\stepto& S'; F; \epsilon \end{array} \\ \qquad - \begin{array}[t]{@{}r@{~}l@{}} - (\iff & S.\SDATA[F.\AMODULE.\MIDATAS[x]] \ne \epsilon \\ - \wedge & S' = S \with \SDATA[F.\AMODULE.\MIDATAS[x]] = \epsilon) \\ - \end{array} - \\[1ex] - \begin{array}{lcl@{\qquad}l} - S; F; (\DATADROP~x) &\stepto& S; F; \TRAP - \end{array} - \\ \qquad - (\otherwise) + (\iff S' = S \with \SDATA[F.\AMODULE.\MIDATAS[x]] = \{ \DIINIT~\epsilon \}) \\ \end{array} @@ -1089,7 +1070,7 @@ Table Instructions 8. Assert: due to :ref:`validation `, :math:`S.\SELEM[\X{ea}]` exists. -9. Let :math:`\X{elem}^?` be the optional :ref:`element instance ` :math:`S.\SELEM[\X{ea}]`. +9. Let :math:`\X{elem}` be the :ref:`element instance ` :math:`S.\SELEM[\X{ea}]`. 10. Assert: due to :ref:`validation `, a value of :ref:`value type ` |I32| is on the top of the stack. @@ -1107,11 +1088,7 @@ Table Instructions a. Return. -17. If :math:`\X{elem}^? = \epsilon`, then: - - a. Trap. - -18. If :math:`cnt = 1`, then: +17. If :math:`cnt = 1`, then: a. Push the value :math:`\I32.\CONST~dst` to the stack. @@ -1127,21 +1104,21 @@ Table Instructions f. Return. -19. Push the value :math:`\I32.\CONST~dst` to the stack. +18. Push the value :math:`\I32.\CONST~dst` to the stack. -20. Push the value :math:`\I32.\CONST~src` to the stack. +19. Push the value :math:`\I32.\CONST~src` to the stack. -21. Push the value :math:`\I32.\CONST~1` to the stack. +20. Push the value :math:`\I32.\CONST~1` to the stack. -22. Execute the instruction :math:`\TABLEINIT~x`. +21. Execute the instruction :math:`\TABLEINIT~x`. -23. Push the value :math:`\vconst_{\I32}(dst+1)` to the stack. +22. Push the value :math:`\vconst_{\I32}(dst+1)` to the stack. -24. Push the value :math:`\vconst_{\I32}(src+1)` to the stack. +23. Push the value :math:`\vconst_{\I32}(src+1)` to the stack. -25. Push the value :math:`\I32.\CONST~(cnt-1)` to the stack. +24. Push the value :math:`\I32.\CONST~(cnt-1)` to the stack. -26. Execute the instruction :math:`\TABLEINIT~x`. +25. Execute the instruction :math:`\TABLEINIT~x`. .. math:: ~\\[-1ex] @@ -1191,13 +1168,7 @@ Table Instructions 4. Assert: due to :ref:`validation `, :math:`S.\SELEM[a]` exists. -5. Let :math:`\X{elem}^?` be the optional :ref:`elem instance ` :math:`S.\SELEM[a]`. - -6. If :math:`\X{elem}^? = \epsilon`, then: - - a. Trap. - -7. Replace :math:`S.\SELEM[a]` with :math:`\epsilon`. +5. Replace :math:`S.\SELEM[a]` with the :ref:`element instance ` :math:`\{\EIINIT~\epsilon\}`. .. math:: ~\\[-1ex] @@ -1206,16 +1177,7 @@ Table Instructions S; F; (\ELEMDROP~x) &\stepto& S'; F; \epsilon \end{array} \\ \qquad - \begin{array}[t]{@{}r@{~}l@{}} - (\iff & S.\SELEM[F.\AMODULE.\MIELEMS[x]] \ne \epsilon \\ - \wedge & S' = S \with \SELEM[F.\AMODULE.\MIELEMS[x]] = \epsilon) \\ - \end{array} - \\[1ex] - \begin{array}{lcl@{\qquad}l} - S; F; (\ELEMDROP~x) &\stepto& S; F; \TRAP - \end{array} - \\ \qquad - (\otherwise) + (\iff S' = S \with \SELEM[F.\AMODULE.\MIELEMS[x]] = \{ \EIINIT~\epsilon \}) \\ \end{array} diff --git a/document/core/exec/runtime.rst b/document/core/exec/runtime.rst index 06ab4ecc86..5889656055 100644 --- a/document/core/exec/runtime.rst +++ b/document/core/exec/runtime.rst @@ -75,7 +75,6 @@ Store The *store* represents all global state that can be manipulated by WebAssembly programs. It consists of the runtime representation of all *instances* of :ref:`functions `, :ref:`tables `, :ref:`memories `, and :ref:`globals `, :ref:`element segments `, and :ref:`data segments ` that have been :ref:`allocated ` during the life time of the abstract machine. [#gc]_ -Element and data segments can be dropped by the owning module, in which case the respective instances are replaced with :math:`\epsilon`. It is an invariant of the semantics that no element or data instance is :ref:`addressed ` from anywhere else but the owning module instances. Syntactically, the store is defined as a :ref:`record ` listing the existing instances of each category: @@ -88,8 +87,8 @@ Syntactically, the store is defined as a :ref:`record ` listing \STABLES & \tableinst^\ast, \\ \SMEMS & \meminst^\ast, \\ \SGLOBALS & \globalinst^\ast, \\ - \SELEM & (\eleminst^?)^\ast, \\ - \SDATA & (\datainst^?)^\ast ~\} \\ + \SELEM & \eleminst^\ast, \\ + \SDATA & \datainst^\ast ~\} \\ \end{array} \end{array} diff --git a/interpreter/exec/eval.ml b/interpreter/exec/eval.ml index b64ce7f750..fcc88b4098 100644 --- a/interpreter/exec/eval.ml +++ b/interpreter/exec/eval.ml @@ -122,22 +122,16 @@ let mem_oob frame x i n = (Memory.bound (memory frame.inst x)) let data_oob frame x i n = - match !(data frame.inst x) with - | None -> false - | Some bs -> - I64.gt_u (I64.add (I64_convert.extend_i32_u i) (I64_convert.extend_i32_u n)) - (I64.of_int_u (String.length bs)) + I64.gt_u (I64.add (I64_convert.extend_i32_u i) (I64_convert.extend_i32_u n)) + (I64.of_int_u (String.length !(data frame.inst x))) let table_oob frame x i n = I64.gt_u (I64.add (I64_convert.extend_i32_u i) (I64_convert.extend_i32_u n)) (I64_convert.extend_i32_u (Table.size (table frame.inst x))) let elem_oob frame x i n = - match !(elem frame.inst x) with - | None -> false - | Some es -> - I64.gt_u (I64.add (I64_convert.extend_i32_u i) (I64_convert.extend_i32_u n)) - (I64.of_int_u (List.length es)) + I64.gt_u (I64.add (I64_convert.extend_i32_u i) (I64_convert.extend_i32_u n)) + (I64.of_int_u (List.length !(elem frame.inst x))) let rec step (c : config) : config = let {frame; code = vs, es; _} = c in @@ -220,42 +214,37 @@ let rec step (c : config) : config = with Global.NotMutable -> Crash.error e.at "write to immutable global" | Global.Type -> Crash.error e.at "type mismatch at global write") - | TableCopy, I32 0l :: I32 s :: I32 d :: vs' -> - vs', [] - | TableCopy, I32 n :: I32 s :: I32 d :: vs' when table_oob frame (0l @@ e.at) s n || table_oob frame (0l @@ e.at) d n -> vs', [Trapping (table_error e.at Table.Bounds) @@ e.at] + | TableCopy, I32 0l :: I32 s :: I32 d :: vs' -> + vs', [] + (* TODO: turn into small-step, but needs reference values *) | TableCopy, I32 n :: I32 s :: I32 d :: vs' -> let tab = table frame.inst (0l @@ e.at) in (try Table.copy tab d s n; vs', [] with exn -> vs', [Trapping (table_error e.at exn) @@ e.at]) - | TableInit x, I32 0l :: I32 s :: I32 d :: vs' -> - vs', [] - | TableInit x, I32 n :: I32 s :: I32 d :: vs' when table_oob frame (0l @@ e.at) d n || elem_oob frame x s n -> vs', [Trapping (table_error e.at Table.Bounds) @@ e.at] + | TableInit x, I32 0l :: I32 s :: I32 d :: vs' -> + vs', [] + (* TODO: turn into small-step, but needs reference values *) | TableInit x, I32 n :: I32 s :: I32 d :: vs' -> let tab = table frame.inst (0l @@ e.at) in - (match !(elem frame.inst x) with - | Some es -> - (try Table.init tab es d s n; vs', [] - with exn -> vs', [Trapping (table_error e.at exn) @@ e.at]) - | None -> vs', [Trapping "element segment dropped" @@ e.at] - ) + let seg = !(elem frame.inst x) in + (try Table.init tab seg d s n; vs', [] + with exn -> vs', [Trapping (table_error e.at exn) @@ e.at]) | ElemDrop x, vs -> let seg = elem frame.inst x in - (match !seg with - | Some _ -> seg := None; vs, [] - | None -> vs, [Trapping "element segment dropped" @@ e.at] - ) + seg := []; + vs, [] | Load {offset; ty; sz; _}, I32 i :: vs' -> let mem = memory frame.inst (0l @@ e.at) in @@ -291,13 +280,13 @@ let rec step (c : config) : config = with Memory.SizeOverflow | Memory.SizeLimit | Memory.OutOfMemory -> -1l in I32 result :: vs', [] - | MemoryFill, I32 0l :: v :: I32 i :: vs' -> - vs', [] - | MemoryFill, I32 n :: v :: I32 i :: vs' when mem_oob frame (0l @@ e.at) i n -> vs', [Trapping (memory_error e.at Memory.Bounds) @@ e.at] + | MemoryFill, I32 0l :: v :: I32 i :: vs' -> + vs', [] + | MemoryFill, I32 n :: v :: I32 i :: vs' -> vs', List.map (at e.at) [ Plain (Const (I32 i @@ e.at)); @@ -310,13 +299,13 @@ let rec step (c : config) : config = Plain (MemoryFill); ] - | MemoryCopy, I32 0l :: I32 s :: I32 d :: vs' -> - vs', [] - | MemoryCopy, I32 n :: I32 s :: I32 d :: vs' when mem_oob frame (0l @@ e.at) s n || mem_oob frame (0l @@ e.at) d n -> vs', [Trapping (memory_error e.at Memory.Bounds) @@ e.at] + | MemoryCopy, I32 0l :: I32 s :: I32 d :: vs' -> + vs', [] + | MemoryCopy, I32 n :: I32 s :: I32 d :: vs' when d <= s -> vs', List.map (at e.at) [ Plain (Const (I32 d @@ e.at)); @@ -345,37 +334,31 @@ let rec step (c : config) : config = {ty = I32Type; align = 0; offset = 0l; sz = Some Memory.Pack8}); ] - | MemoryInit x, I32 0l :: I32 s :: I32 d :: vs' -> - vs', [] - | MemoryInit x, I32 n :: I32 s :: I32 d :: vs' when mem_oob frame (0l @@ e.at) d n || data_oob frame x s n -> vs', [Trapping (memory_error e.at Memory.Bounds) @@ e.at] + | MemoryInit x, I32 0l :: I32 s :: I32 d :: vs' -> + vs', [] + | MemoryInit x, I32 n :: I32 s :: I32 d :: vs' -> - (match !(data frame.inst x) with - | None -> - vs', [Trapping "data segment dropped" @@ e.at] - | Some bs -> - let b = Int32.of_int (Char.code bs.[Int32.to_int s]) in - vs', List.map (at e.at) [ - Plain (Const (I32 d @@ e.at)); - Plain (Const (I32 b @@ e.at)); - Plain ( - Store {ty = I32Type; align = 0; offset = 0l; sz = Some Memory.Pack8}); - Plain (Const (I32 (I32.add d 1l) @@ e.at)); - Plain (Const (I32 (I32.add s 1l) @@ e.at)); - Plain (Const (I32 (I32.sub n 1l) @@ e.at)); - Plain (MemoryInit x); - ] - ) + let seg = !(data frame.inst x) in + let b = Int32.of_int (Char.code seg.[Int32.to_int s]) in + vs', List.map (at e.at) [ + Plain (Const (I32 d @@ e.at)); + Plain (Const (I32 b @@ e.at)); + Plain ( + Store {ty = I32Type; align = 0; offset = 0l; sz = Some Memory.Pack8}); + Plain (Const (I32 (I32.add d 1l) @@ e.at)); + Plain (Const (I32 (I32.add s 1l) @@ e.at)); + Plain (Const (I32 (I32.sub n 1l) @@ e.at)); + Plain (MemoryInit x); + ] | DataDrop x, vs -> let seg = data frame.inst x in - (match !seg with - | Some _ -> seg := None; vs, [] - | None -> vs, [Trapping "data segment dropped" @@ e.at] - ) + seg := ""; + vs, [] | Const v, vs -> v.it :: vs, [] @@ -536,11 +519,11 @@ let elem_list inst init = let create_elem (inst : module_inst) (seg : elem_segment) : elem_inst = let {etype; einit; _} = seg.it in - ref (Some (elem_list inst einit)) + ref (elem_list inst einit) let create_data (inst : module_inst) (seg : data_segment) : data_inst = let {dinit; _} = seg.it in - ref (Some dinit) + ref dinit let add_import (m : module_) (ext : extern) (im : import) (inst : module_inst) diff --git a/interpreter/runtime/instance.ml b/interpreter/runtime/instance.ml index de0e814189..a58859aca3 100644 --- a/interpreter/runtime/instance.ml +++ b/interpreter/runtime/instance.ml @@ -17,8 +17,8 @@ and table_inst = Table.t and memory_inst = Memory.t and global_inst = Global.t and export_inst = Ast.name * extern -and elem_inst = Table.elem list option ref -and data_inst = string option ref +and elem_inst = Table.elem list ref +and data_inst = string ref and extern = | ExternFunc of func_inst diff --git a/proposals/bulk-memory-operations/Overview.md b/proposals/bulk-memory-operations/Overview.md index 69fb55ffc1..a743504599 100644 --- a/proposals/bulk-memory-operations/Overview.md +++ b/proposals/bulk-memory-operations/Overview.md @@ -273,10 +273,9 @@ The instruction has the signature `[i32 i32 i32] -> []`. The parameters are, in It is a validation error to use `memory.init` with an out-of-bounds segment index. A trap occurs if: -* the segment is used after it has been dropped via `data.drop`. This includes - active segments that were dropped after being copied into memory during module - instantiation. -* any of the accessed bytes lies outside the source data segment or the target memory +* the source offset plus size is greater than the length of the source data segment; + this includes the case that the segment has been dropped via `data.drop` +* the destination offset plus size is greater than the length of the target memory Note that it is allowed to use `memory.init` on the same data segment more than once. @@ -337,7 +336,8 @@ The instruction has the signature `[i32 i32 i32] -> []`. The parameters are, in - top-0: size of memory region in bytes A trap occurs if: -* any of the accessed bytes lies outside the source or target memory +* the source offset plus size is greater than the length of the source memory +* the destination offset plus size is greater than the length of the target memory A trap resulting from an access outside the source or target region only occurs once the first byte that is outside the source or target @@ -360,7 +360,7 @@ The instruction has the signature `[i32 i32 i32] -> []`. The parameters are, in - top-0: size of memory region in bytes A trap occurs if: -* any of the accessed bytes lies outside the target memory +* the destination offset plus size is greater than the length of the target memory Filling takes place bytewise from lower addresses toward higher addresses. A trap resulting from an access outside the target memory diff --git a/test/core/bulk.wast b/test/core/bulk.wast index 9e26519e0c..fe71939d3b 100644 --- a/test/core/bulk.wast +++ b/test/core/bulk.wast @@ -48,8 +48,9 @@ ;; Succeed when writing 0 bytes at the end of the region. (invoke "fill" (i32.const 0x10000) (i32.const 0) (i32.const 0)) -;; OK to write 0 bytes outside of memory. -(invoke "fill" (i32.const 0x10001) (i32.const 0) (i32.const 0)) +;; Writing 0 bytes outside the memory traps. +(assert_trap (invoke "fill" (i32.const 0x10001) (i32.const 0) (i32.const 0)) + "out of bounds memory access") ;; memory.copy @@ -103,9 +104,11 @@ (invoke "copy" (i32.const 0x10000) (i32.const 0) (i32.const 0)) (invoke "copy" (i32.const 0) (i32.const 0x10000) (i32.const 0)) -;; OK to copy 0 bytes outside of memory. -(invoke "copy" (i32.const 0x10001) (i32.const 0) (i32.const 0)) -(invoke "copy" (i32.const 0) (i32.const 0x10001) (i32.const 0)) +;; Copying 0 bytes outside the memory traps. +(assert_trap (invoke "copy" (i32.const 0x10001) (i32.const 0) (i32.const 0)) + "out of bounds memory access") +(assert_trap (invoke "copy" (i32.const 0) (i32.const 0x10001) (i32.const 0)) + "out of bounds memory access") ;; memory.init @@ -141,9 +144,11 @@ (invoke "init" (i32.const 0x10000) (i32.const 0) (i32.const 0)) (invoke "init" (i32.const 0) (i32.const 4) (i32.const 0)) -;; OK to write 0 bytes outside of memory or segment. -(invoke "init" (i32.const 0x10001) (i32.const 0) (i32.const 0)) -(invoke "init" (i32.const 0) (i32.const 5) (i32.const 0)) +;; Writing 0 bytes outside the memory traps. +(assert_trap (invoke "init" (i32.const 0x10001) (i32.const 0) (i32.const 0)) + "out of bounds memory access") +(assert_trap (invoke "init" (i32.const 0) (i32.const 5) (i32.const 0)) + "out of bounds memory access") ;; data.drop (module @@ -162,12 +167,14 @@ (invoke "init_passive" (i32.const 1)) (invoke "drop_passive") -(assert_trap (invoke "drop_passive") "data segment dropped") +(invoke "drop_passive") (assert_return (invoke "init_passive" (i32.const 0))) -(assert_trap (invoke "init_passive" (i32.const 1)) "data segment dropped") -(assert_trap (invoke "drop_active") "data segment dropped") +(assert_trap (invoke "init_passive" (i32.const 1)) "out of bounds") +(invoke "init_passive" (i32.const 0)) +(invoke "drop_active") (assert_return (invoke "init_active" (i32.const 0))) -(assert_trap (invoke "init_active" (i32.const 1)) "data segment dropped") +(assert_trap (invoke "init_active" (i32.const 1)) "out of bounds") +(invoke "init_active" (i32.const 0)) ;; table.init @@ -208,9 +215,11 @@ (invoke "init" (i32.const 3) (i32.const 0) (i32.const 0)) (invoke "init" (i32.const 0) (i32.const 4) (i32.const 0)) -;; OK to storing 0 elements outside of table or segment. -(invoke "init" (i32.const 4) (i32.const 0) (i32.const 0)) -(invoke "init" (i32.const 0) (i32.const 5) (i32.const 0)) +;; Writing 0 elements outside the table traps. +(assert_trap (invoke "init" (i32.const 4) (i32.const 0) (i32.const 0)) + "out of bounds table access") +(assert_trap (invoke "init" (i32.const 0) (i32.const 5) (i32.const 0)) + "out of bounds table access") ;; elem.drop @@ -233,12 +242,14 @@ (invoke "init_passive" (i32.const 1)) (invoke "drop_passive") -(assert_trap (invoke "drop_passive") "element segment dropped") +(invoke "drop_passive") (assert_return (invoke "init_passive" (i32.const 0))) -(assert_trap (invoke "init_passive" (i32.const 1)) "element segment dropped") -(assert_trap (invoke "drop_active") "element segment dropped") +(assert_trap (invoke "init_passive" (i32.const 1)) "out of bounds") +(invoke "init_passive" (i32.const 0)) +(invoke "drop_active") (assert_return (invoke "init_active" (i32.const 0))) -(assert_trap (invoke "init_active" (i32.const 1)) "element segment dropped") +(assert_trap (invoke "init_active" (i32.const 1)) "out of bounds") +(invoke "init_active" (i32.const 0)) ;; table.copy @@ -290,5 +301,7 @@ (invoke "copy" (i32.const 0) (i32.const 10) (i32.const 0)) ;; Fail on out-of-bounds when copying 0 elements outside of table. -(invoke "copy" (i32.const 11) (i32.const 0) (i32.const 0)) -(invoke "copy" (i32.const 0) (i32.const 11) (i32.const 0)) +(assert_trap (invoke "copy" (i32.const 11) (i32.const 0) (i32.const 0)) + "out of bounds") +(assert_trap (invoke "copy" (i32.const 0) (i32.const 11) (i32.const 0)) + "out of bounds") diff --git a/test/core/data.wast b/test/core/data.wast index a343fdc5eb..aabe1021b2 100644 --- a/test/core/data.wast +++ b/test/core/data.wast @@ -193,16 +193,19 @@ ) "out of bounds" ) - -;; Writing 0 bytes outside of bounds is allowed now. -(module - (memory 0) - (data (i32.const 1)) +(assert_trap + (module + (memory 0) + (data (i32.const 1)) + ) + "out of bounds" ) - -(module - (memory 0 1) - (data (i32.const 1)) +(assert_trap + (module + (memory 0 1) + (data (i32.const 1)) + ) + "out of bounds" ) ;; This seems to cause a time-out on Travis. diff --git a/test/core/elem.wast b/test/core/elem.wast index 90647a4a2f..bb622ee662 100644 --- a/test/core/elem.wast +++ b/test/core/elem.wast @@ -219,12 +219,13 @@ "out of bounds" ) -;; Writing 0 elems outside of bounds is allowed now. -(module - (table 0 funcref) - (elem (i32.const 1)) +(assert_trap + (module + (table 0 funcref) + (elem (i32.const 1)) + ) + "out of bounds" ) - (assert_trap (module (table 10 funcref) diff --git a/test/core/memory_copy.wast b/test/core/memory_copy.wast index cb46144d35..692e1ad85f 100644 --- a/test/core/memory_copy.wast +++ b/test/core/memory_copy.wast @@ -4869,7 +4869,7 @@ (memory 1 1) (func (export "test") (memory.copy (i32.const 0x20000) (i32.const 0x7000) (i32.const 0)))) -(invoke "test") +(assert_trap (invoke "test") "out of bounds") (module (memory 1 1) @@ -4881,7 +4881,7 @@ (memory 1 1) (func (export "test") (memory.copy (i32.const 0x9000) (i32.const 0x20000) (i32.const 0)))) -(invoke "test") +(assert_trap (invoke "test") "out of bounds") (module (memory 1 1) @@ -4889,6 +4889,12 @@ (memory.copy (i32.const 0x10000) (i32.const 0x10000) (i32.const 0)))) (invoke "test") +(module + (memory 1 1) + (func (export "test") + (memory.copy (i32.const 0x20000) (i32.const 0x20000) (i32.const 0)))) +(assert_trap (invoke "test") "out of bounds") + (module (memory 1 1) (func (export "test") diff --git a/test/core/memory_fill.wast b/test/core/memory_fill.wast index bbce9d8e3e..caca80b5da 100644 --- a/test/core/memory_fill.wast +++ b/test/core/memory_fill.wast @@ -114,7 +114,7 @@ (func (export "test") (memory.fill (i32.const 0x20000) (i32.const 0x55) (i32.const 0)))) -(invoke "test") +(assert_trap (invoke "test") "out of bounds") (module (memory 1 1) diff --git a/test/core/memory_init.wast b/test/core/memory_init.wast index 670bddc28d..c647079d91 100644 --- a/test/core/memory_init.wast +++ b/test/core/memory_init.wast @@ -205,7 +205,7 @@ (func (export "test") (data.drop 0) (data.drop 0))) -(assert_trap (invoke "test") "data segment dropped") +(invoke "test") (module (memory 1) @@ -213,14 +213,14 @@ (func (export "test") (data.drop 0) (memory.init 0 (i32.const 1234) (i32.const 1) (i32.const 1)))) -(assert_trap (invoke "test") "data segment dropped") +(assert_trap (invoke "test") "out of bounds") (module (memory 1) (data (i32.const 0) "\37") (func (export "test") (memory.init 0 (i32.const 1234) (i32.const 1) (i32.const 1)))) -(assert_trap (invoke "test") "data segment dropped") +(assert_trap (invoke "test") "out of bounds") (assert_invalid (module @@ -270,7 +270,7 @@ (data "\37") (func (export "test") (memory.init 0 (i32.const 1234) (i32.const 4) (i32.const 0)))) -(invoke "test") +(assert_trap (invoke "test") "out of bounds") (module (memory 1) @@ -284,7 +284,7 @@ (data "\37") (func (export "test") (memory.init 0 (i32.const 0x10001) (i32.const 0) (i32.const 0)))) -(invoke "test") +(assert_trap (invoke "test") "out of bounds") (module (memory 1) @@ -300,6 +300,13 @@ (memory.init 0 (i32.const 0x10000) (i32.const 1) (i32.const 0)))) (invoke "test") +(module + (memory 1) + (data "\37") + (func (export "test") + (memory.init 0 (i32.const 0x10001) (i32.const 4) (i32.const 0)))) +(assert_trap (invoke "test") "out of bounds") + (assert_invalid (module (memory 1) diff --git a/test/core/table_copy.wast b/test/core/table_copy.wast index 20949b3061..d0aa77b205 100644 --- a/test/core/table_copy.wast +++ b/test/core/table_copy.wast @@ -633,7 +633,7 @@ (table.copy (i32.const 31) (i32.const 15) (i32.const 0)) )) -(invoke "test") +(assert_trap (invoke "test") "out of bounds") (module (table 30 30 funcref) @@ -681,7 +681,7 @@ (table.copy (i32.const 15) (i32.const 31) (i32.const 0)) )) -(invoke "test") +(assert_trap (invoke "test") "out of bounds") (module (table 30 30 funcref) @@ -707,6 +707,30 @@ (invoke "test") +(module + (table 30 30 funcref) + (elem (i32.const 2) 3 1 4 1) + (elem funcref + (ref.func 2) (ref.func 7) (ref.func 1) (ref.func 8)) + (elem (i32.const 12) 7 5 2 3 6) + (elem funcref + (ref.func 5) (ref.func 9) (ref.func 2) (ref.func 7) (ref.func 6)) + (func (result i32) (i32.const 0)) + (func (result i32) (i32.const 1)) + (func (result i32) (i32.const 2)) + (func (result i32) (i32.const 3)) + (func (result i32) (i32.const 4)) + (func (result i32) (i32.const 5)) + (func (result i32) (i32.const 6)) + (func (result i32) (i32.const 7)) + (func (result i32) (i32.const 8)) + (func (result i32) (i32.const 9)) + (func (export "test") + (table.copy (i32.const 31) (i32.const 31) (i32.const 0)) + )) + +(assert_trap (invoke "test") "out of bounds") + (module (type (func (result i32))) (table 32 64 funcref) diff --git a/test/core/table_init.wast b/test/core/table_init.wast index 658deb68f6..80eaf065d8 100644 --- a/test/core/table_init.wast +++ b/test/core/table_init.wast @@ -239,7 +239,7 @@ (func (export "test") (elem.drop 2) )) -(assert_trap (invoke "test") "element segment dropped") +(invoke "test") (module (table 30 30 funcref) @@ -262,7 +262,7 @@ (func (export "test") (table.init 2 (i32.const 12) (i32.const 1) (i32.const 1)) )) -(assert_trap (invoke "test") "element segment dropped") +(assert_trap (invoke "test") "out of bounds") (module (table 30 30 funcref) @@ -308,7 +308,7 @@ (func (export "test") (elem.drop 1) (elem.drop 1))) -(assert_trap (invoke "test") "element segment dropped") +(invoke "test") (module (table 30 30 funcref) @@ -331,7 +331,7 @@ (func (export "test") (elem.drop 1) (table.init 1 (i32.const 12) (i32.const 1) (i32.const 1)))) -(assert_trap (invoke "test") "element segment dropped") +(assert_trap (invoke "test") "out of bounds") (module (table 30 30 funcref) @@ -446,7 +446,7 @@ (func (export "test") (table.init 1 (i32.const 12) (i32.const 5) (i32.const 0)) )) -(invoke "test") +(assert_trap (invoke "test") "out of bounds") (module (table 30 30 funcref) @@ -492,7 +492,7 @@ (func (export "test") (table.init 1 (i32.const 31) (i32.const 2) (i32.const 0)) )) -(invoke "test") +(assert_trap (invoke "test") "out of bounds") (module (table 30 30 funcref) @@ -517,6 +517,29 @@ )) (invoke "test") +(module + (table 30 30 funcref) + (elem (i32.const 2) 3 1 4 1) + (elem funcref + (ref.func 2) (ref.func 7) (ref.func 1) (ref.func 8)) + (elem (i32.const 12) 7 5 2 3 6) + (elem funcref + (ref.func 5) (ref.func 9) (ref.func 2) (ref.func 7) (ref.func 6)) + (func (result i32) (i32.const 0)) + (func (result i32) (i32.const 1)) + (func (result i32) (i32.const 2)) + (func (result i32) (i32.const 3)) + (func (result i32) (i32.const 4)) + (func (result i32) (i32.const 5)) + (func (result i32) (i32.const 6)) + (func (result i32) (i32.const 7)) + (func (result i32) (i32.const 8)) + (func (result i32) (i32.const 9)) + (func (export "test") + (table.init 1 (i32.const 31) (i32.const 5) (i32.const 0)) + )) +(assert_trap (invoke "test") "out of bounds") + (assert_invalid (module (table 10 funcref) diff --git a/test/meta/generate_memory_copy.js b/test/meta/generate_memory_copy.js index 687ce6c7c8..e5b7c0c997 100644 --- a/test/meta/generate_memory_copy.js +++ b/test/meta/generate_memory_copy.js @@ -280,13 +280,13 @@ print( (invoke "test") `); -// Zero len with dest offset out-of-bounds past the end of memory is allowed +// Zero len with dest offset out-of-bounds past the end of memory is not allowed print( `(module (memory 1 1) (func (export "test") (memory.copy (i32.const 0x20000) (i32.const 0x7000) (i32.const 0)))) -(invoke "test") +(assert_trap (invoke "test") "out of bounds") `); // Zero len with src offset out-of-bounds at the end of memory is allowed @@ -298,13 +298,13 @@ print( (invoke "test") `); -// Zero len with src offset out-of-bounds past the end of memory is allowed +// Zero len with src offset out-of-bounds past the end of memory is not allowed print( `(module (memory 1 1) (func (export "test") (memory.copy (i32.const 0x9000) (i32.const 0x20000) (i32.const 0)))) -(invoke "test") +(assert_trap (invoke "test") "out of bounds") `); // Zero len with both dest and src offsets out-of-bounds at the end of memory is allowed @@ -316,6 +316,15 @@ print( (invoke "test") `); +// Zero len with both dest and src offsets out-of-bounds past the end of memory is not allowed +print( +`(module + (memory 1 1) + (func (export "test") + (memory.copy (i32.const 0x20000) (i32.const 0x20000) (i32.const 0)))) +(assert_trap (invoke "test") "out of bounds") +`); + // 100 random fills followed by 100 random copies, in a single-page buffer, // followed by verification of the (now heavily mashed-around) buffer. print( diff --git a/test/meta/generate_memory_fill.js b/test/meta/generate_memory_fill.js index cb048f6a11..0dba569e9b 100644 --- a/test/meta/generate_memory_fill.js +++ b/test/meta/generate_memory_fill.js @@ -56,13 +56,13 @@ print( (invoke "test") `); -// Zero len with offset out-of-bounds past the end of memory is allowed +// Zero len with offset out-of-bounds past the end of memory is not allowed print( `(module ${PREAMBLE} (func (export "test") (memory.fill (i32.const 0x20000) (i32.const 0x55) (i32.const 0)))) -(invoke "test") +(assert_trap (invoke "test") "out of bounds") `); // Very large range @@ -136,7 +136,7 @@ function mem_fill(min, max, shared, backup, write=backup*2) { (func (export "run") (param $offs i32) (param $val i32) (param $len i32) (memory.fill (local.get $offs) (local.get $val) (local.get $len)))) `); - // A fill past the end should throw *and* have filled all the way up to the end + // A fill past the end should throw *and* not have performed a partial fill let offs = min*PAGESIZE - backup; let val = 37; print( diff --git a/test/meta/generate_memory_init.js b/test/meta/generate_memory_init.js index eccbabfecc..0b5d7f6505 100644 --- a/test/meta/generate_memory_init.js +++ b/test/meta/generate_memory_init.js @@ -85,7 +85,7 @@ print( (func (export "test") (data.drop 0) (data.drop 0))) -(assert_trap (invoke "test") "data segment dropped") +(invoke "test") `); // drop, then init @@ -95,7 +95,7 @@ print( (func (export "test") (data.drop 0) (memory.init 0 (i32.const 1234) (i32.const 1) (i32.const 1)))) -(assert_trap (invoke "test") "data segment dropped") +(assert_trap (invoke "test") "out of bounds") `); // init with data seg ix indicating an active segment @@ -105,7 +105,7 @@ print( (data (i32.const 0) "\\37") (func (export "test") (memory.init 0 (i32.const 1234) (i32.const 1) (i32.const 1)))) -(assert_trap (invoke "test") "data segment dropped") +(assert_trap (invoke "test") "out of bounds") `); // init with no memory @@ -164,13 +164,13 @@ print( (assert_trap (invoke "test") "out of bounds") `); -// init: seg ix is valid passive, src offset past the end, zero len is always valid +// init: seg ix is valid passive, src offset past the end, zero len is invalid print( `(module ${PREAMBLE} (func (export "test") (memory.init 0 (i32.const 1234) (i32.const 4) (i32.const 0)))) -(invoke "test") +(assert_trap (invoke "test") "out of bounds") `); // init: seg ix is valid passive, zero len, src offset at the end @@ -182,13 +182,13 @@ print( (invoke "test") `); -// init: seg ix is valid passive, dst offset past the end, zero len is always valid +// init: seg ix is valid passive, dst offset past the end, zero len is invalid print( `(module ${PREAMBLE} (func (export "test") (memory.init 0 (i32.const 0x10001) (i32.const 0) (i32.const 0)))) -(invoke "test") +(assert_trap (invoke "test") "out of bounds") `); // init: seg ix is valid passive, zero len, but dst offset at the end @@ -209,6 +209,16 @@ print( (invoke "test") `); +// init: seg ix is valid passive, src and dst offset past the end, zero len is +// invalid +print( +`(module + ${PREAMBLE} + (func (export "test") + (memory.init 0 (i32.const 0x10001) (i32.const 4) (i32.const 0)))) +(assert_trap (invoke "test") "out of bounds") +`); + // invalid argument types. TODO: can add anyfunc etc here. { const tys = ['i32', 'f32', 'i64', 'f64']; diff --git a/test/meta/generate_table_copy.js b/test/meta/generate_table_copy.js index d399fdc42a..867189445e 100644 --- a/test/meta/generate_table_copy.js +++ b/test/meta/generate_table_copy.js @@ -189,26 +189,31 @@ tab_test2("(table.copy (i32.const 30) (i32.const 15) (i32.const 0))", "", undefined); -// copy: zero length with dst offset out of bounds past the end of the table is allowed +// copy: zero length with dst offset out of bounds past the end of the table is not allowed tab_test2("(table.copy (i32.const 31) (i32.const 15) (i32.const 0))", "", - undefined); + "out of bounds"); // copy: zero length with src offset out of bounds at the end of the table is allowed tab_test2("(table.copy (i32.const 15) (i32.const 30) (i32.const 0))", "", undefined); -// copy: zero length with src offset out of bounds past the end of the table is allowed +// copy: zero length with src offset out of bounds past the end of the table is not allowed tab_test2("(table.copy (i32.const 15) (i32.const 31) (i32.const 0))", "", - undefined); + "out of bounds"); // copy: zero length with both dst and src offset out of bounds at the end of the table is allowed tab_test2("(table.copy (i32.const 30) (i32.const 30) (i32.const 0))", "", undefined); +// copy: zero length with both dst and src offset out of bounds past the end of the table is not allowed +tab_test2("(table.copy (i32.const 31) (i32.const 31) (i32.const 0))", + "", + "out of bounds"); + // table.copy: out of bounds of the table for the source or target, but should // perform the operation up to the appropriate bound. Major cases: // diff --git a/test/meta/generate_table_init.js b/test/meta/generate_table_init.js index bc59409035..9329d937d7 100644 --- a/test/meta/generate_table_init.js +++ b/test/meta/generate_table_init.js @@ -181,32 +181,29 @@ function tab_test2(insn1, insn2, errText) { do_test(insn1, insn2, errText); } -function tab_test_nofail(insn1, insn2) { - do_test(insn1, insn2, undefined); -} - // drop with elem seg ix indicating an active segment tab_test1("(elem.drop 2)", - "element segment dropped"); + undefined); // init with elem seg ix indicating an active segment tab_test1("(table.init 2 (i32.const 12) (i32.const 1) (i32.const 1))", - "element segment dropped"); + "out of bounds"); // init, using an elem seg ix more than once is OK -tab_test_nofail( +tab_test2( "(table.init 1 (i32.const 12) (i32.const 1) (i32.const 1))", - "(table.init 1 (i32.const 21) (i32.const 1) (i32.const 1))"); + "(table.init 1 (i32.const 21) (i32.const 1) (i32.const 1))", + undefined); // drop, then drop tab_test2("(elem.drop 1)", "(elem.drop 1)", - "element segment dropped"); + undefined); // drop, then init tab_test2("(elem.drop 1)", "(table.init 1 (i32.const 12) (i32.const 1) (i32.const 1))", - "element segment dropped"); + "out of bounds"); // init: seg ix is valid passive, but length to copy > len of seg tab_test1("(table.init 1 (i32.const 12) (i32.const 0) (i32.const 5))", @@ -226,9 +223,9 @@ tab_test1("(table.init 1 (i32.const 12) (i32.const 4) (i32.const 0))", undefined); // init: seg ix is valid passive, zero len, and src offset out of bounds past the -// end of the table - this is allowed +// end of the table - this is not allowed tab_test1("(table.init 1 (i32.const 12) (i32.const 5) (i32.const 0))", - undefined); + "out of bounds"); // init: seg ix is valid passive, zero len, and dst offset out of bounds at the // end of the table - this is allowed @@ -236,15 +233,20 @@ tab_test1("(table.init 1 (i32.const 30) (i32.const 2) (i32.const 0))", undefined); // init: seg ix is valid passive, zero len, and dst offset out of bounds past the -// end of the table - this is allowed +// end of the table - this is not allowed tab_test1("(table.init 1 (i32.const 31) (i32.const 2) (i32.const 0))", - undefined); + "out of bounds"); // init: seg ix is valid passive, zero len, and dst and src offsets out of bounds // at the end of the table - this is allowed tab_test1("(table.init 1 (i32.const 30) (i32.const 4) (i32.const 0))", undefined); +// init: seg ix is valid passive, zero len, and src/dst offset out of bounds past the +// end of the table - this is not allowed +tab_test1("(table.init 1 (i32.const 31) (i32.const 5) (i32.const 0))", + "out of bounds"); + // invalid argument types { const tys = ['i32', 'f32', 'i64', 'f64']; From 1e296604ae7c2aa2ce7619929a8817c9fd95941d Mon Sep 17 00:00:00 2001 From: Andreas Rossberg Date: Sat, 23 Nov 2019 10:16:56 +0100 Subject: [PATCH 134/199] [spec] Adapt OOB behaviour in spec; store typing (#129) * [interpreter] Simplify zero-len and drop semantics * Update overview * [spec] Change drop semantics * [spec] Forgot to adjust prose for *.init ops * [spec] Adapt to early OOB checks * [spec] Fix OOB for table rules * [spec] Spec memory OOB * [spec] Extend store typing to elem and data instances * Apply suggestions from code review Co-Authored-By: Ryan Hunt * Comments * [spec] Fix uses of table.set --- document/core/appendix/index-rules.rst | 4 + document/core/appendix/properties.rst | 115 +++++- document/core/exec/instructions.rst | 498 ++++++++++++------------- document/core/exec/modules.rst | 20 +- document/core/exec/runtime.rst | 21 +- document/core/util/macros.def | 13 +- 6 files changed, 376 insertions(+), 295 deletions(-) diff --git a/document/core/appendix/index-rules.rst b/document/core/appendix/index-rules.rst index 0e98a7866d..647ad42620 100644 --- a/document/core/appendix/index-rules.rst +++ b/document/core/appendix/index-rules.rst @@ -54,6 +54,8 @@ Construct Judgement :ref:`Table instance ` :math:`S \vdashtableinst \tableinst : \tabletype` :ref:`Memory instance ` :math:`S \vdashmeminst \meminst : \memtype` :ref:`Global instance ` :math:`S \vdashglobalinst \globalinst : \globaltype` +:ref:`Element instance ` :math:`S \vdasheleminst \eleminst \ok` +:ref:`Data instance ` :math:`S \vdashdatainst \datainst \ok` :ref:`Export instance ` :math:`S \vdashexportinst \exportinst \ok` :ref:`Module instance ` :math:`S \vdashmoduleinst \moduleinst : C` :ref:`Store ` :math:`\vdashstore \store \ok` @@ -95,6 +97,8 @@ Construct Judgement :ref:`Table instance ` :math:`\vdashtableinstextends \tableinst_1 \extendsto \tableinst_2` :ref:`Memory instance ` :math:`\vdashmeminstextends \meminst_1 \extendsto \meminst_2` :ref:`Global instance ` :math:`\vdashglobalinstextends \globalinst_1 \extendsto \globalinst_2` +:ref:`Element instance ` :math:`\vdasheleminstextends \eleminst_1 \extendsto \eleminst_2` +:ref:`Data instance ` :math:`\vdashdatainstextends \datainst_1 \extendsto \datainst_2` :ref:`Store ` :math:`\vdashstoreextends \store_1 \extendsto \store_2` =============================================== =============================================================================== diff --git a/document/core/appendix/properties.rst b/document/core/appendix/properties.rst index e1f5d8c002..83437f8bd8 100644 --- a/document/core/appendix/properties.rst +++ b/document/core/appendix/properties.rst @@ -100,6 +100,10 @@ Module instances are classified by *module contexts*, which are regular :ref:`co * Each :ref:`global instance ` :math:`\globalinst_i` in :math:`S.\SGLOBALS` must be :ref:`valid ` with some :ref:`global type ` :math:`\globaltype_i`. +* Each :ref:`element instance ` :math:`\eleminst_i` in :math:`S.\SELEMS` must be :ref:`valid `. + +* Each :ref:`data instance ` :math:`\datainst_i` in :math:`S.\SDATAS` must be :ref:`valid `. + * Then the store is valid. .. math:: @@ -114,11 +118,17 @@ Module instances are classified by *module contexts*, which are regular :ref:`co \qquad (S \vdashglobalinst \globalinst : \globaltype)^\ast \\ + (S \vdasheleminst \eleminst \ok)^\ast + \qquad + (S \vdashdatainst \datainst \ok)^\ast + \\ S = \{ \SFUNCS~\funcinst^\ast, \STABLES~\tableinst^\ast, \SMEMS~\meminst^\ast, - \SGLOBALS~\globalinst^\ast \} + \SGLOBALS~\globalinst^\ast, + \SELEMS~\eleminst^\ast, + \SDATAS~\datainst^\ast \} \end{array} }{ \vdashstore S \ok @@ -224,7 +234,7 @@ Module instances are classified by *module contexts*, which are regular :ref:`co .. math:: \frac{ - ((S \vdash \EVFUNC~\X{fa} : \ETFUNC~\functype)^?)^n + ((S \vdashexternval \EVFUNC~\X{fa} : \ETFUNC~\functype)^?)^n \qquad \vdashlimits \{\LMIN~n, \LMAX~m^?\} : 2^{32} }{ @@ -265,6 +275,41 @@ Module instances are classified by *module contexts*, which are regular :ref:`co } +.. index:: element instance, reference +.. _valid-eleminst: + +:ref:`Element Instances ` :math:`\{ \EIELEM~\X{fa}^\ast \}` +............................................................................ + +* For each :ref:`function address ` :math:`\X{fa}_i` in the table elements :math:`\X{fa}^\ast`: + + * The :ref:`external value ` :math:`\EVFUNC~\X{fa}` must be :ref:`valid ` with some :ref:`external type ` :math:`\ETFUNC~\X{ft}`. + +* Then the element instance is valid. + +.. math:: + \frac{ + (S \vdashexternval \EVFUNC~\X{fa} : \ETFUNC~\functype)^\ast + }{ + S \vdasheleminst \{ \EIELEM~\X{fa}^\ast \} \ok + } + + +.. index:: data instance, byte +.. _valid-datainst: + +:ref:`Data Instances ` :math:`\{ \DIDATA~b^\ast \}` +.................................................................... + +* The data instance is valid. + +.. math:: + \frac{ + }{ + S \vdashdatainst \{ \DIDATA~b^\ast \} \ok + } + + .. index:: external type, export instance, name, external value .. _valid-exportinst: @@ -299,6 +344,10 @@ Module instances are classified by *module contexts*, which are regular :ref:`co * For each :ref:`global address ` :math:`\globaladdr_i` in :math:`\moduleinst.\MIGLOBALS`, the :ref:`external value ` :math:`\EVGLOBAL~\globaladdr_i` must be :ref:`valid ` with some :ref:`external type ` :math:`\ETGLOBAL~\globaltype_i`. +* For each :ref:`element address ` :math:`\elemaddr_i` in :math:`\moduleinst.\MIELEMS`, the :ref:`element instance ` :math:`S.\SELEMS[\elemaddr_i]` must be :ref:`valid `. + +* For each :ref:`data address ` :math:`\dataaddr_i` in :math:`\moduleinst.\MIDATAS`, the :ref:`data instance ` :math:`S.\SDATAS[\dataaddr_i]` must be :ref:`valid `. + * Each :ref:`export instance ` :math:`\exportinst_i` in :math:`\moduleinst.\MIEXPORTS` must be :ref:`valid `. * For each :ref:`export instance ` :math:`\exportinst_i` in :math:`\moduleinst.\MIEXPORTS`, the :ref:`name ` :math:`\exportinst_i.\EINAME` must be different from any other name occurring in :math:`\moduleinst.\MIEXPORTS`. @@ -327,6 +376,10 @@ Module instances are classified by *module contexts*, which are regular :ref:`co \qquad (S \vdashexternval \EVGLOBAL~\globaladdr : \ETGLOBAL~\globaltype)^\ast \\ + (S \vdasheleminst S.\SELEMS[\elemaddr] \ok)^\ast + \qquad + (S \vdashdatainst S.\SDATAS[\dataaddr] \ok)^\ast + \\ (S \vdashexportinst \exportinst \ok)^\ast \qquad (\exportinst.\EINAME)^\ast ~\mbox{disjoint} @@ -338,7 +391,9 @@ Module instances are classified by *module contexts*, which are regular :ref:`co \MIFUNCS & \funcaddr^\ast, \\ \MITABLES & \tableaddr^\ast, \\ \MIMEMS & \memaddr^\ast, \\ - \MIGLOBALS & \globaladdr^\ast \\ + \MIGLOBALS & \globaladdr^\ast, \\ + \MIELEMS & \elemaddr^\ast, \\ + \MIDATAS & \dataaddr^\ast, \\ \MIEXPORTS & \exportinst^\ast ~\} : \{ \begin{array}[t]{@{}l@{~}l@{}} \CTYPES & \functype^\ast, \\ @@ -560,6 +615,10 @@ a store state :math:`S'` extends state :math:`S`, written :math:`S \extendsto S' * The length of :math:`S.\SGLOBALS` must not shrink. +* The length of :math:`S.\SELEMS` must not shrink. + +* The length of :math:`S.\SDATAS` must not shrink. + * For each :ref:`function instance ` :math:`\funcinst_i` in the original :math:`S.\SFUNCS`, the new function instance must be an :ref:`extension ` of the old. * For each :ref:`table instance ` :math:`\tableinst_i` in the original :math:`S.\STABLES`, the new table instance must be an :ref:`extension ` of the old. @@ -568,21 +627,31 @@ a store state :math:`S'` extends state :math:`S`, written :math:`S \extendsto S' * For each :ref:`global instance ` :math:`\globalinst_i` in the original :math:`S.\SGLOBALS`, the new global instance must be an :ref:`extension ` of the old. +* For each :ref:`element instance ` :math:`\eleminst_i` in the original :math:`S.\SELEMS`, the new global instance must be an :ref:`extension ` of the old. + +* For each :ref:`data instance ` :math:`\datainst_i` in the original :math:`S.\SDATAS`, the new global instance must be an :ref:`extension ` of the old. + .. math:: \frac{ \begin{array}{@{}ccc@{}} S_1.\SFUNCS = \funcinst_1^\ast & S_2.\SFUNCS = {\funcinst'_1}^\ast~\funcinst_2^\ast & - (\funcinst_1 \extendsto \funcinst'_1)^\ast \\ + (\vdashfuncinstextends \funcinst_1 \extendsto \funcinst'_1)^\ast \\ S_1.\STABLES = \tableinst_1^\ast & S_2.\STABLES = {\tableinst'_1}^\ast~\tableinst_2^\ast & - (\tableinst_1 \extendsto \tableinst'_1)^\ast \\ + (\vdashtableinstextends \tableinst_1 \extendsto \tableinst'_1)^\ast \\ S_1.\SMEMS = \meminst_1^\ast & S_2.\SMEMS = {\meminst'_1}^\ast~\meminst_2^\ast & - (\meminst_1 \extendsto \meminst'_1)^\ast \\ + (\vdashmeminstextends \meminst_1 \extendsto \meminst'_1)^\ast \\ S_1.\SGLOBALS = \globalinst_1^\ast & S_2.\SGLOBALS = {\globalinst'_1}^\ast~\globalinst_2^\ast & - (\globalinst_1 \extendsto \globalinst'_1)^\ast \\ + (\vdashglobalinstextends \globalinst_1 \extendsto \globalinst'_1)^\ast \\ + S_1.\SELEMS = \eleminst_1^\ast & + S_2.\SELEMS = {\eleminst'_1}^\ast~\eleminst_2^\ast & + (\vdasheleminstextends \eleminst_1 \extendsto \eleminst'_1)^\ast \\ + S_1.\SDATAS = \datainst_1^\ast & + S_2.\SDATAS = {\datainst'_1}^\ast~\datainst_2^\ast & + (\vdashdatainstextends \datainst_1 \extendsto \datainst'_1)^\ast \\ \end{array} }{ \vdashstoreextends S_1 \extendsto S_2 @@ -660,6 +729,38 @@ a store state :math:`S'` extends state :math:`S`, written :math:`S \extendsto S' } +.. index:: element instance +.. _extend-eleminst: + +:ref:`Element Instance ` :math:`\eleminst` +........................................................... + +* The vector :math:`\eleminst.\EIELEM` must either remain unchanged or shrink to length :math:`0`. + +.. math:: + \frac{ + \X{fa}_1^\ast = \X{fa}_2^\ast \vee \X{fa}_2^\ast = \epsilon + }{ + \vdasheleminstextends \{\EIELEM~\X{fa}_1^\ast\} \extendsto \{\EIELEM~\X{fa}_2^\ast\} + } + + +.. index:: data instance +.. _extend-datainst: + +:ref:`Data Instance ` :math:`\datainst` +........................................................ + +* The vector :math:`\datainst.\DIDATA` must either remain unchanged or shrink to length :math:`0`. + +.. math:: + \frac{ + b_1^\ast = b_2^\ast \vee b_2^\ast = \epsilon + }{ + \vdashdatainstextends \{\DIDATA~b_1^\ast\} \extendsto \{\DIDATA~b_2^\ast\} + } + + .. index:: ! preservation, ! progress, soundness, configuration, thread, terminal configuration, instantiation, invocation, validity, module .. _soundness-statement: diff --git a/document/core/exec/instructions.rst b/document/core/exec/instructions.rst index eecf0f8d41..590d8ff66c 100644 --- a/document/core/exec/instructions.rst +++ b/document/core/exec/instructions.rst @@ -635,11 +635,11 @@ Memory Instructions 2. Assert: due to :ref:`validation `, :math:`F.\AMODULE.\MIMEMS[0]` exists. -3. Let :math:`a` be the :ref:`memory address ` :math:`F.\AMODULE.\MIMEMS[0]`. +3. Let :math:`\X{ma}` be the :ref:`memory address ` :math:`F.\AMODULE.\MIMEMS[0]`. -4. Assert: due to :ref:`validation `, :math:`S.\SMEMS[a]` exists. +4. Assert: due to :ref:`validation `, :math:`S.\SMEMS[\X{ma}]` exists. -5. Let :math:`\X{mem}` be the :ref:`memory instance ` :math:`S.\SMEMS[a]`. +5. Let :math:`\X{mem}` be the :ref:`memory instance ` :math:`S.\SMEMS[\X{ma}]`. 6. Assert: due to :ref:`validation `, a value of :ref:`value type ` |I32| is on the top of the stack. @@ -651,31 +651,25 @@ Memory Instructions 10. Assert: due to :ref:`validation `, a value of :ref:`value type ` |I32| is on the top of the stack. -11. Pop the value :math:`\I32.\CONST~i` from the stack. +11. Pop the value :math:`\I32.\CONST~d` from the stack. -12. If :math:`n = 0`, then: +12. If :math:`d + n` is larger than the length of :math:`\X{mem}.\MIDATA`, then: - a. Return. - -13. If :math:`n = 1`, then: - - a. Push the value :math:`\I32.\CONST~i` to the stack. - - b. Push the value :math:`\val` to the stack. + a. Trap. - c. Execute the instruction :math:`\I32\K{.}\STORE\K{8}~\{ \OFFSET~0, \ALIGN~0 \}`. +13. If :math:`n = 0`, then: - d. Return. + a. Return. -14. Push the value :math:`\I32.\CONST~i` to the stack. +14. Push the value :math:`\I32.\CONST~d` to the stack. 15. Push the value :math:`\val` to the stack. -16. Push the value :math:`\I32.\CONST~1` to the stack. +16. Execute the instruction :math:`\I32\K{.}\STORE\K{8}~\{ \OFFSET~0, \ALIGN~0 \}`. -17. Execute the instruction :math:`\MEMORYFILL`. +17. Assert: due to the earlier check against the memory size, :math:`d+1 < 2^{32}`. -18. Push the value :math:`\vconst_{\I32}(i+1)` to the stack. +18. Push the value :math:`\I32.\CONST~(d+1)` to the stack. 19. Push the value :math:`\val` to the stack. @@ -684,28 +678,28 @@ Memory Instructions 21. Execute the instruction :math:`\MEMORYFILL`. .. math:: + ~\\[-1ex] \begin{array}{l} - \begin{array}{lcl@{\qquad}l} - S; F; (\I32.\CONST~i)~\val~(\I32.\CONST~0)~(\MEMORYFILL) &\stepto& S; F; \epsilon - \end{array} \\ - \begin{array}{lcl@{\qquad}l} - S; F; (\I32.\CONST~i)~\val~(\I32.\CONST~1)~(\MEMORYFILL) &\stepto& S; F; - (\I32.\CONST~i)~\val~(\I32\K{.}\STORE\K{8}~\{ \OFFSET~0, \ALIGN~0 \}) \\ - \end{array} \\ - \begin{array}{lcl@{\qquad}l} - S; F; (\I32.\CONST~i)~\val~(\I32.\CONST~n)~(\MEMORYFILL) &\stepto& S; F; - \begin{array}[t]{@{}l@{}} - (\I32.\CONST~i)~\val~(\I32.\CONST~1)~(\MEMORYFILL) \\ - (\vconst_{\I32}(i+1))~\val~(\I32.\CONST~(n-1))~(\MEMORYFILL) \\ - \end{array} \\ - \end{array} - \\ \qquad - (\iff n > 1) \\ + S; F; (\I32.\CONST~d)~\val~(\I32.\CONST~n)~\MEMORYFILL + \quad\stepto\quad S; F; \TRAP + \\ \qquad + (\iff d + n > |S.\SMEMS[F.\AMODULE.\MIMEMS[x]].\MIDATA|) \\ + \\[1ex] + S; F; (\I32.\CONST~d)~\val~(\I32.\CONST~0)~\MEMORYFILL + \quad\stepto\quad S; F; \epsilon + \\ \qquad + (\otherwise) + \\[1ex] + S; F; (\I32.\CONST~d)~\val~(\I32.\CONST~n+1)~\MEMORYFILL + \quad\stepto\quad S; F; + \begin{array}[t]{@{}l@{}} + (\I32.\CONST~d)~\val~(\I32\K{.}\STORE\K{8}~\{ \OFFSET~0, \ALIGN~0 \}) \\ + (\I32.\CONST~d+1)~\val~(\I32.\CONST~n)~\MEMORYFILL \\ + \end{array} + \\ \qquad + (\otherwise) \\ \end{array} -.. note:: - The use of the :math:`\vconst_t` meta function in the rules for this and the following instructions ensures that an overflowing index turns into a :ref:`trap `. - .. _exec-memory.init: @@ -726,9 +720,9 @@ Memory Instructions 7. Let :math:`\X{da}` be the :ref:`data address ` :math:`F.\AMODULE.\MIDATAS[x]`. -8. Assert: due to :ref:`validation `, :math:`S.\SDATA[\X{da}]` exists. +8. Assert: due to :ref:`validation `, :math:`S.\SDATAS[\X{da}]` exists. -9. Let :math:`\X{data}` be the :ref:`data instance ` :math:`S.\SDATA[\X{da}]`. +9. Let :math:`\X{data}` be the :ref:`data instance ` :math:`S.\SDATAS[\X{da}]`. 10. Assert: due to :ref:`validation `, a value of :ref:`value type ` |I32| is on the top of the stack. @@ -742,74 +736,58 @@ Memory Instructions 15. Pop the value :math:`\I32.\CONST~dst` from the stack. -16. If :math:`cnt = 0`, then: - - a. Return. - -17. If :math:`cnt = 1`, then: - - a. Push the value :math:`\I32.\CONST~dst` to the stack. +16. If :math:`s + n` is larger than the length of :math:`\X{data}.\DIDATA` or :math:`d + n` is larger than the length of :math:`\X{mem}.\MIDATA`, then: - b. If `src` is larger than the length of :math:`\X{data}.\DIINIT`, then: - - i. Trap. + a. Trap. - c. Let :math:`b` be the byte :math:`\X{data}.\DIINIT[src]`. +17. If :math:`n = 0`, then: - d. Push the value :math:`\I32.\CONST~b` to the stack. + a. Return. - e. Execute the instruction :math:`\I32\K{.}\STORE\K{8}~\{ \OFFSET~0, \ALIGN~0 \}`. +18. Let :math:`b` be the byte :math:`\X{data}.\DIDATA[s]`. - f. Return. +19. Push the value :math:`\I32.\CONST~d` to the stack. -18. Push the value :math:`\I32.\CONST~dst` to the stack. +20. Push the value :math:`\I32.\CONST~b` to the stack. -19. Push the value :math:`\I32.\CONST~src` to the stack. +21. Execute the instruction :math:`\I32\K{.}\STORE\K{8}~\{ \OFFSET~0, \ALIGN~0 \}`. -20. Push the value :math:`\I32.\CONST~1` to the stack. +22. Assert: due to the earlier check against the memory size, :math:`d+1 < 2^{32}`. -21. Execute the instruction :math:`\MEMORYINIT~x`. +23. Push the value :math:`\I32.\CONST~(d+1)` to the stack. -22. Push the value :math:`\vconst_{\I32}(dst+1)` to the stack. +24. Assert: due to the earlier check against the memory size, :math:`s+1 < 2^{32}`. -23. Push the value :math:`\vconst_{\I32}(src+1)` to the stack. +25. Push the value :math:`\I32.\CONST~(s+1)` to the stack. -24. Push the value :math:`\I32.\CONST~(cnt-1)` to the stack. +26. Push the value :math:`\I32.\CONST~(n-1)` to the stack. -25. Execute the instruction :math:`\MEMORYINIT~x`. +27. Execute the instruction :math:`\MEMORYINIT~x`. .. math:: ~\\[-1ex] \begin{array}{l} - \begin{array}{lcl@{\qquad}l} - S; F; (\I32.\CONST~dst)~(\I32.\CONST~src)~(\I32.\CONST~0)~(\MEMORYINIT~x) &\stepto& S; F; \epsilon - \end{array} - \\[1ex] - \begin{array}{lcl@{\qquad}l} - S; F; (\I32.\CONST~dst)~(\I32.\CONST~src)~(\I32.\CONST~1)~(\MEMORYINIT~x) &\stepto& S; F; - (\I32.\CONST~dst)~(\I32.\CONST~b)~(\I32\K{.}\STORE\K{8}~\{ \OFFSET~0, \ALIGN~0 \}) \\ - \end{array} - \\ \qquad + S; F; (\I32.\CONST~d)~(\I32.\CONST~s)~(\I32.\CONST~n)~(\MEMORYINIT~x) + \quad\stepto\quad S; F; \TRAP + \\ \qquad \begin{array}[t]{@{}r@{~}l@{}} - (\iff & src < |S.\SDATA[F.\AMODULE.\MIDATAS[x]].\DIINIT| \\ - \wedge & b = S.\SDATA[F.\AMODULE.\MIDATAS[x]].\DIINIT[src]) \\ + (\iff & s + n > |S.\SDATAS[F.\AMODULE.\MIDATAS[x]].\DIDATA| \\ + \vee & d + n > |S.\SMEMS[F.\AMODULE.\MIMEMS[x]].\MIDATA|) \\ \end{array} \\[1ex] - \begin{array}{lcl@{\qquad}l} - S; F; (\I32.\CONST~dst)~(\I32.\CONST~src)~(\I32.\CONST~cnt))~(\MEMORYINIT~x) &\stepto& S; F; - \begin{array}[t]{@{}l@{}} - (\I32.\CONST~dst)~(\I32.\CONST~src)~(\I32.\CONST~1)~(\MEMORYINIT~x) \\ - (\vconst_{\I32}(dst+1))~(\vconst_{\I32}(src+1))~(\I32.\CONST~(cnt-1))~(\MEMORYINIT~x) \\ - \end{array} \\ - \end{array} - \\ \qquad - (\iff cnt > 1) + S; F; (\I32.\CONST~d)~(\I32.\CONST~s)~(\I32.\CONST~0)~(\MEMORYINIT~x) + \quad\stepto\quad S; F; \epsilon + \\ \qquad + (\otherwise) \\[1ex] - \begin{array}{lcl@{\qquad}l} - S; F; (\I32.\CONST~dst)~(\I32.\CONST~src)~(\I32.\CONST~cnt)~(\MEMORYINIT~x) &\stepto& S; F; \TRAP - \end{array} - \\ \qquad - (\otherwise) \\ + S; F; (\I32.\CONST~d)~(\I32.\CONST~s)~(\I32.\CONST~n+1)~(\MEMORYINIT~x) + \quad\stepto\quad S; F; + \begin{array}[t]{@{}l@{}} + (\I32.\CONST~d)~(\I32.\CONST~b)~(\I32\K{.}\STORE\K{8}~\{ \OFFSET~0, \ALIGN~0 \}) \\ + (\I32.\CONST~d+1)~(\I32.\CONST~s+1)~(\I32.\CONST~n)~(\MEMORYINIT~x) \\ + \end{array} + \\ \qquad + (\otherwise, \iff b = S.\SDATAS[F.\AMODULE.\MIDATAS[x]].\DIDATA[s]) \\ \end{array} @@ -824,9 +802,9 @@ Memory Instructions 3. Let :math:`a` be the :ref:`data address ` :math:`F.\AMODULE.\MIDATAS[x]`. -4. Assert: due to :ref:`validation `, :math:`S.\SDATA[a]` exists. +4. Assert: due to :ref:`validation `, :math:`S.\SDATAS[a]` exists. -5. Replace :math:`S.\SDATA[a]` with the :ref:`data instance ` :math:`\{\DIINIT~\epsilon\}`. +5. Replace :math:`S.\SDATAS[a]` with the :ref:`data instance ` :math:`\{\DIDATA~\epsilon\}`. .. math:: ~\\[-1ex] @@ -835,7 +813,7 @@ Memory Instructions S; F; (\DATADROP~x) &\stepto& S'; F; \epsilon \end{array} \\ \qquad - (\iff S' = S \with \SDATA[F.\AMODULE.\MIDATAS[x]] = \{ \DIINIT~\epsilon \}) \\ + (\iff S' = S \with \SDATAS[F.\AMODULE.\MIDATAS[x]] = \{ \DIDATA~\epsilon \}) \\ \end{array} @@ -844,101 +822,113 @@ Memory Instructions :math:`\MEMORYCOPY` ................... -1. Assert: due to :ref:`validation `, a value of :ref:`value type ` |I32| is on the top of the stack. +1. Let :math:`F` be the :ref:`current ` :ref:`frame `. + +2. Assert: due to :ref:`validation `, :math:`F.\AMODULE.\MIMEMS[0]` exists. + +3. Let :math:`\X{ma}` be the :ref:`memory address ` :math:`F.\AMODULE.\MIMEMS[0]`. + +4. Assert: due to :ref:`validation `, :math:`S.\SMEMS[\X{ma}]` exists. + +5. Let :math:`\X{mem}` be the :ref:`memory instance ` :math:`S.\SMEMS[\X{ma}]`. + +6. Assert: due to :ref:`validation `, a value of :ref:`value type ` |I32| is on the top of the stack. -2. Pop the value :math:`\I32.\CONST~cnt` from the stack. +7. Pop the value :math:`\I32.\CONST~n` from the stack. + +8. Assert: due to :ref:`validation `, a value of :ref:`value type ` |I32| is on the top of the stack. -3. Assert: due to :ref:`validation `, a value of :ref:`value type ` |I32| is on the top of the stack. +9. Pop the value :math:`\I32.\CONST~s` from the stack. -4. Pop the value :math:`\I32.\CONST~src` from the stack. +10. Assert: due to :ref:`validation `, a value of :ref:`value type ` |I32| is on the top of the stack. -5. Assert: due to :ref:`validation `, a value of :ref:`value type ` |I32| is on the top of the stack. +11. Pop the value :math:`\I32.\CONST~d` from the stack. -6. Pop the value :math:`\I32.\CONST~dst` from the stack. +12. If :math:`s + n` is larger than the length of :math:`\X{mem}.\MIDATA` or :math:`d + n` is larger than the length of :math:`\X{mem}.\MIDATA`, then: + + a. Trap. -7. If :math:`cnt = 0`, then: +13. If :math:`n = 0`, then: a. Return. -8. If :math:`cnt = 1`, then: +14. If :math:`d \leq s`, then: - a. Push the value :math:`\I32.\CONST~dst` to the stack. + a. Push the value :math:`\I32.\CONST~d` to the stack. - b. Push the value :math:`\I32.\CONST~src` to the stack. + b. Push the value :math:`\I32.\CONST~s` to the stack. c. Execute the instruction :math:`\I32\K{.}\LOAD\K{8\_u}~\{ \OFFSET~0, \ALIGN~0 \}`. d. Execute the instruction :math:`\I32\K{.}\STORE\K{8}~\{ \OFFSET~0, \ALIGN~0 \}`. - e. Return. + e. Assert: due to the earlier check against the memory size, :math:`d+1 < 2^{32}`. -9. If :math:`dst <= src`, then: + f. Push the value :math:`\I32.\CONST~(d+1)` to the stack. - a. Push the value :math:`\I32.\CONST~dst` to the stack. + g. Assert: due to the earlier check against the memory size, :math:`s+1 < 2^{32}`. - b. Push the value :math:`\I32.\CONST~src` to the stack. + h. Push the value :math:`\I32.\CONST~(s+1)` to the stack. - c. Push the value :math:`\I32.\CONST~1` to the stack. +15. Else: - d. Execute the instruction :math:`\MEMORYCOPY`. + a. Assert: due to the earlier check against the memory size, :math:`d+n-1 < 2^{32}`. - e. Push the value :math:`\vconst_{\I32}(dst+1)` to the stack. + b. Push the value :math:`\I32.\CONST~(d+n-1)` to the stack. - f. Push the value :math:`\vconst_{\I32}(src+1)` to the stack. + c. Assert: due to the earlier check against the memory size, :math:`s+n-1 < 2^{32}`. -10. Else: + d. Push the value :math:`\I32.\CONST~(s+n-1)` to the stack. - a. Push the value :math:`\vconst_{\I32}(dst+cnt-1)` to the stack. + e. Execute the instruction :math:`\I32\K{.}\LOAD\K{8\_u}~\{ \OFFSET~0, \ALIGN~0 \}`. - b. Push the value :math:`\vconst_{\I32}(src+cnt-1)` to the stack. + f. Execute the instruction :math:`\I32\K{.}\STORE\K{8}~\{ \OFFSET~0, \ALIGN~0 \}`. - c. Push the value :math:`\I32.\CONST~1` to the stack. + g. Push the value :math:`\I32.\CONST~d` to the stack. - d. Execute the instruction :math:`\MEMORYCOPY`. + h. Push the value :math:`\I32.\CONST~s` to the stack. - e. Push the value :math:`\I32.\CONST~dst` to the stack. +16. Push the value :math:`\I32.\CONST~(n-1)` to the stack. - f. Push the value :math:`\I32.\CONST~src` to the stack. - -11. Push the value :math:`\I32.\CONST~(cnt-1)` to the stack. - -12. Execute the instruction :math:`\MEMORYCOPY`. +17. Execute the instruction :math:`\MEMORYCOPY`. .. math:: ~\\[-1ex] \begin{array}{l} - \begin{array}{lcl@{\qquad}l} - S; F; (\I32.\CONST~dst)~(\I32.\CONST~src)~(\I32.\CONST~0)~\MEMORYCOPY &\stepto& S; F; \epsilon - \end{array} + S; F; (\I32.\CONST~d)~(\I32.\CONST~s)~(\I32.\CONST~n)~\MEMORYCOPY + \quad\stepto\quad S; F; \TRAP + \\ \qquad + \begin{array}[t]{@{}r@{~}l@{}} + (\iff & s + n > |S.\SMEMS[F.\AMODULE.\MIMEMS[0]].\MIDATA| \\ + \vee & d + n > |S.\SMEMS[F.\AMODULE.\MIMEMS[0]].\MIDATA|) \\ + \end{array} \\[1ex] - \begin{array}{lcl@{\qquad}l} - S; F; (\I32.\CONST~dst)~(\I32.\CONST~src)~(\I32.\CONST~1)~\MEMORYCOPY &\stepto& S; F; - \begin{array}[t]{@{}l@{}} - (\I32.\CONST~dst) \\ - (\I32.\CONST~src)~(\I32\K{.}\LOAD\K{8\_u}~\{ \OFFSET~0, \ALIGN~0 \}) \\ - (\I32\K{.}\STORE\K{8}~\{ \OFFSET~0, \ALIGN~0 \}) \\ - \end{array} \\ - \end{array} + S; F; (\I32.\CONST~d)~(\I32.\CONST~s)~(\I32.\CONST~0)~\MEMORYCOPY + \quad\stepto\quad S; F; \epsilon + \\ \qquad + (\otherwise) \\[1ex] - \begin{array}{lcl@{\qquad}l} - S; F; (\I32.\CONST~dst)~(\I32.\CONST~src)~(\I32.\CONST~cnt)~\MEMORYCOPY &\stepto& S; F; - \begin{array}[t]{@{}l@{}} - (\I32.\CONST~dst)~(\I32.\CONST~src)~(\I32.\CONST~1)~\MEMORYCOPY \\ - (\vconst_{\I32}(dst+1))~(\vconst_{\I32}(src+1))~(\I32.\CONST~(cnt-1))~\MEMORYCOPY \\ - \end{array} \\ - \end{array} - \\ \qquad - (\iff dst \leq src \wedge cnt > 1) + S; F; (\I32.\CONST~d)~(\I32.\CONST~s)~(\I32.\CONST~n+1)~\MEMORYCOPY + \quad\stepto\quad S; F; + \begin{array}[t]{@{}l@{}} + (\I32.\CONST~d) \\ + (\I32.\CONST~s)~(\I32\K{.}\LOAD\K{8\_u}~\{ \OFFSET~0, \ALIGN~0 \}) \\ + (\I32\K{.}\STORE\K{8}~\{ \OFFSET~0, \ALIGN~0 \}) \\ + (\I32.\CONST~d+1)~(\I32.\CONST~s+1)~(\I32.\CONST~n)~\MEMORYCOPY \\ + \end{array} + \\ \qquad + (\otherwise, \iff d \leq s) \\[1ex] - \begin{array}{lcl@{\qquad}l} - S; F; (\I32.\CONST~dst)~(\I32.\CONST~src)~(\I32.\CONST~cnt)~\MEMORYCOPY &\stepto& S; F; - \begin{array}[t]{@{}l@{}} - (\vconst_{\I32}(dst+cnt-1))~(\vconst_{\I32}(src+cnt-1))~(\I32.\CONST~1)~\MEMORYCOPY \\ - (\I32.\CONST~dst)~(\I32.\CONST~src)~(\I32.\CONST~(cnt-1))~\MEMORYCOPY \\ - \end{array} \\ - \end{array} - \\ \qquad - (\iff dst > src \wedge cnt > 1) \\ + S; F; (\I32.\CONST~d)~(\I32.\CONST~s)~(\I32.\CONST~n+1)~\MEMORYCOPY + \quad\stepto\quad S; F; + \begin{array}[t]{@{}l@{}} + (\I32.\CONST~d+n-1) \\ + (\I32.\CONST~s+n-1)~(\I32\K{.}\LOAD\K{8\_u}~\{ \OFFSET~0, \ALIGN~0 \}) \\ + (\I32\K{.}\STORE\K{8}~\{ \OFFSET~0, \ALIGN~0 \}) \\ + (\I32.\CONST~d)~(\I32.\CONST~s)~(\I32.\CONST~n)~\MEMORYCOPY \\ + \end{array} + \\ \qquad + (\otherwise, \iff d > s) \\ \end{array} @@ -955,97 +945,109 @@ Table Instructions :math:`\TABLECOPY` .................. -1. Assert: due to :ref:`validation `, a value of :ref:`value type ` |I32| is on the top of the stack. +1. Let :math:`F` be the :ref:`current ` :ref:`frame `. + +2. Assert: due to :ref:`validation `, :math:`F.\AMODULE.\MITABLES[0]` exists. + +3. Let :math:`\X{ta}` be the :ref:`table address ` :math:`F.\AMODULE.\MITABLES[0]`. + +4. Assert: due to :ref:`validation `, :math:`S.\STABLES[\X{ta}]` exists. -2. Pop the value :math:`\I32.\CONST~cnt` from the stack. +5. Let :math:`\X{tab}` be the :ref:`table instance ` :math:`S.\STABLES[\X{ta}]`. -3. Assert: due to :ref:`validation `, a value of :ref:`value type ` |I32| is on the top of the stack. +6. Assert: due to :ref:`validation `, a value of :ref:`value type ` |I32| is on the top of the stack. -4. Pop the value :math:`\I32.\CONST~src` from the stack. +7. Pop the value :math:`\I32.\CONST~n` from the stack. -5. Assert: due to :ref:`validation `, a value of :ref:`value type ` |I32| is on the top of the stack. +8. Assert: due to :ref:`validation `, a value of :ref:`value type ` |I32| is on the top of the stack. -6. Pop the value :math:`\I32.\CONST~dst` from the stack. +9. Pop the value :math:`\I32.\CONST~s` from the stack. -7. If :math:`cnt = 0`, then: +10. Assert: due to :ref:`validation `, a value of :ref:`value type ` |I32| is on the top of the stack. + +11. Pop the value :math:`\I32.\CONST~d` from the stack. + +12. If :math:`s + n` is larger than the length of :math:`\X{tab}.\TIELEM` or :math:`d + n` is larger than the length of :math:`\X{tab}.\TIELEM`, then: + + a. Trap. + +13. If :math:`n = 0`, then: a. Return. -8. If :math:`cnt = 1`, then: +14. If :math:`d \leq s`, then: - a. Push the value :math:`\I32.\CONST~dst` to the stack. + a. Push the value :math:`\I32.\CONST~d` to the stack. - b. Push the value :math:`\I32.\CONST~src` to the stack. + b. Push the value :math:`\I32.\CONST~s` to the stack. c. Execute the instruction :math:`\TABLEGET`. d. Execute the instruction :math:`\TABLESET`. - e. Return. - -9. If :math:`dst <= src`, then: + e. Assert: due to the earlier check against the table size, :math:`d+1 < 2^{32}`. - a. Push the value :math:`\I32.\CONST~dst` to the stack. + f. Push the value :math:`\I32.\CONST~(d+1)` to the stack. - b. Push the value :math:`\I32.\CONST~src` to the stack. + g. Assert: due to the earlier check against the table size, :math:`s+1 < 2^{32}`. - c. Push the value :math:`\I32.\CONST~1` to the stack. + h. Push the value :math:`\I32.\CONST~(s+1)` to the stack. - d. Execute the instruction :math:`\TABLECOPY`. +15. Else: - e. Push the value :math:`\vconst_{\I32}(dst+1)` to the stack. + a. Assert: due to the earlier check against the table size, :math:`d+n-1 < 2^{32}`. - f. Push the value :math:`\vconst_{\I32}(src+1)` to the stack. + b. Push the value :math:`\I32.\CONST~(d+n-1)` to the stack. -10. Else: + c. Assert: due to the earlier check against the table size, :math:`s+n-1 < 2^{32}`. - a. Push the value :math:`\vconst_{\I32}(dst+cnt-1)` to the stack. + d. Push the value :math:`\I32.\CONST~(s+n-1)` to the stack. - b. Push the value :math:`\vconst_{\I32}(src+cnt-1)` to the stack. - - c. Push the value :math:`\I32.\CONST~1` to the stack. + c. Execute the instruction :math:`\TABLEGET`. - d. Execute the instruction :math:`\TABLECOPY`. + f. Execute the instruction :math:`\TABLESET`. - e. Push the value :math:`\I32.\CONST~dst` to the stack. + g. Push the value :math:`\I32.\CONST~d` to the stack. - f. Push the value :math:`\I32.\CONST~src` to the stack. + h. Push the value :math:`\I32.\CONST~s` to the stack. -11. Push the value :math:`\I32.\CONST~(cnt-1)` to the stack. +16. Push the value :math:`\I32.\CONST~(n-1)` to the stack. -12. Execute the instruction :math:`\TABLECOPY`. +17. Execute the instruction :math:`\TABLECOPY`. .. math:: ~\\[-1ex] \begin{array}{l} - \begin{array}{lcl@{\qquad}l} - S; F; (\I32.\CONST~dst)~(\I32.\CONST~src)~(\I32.\CONST~0)~\TABLECOPY &\stepto& S; F; \epsilon - \end{array} + S; F; (\I32.\CONST~d)~(\I32.\CONST~s)~(\I32.\CONST~n)~\TABLECOPY + \quad\stepto\quad S; F; \TRAP + \\ \qquad + \begin{array}[t]{@{}r@{~}l@{}} + (\iff & s + n > |S.\STABLES[F.\AMODULE.\MITABLES[0]].\TIELEM| \\ + \vee & d + n > |S.\STABLES[F.\AMODULE.\MITABLES[0]].\TIELEM|) \\ + \end{array} \\[1ex] - \begin{array}{lcl@{\qquad}l} - S; F; (\I32.\CONST~dst)~(\I32.\CONST~src)~(\I32.\CONST~1)~\TABLECOPY &\stepto& S; F; - (\I32.\CONST~dst)~(\I32.\CONST~src)~\TABLEGET~\TABLESET \\ - \end{array} + S; F; (\I32.\CONST~d)~(\I32.\CONST~s)~(\I32.\CONST~0)~\TABLECOPY + \quad\stepto\quad S; F; \epsilon + \\ \qquad + (\otherwise) \\[1ex] - \begin{array}{lcl@{\qquad}l} - S; F; (\I32.\CONST~dst)~(\I32.\CONST~src)~(\I32.\CONST~cnt)~\TABLECOPY &\stepto& S; F; - \begin{array}[t]{@{}l@{}} - (\I32.\CONST~dst)~(\I32.\CONST~src)~(\I32.\CONST~1)~\TABLECOPY \\ - (\vconst_{\I32}(dst+1))~(\vconst_{\I32}(src+1))~(\I32.\CONST~(cnt-1))~\TABLECOPY \\ - \end{array} \\ - \end{array} - \\ \qquad - (\iff dst <= src \wedge cnt > 1) + S; F; (\I32.\CONST~d)~(\I32.\CONST~s)~(\I32.\CONST~n+1)~\TABLECOPY + \quad\stepto\quad S; F; + \begin{array}[t]{@{}l@{}} + (\I32.\CONST~d)~(\I32.\CONST~s)~\TABLEGET~\TABLESET \\ + (\I32.\CONST~d+1)~(\I32.\CONST~s+1)~(\I32.\CONST~n)~\TABLECOPY \\ + \end{array} + \\ \qquad + (\otherwise, \iff d \leq s) \\[1ex] - \begin{array}{lcl@{\qquad}l} - S; F; (\I32.\CONST~dst)~(\I32.\CONST~src)~(\I32.\CONST~cnt)~\TABLECOPY &\stepto& S; F; - \begin{array}[t]{@{}l@{}} - (\I32.\CONST~(dst+cnt-1))~(\I32.\CONST~(src+cnt-1))~(\I32.\CONST~1)~\TABLECOPY \\ - (\I32.\CONST~dst)~(\I32.\CONST~src)~(\I32.\CONST~(cnt-1))~\TABLECOPY \\ - \end{array} \\ - \end{array} - \\ \qquad - (\iff dst > src \wedge cnt > 1) \\ + S; F; (\I32.\CONST~d)~(\I32.\CONST~s)~(\I32.\CONST~n+1)~\TABLECOPY + \quad\stepto\quad S; F; + \begin{array}[t]{@{}l@{}} + (\I32.\CONST~d+n-1)~(\I32.\CONST~s+n-1)~\TABLEGET~\TABLESET \\ + (\I32.\CONST~d)~(\I32.\CONST~s)~(\I32.\CONST~n)~\TABLECOPY \\ + \end{array} + \\ \qquad + (\otherwise, \iff d > s) \\ \end{array} @@ -1068,90 +1070,74 @@ Table Instructions 7. Let :math:`\X{ea}` be the :ref:`element address ` :math:`F.\AMODULE.\MIELEMS[x]`. -8. Assert: due to :ref:`validation `, :math:`S.\SELEM[\X{ea}]` exists. +8. Assert: due to :ref:`validation `, :math:`S.\SELEMS[\X{ea}]` exists. -9. Let :math:`\X{elem}` be the :ref:`element instance ` :math:`S.\SELEM[\X{ea}]`. +9. Let :math:`\X{elem}` be the :ref:`element instance ` :math:`S.\SELEMS[\X{ea}]`. 10. Assert: due to :ref:`validation `, a value of :ref:`value type ` |I32| is on the top of the stack. -11. Pop the value :math:`\I32.\CONST~cnt` from the stack. +11. Pop the value :math:`\I32.\CONST~n` from the stack. 12. Assert: due to :ref:`validation `, a value of :ref:`value type ` |I32| is on the top of the stack. -13. Pop the value :math:`\I32.\CONST~src` from the stack. +13. Pop the value :math:`\I32.\CONST~s` from the stack. 14. Assert: due to :ref:`validation `, a value of :ref:`value type ` |I32| is on the top of the stack. -15. Pop the value :math:`\I32.\CONST~dst` from the stack. - -16. If :math:`cnt = 0`, then: - - a. Return. - -17. If :math:`cnt = 1`, then: +15. Pop the value :math:`\I32.\CONST~d` from the stack. - a. Push the value :math:`\I32.\CONST~dst` to the stack. +16. If :math:`s + n` is larger than the length of :math:`\X{elem}.\EIELEM` or :math:`d + n` is larger than the length of :math:`\X{tab}.\TIELEM`, then: - b. If `src` is larger than the length of :math:`\X{elem}.\EIINIT`, then: - - i. Trap. + a. Trap. - c. Let :math:`\funcelem` be the :ref:`function element ` :math:`\X{elem}.\EIINIT[src]`. +17. If :math:`n = 0`, then: - d. Push the value :math:`\funcelem` to the stack. + a. Return. - e. Execute the instruction :math:`\TABLESET`. +18. Let :math:`\funcelem` be the :ref:`function element ` :math:`\X{elem}.\EIELEM[s]`. - f. Return. +19. Push the value :math:`\I32.\CONST~d` to the stack. -18. Push the value :math:`\I32.\CONST~dst` to the stack. +20. Push the value :math:`\funcelem` to the stack. -19. Push the value :math:`\I32.\CONST~src` to the stack. +21. Execute the instruction :math:`\TABLESET`. -20. Push the value :math:`\I32.\CONST~1` to the stack. +22. Assert: due to the earlier check against the table size, :math:`d+1 < 2^{32}`. -21. Execute the instruction :math:`\TABLEINIT~x`. +23. Push the value :math:`\I32.\CONST~(d+1)` to the stack. -22. Push the value :math:`\vconst_{\I32}(dst+1)` to the stack. +24. Assert: due to the earlier check against the segment size, :math:`s+1 < 2^{32}`. -23. Push the value :math:`\vconst_{\I32}(src+1)` to the stack. +25. Push the value :math:`\I32.\CONST~(s+1)` to the stack. -24. Push the value :math:`\I32.\CONST~(cnt-1)` to the stack. +26. Push the value :math:`\I32.\CONST~(n-1)` to the stack. -25. Execute the instruction :math:`\TABLEINIT~x`. +27. Execute the instruction :math:`\TABLEINIT~x`. .. math:: ~\\[-1ex] \begin{array}{l} - \begin{array}{lcl@{\qquad}l} - S; F; (\I32.\CONST~dst)~(\I32.\CONST~src)~(\I32.\CONST~0)~(\TABLEINIT~x) &\stepto& S; F; \epsilon - \end{array} - \\[1ex] - \begin{array}{lcl@{\qquad}l} - S; F; (\I32.\CONST~dst)~(\I32.\CONST~src)~(\I32.\CONST~1)~(\TABLEINIT~x) &\stepto& S; F; - (\I32.\CONST~dst)~\funcelem~(\TABLESET~x) \\ - \end{array} - \\ \qquad + S; F; (\I32.\CONST~d)~(\I32.\CONST~s)~(\I32.\CONST~n)~(\TABLEINIT~x) + \quad\stepto\quad S; F; \TRAP + \\ \qquad \begin{array}[t]{@{}r@{~}l@{}} - (\iff & src < |S.\SELEM[F.\AMODULE.\MIELEMS[x]].\EIINIT| \\ - \wedge & \funcelem = S.\SELEM[F.\AMODULE.\MIELEMS[x]].\EIINIT[src]) \\ + (\iff & s + n > |S.\SELEMS[F.\AMODULE.\MIELEMS[x]].\EIELEM| \\ + \vee & d + n > |S.\STABLES[F.\AMODULE.\MITABLES[x]].\TIELEM|) \\ \end{array} \\[1ex] - \begin{array}{lcl@{\qquad}l} - S; F; (\I32.\CONST~dst)~(\I32.\CONST~src)~(\I32.\CONST~cnt)~(\TABLEINIT~x) &\stepto& S; F; - \begin{array}[t]{@{}l@{}} - (\I32.\CONST~dst)~(\I32.\CONST~src)~(\I32.\CONST~1)~(\TABLEINIT~x) \\ - (\vconst_{\I32}(dst+1))~(\vconst_{\I32}(src+1))~(\I32.\CONST~(cnt-1))~(\TABLEINIT~x) \\ - \end{array} \\ - \end{array} - \\ \qquad - (\iff cnt > 1) + S; F; (\I32.\CONST~d)~(\I32.\CONST~s)~(\I32.\CONST~0)~(\TABLEINIT~x) + \quad\stepto\quad S; F; \epsilon + \\ \qquad + (\otherwise) \\[1ex] - \begin{array}{lcl@{\qquad}l} - S; F; (\I32.\CONST~dst)~(\I32.\CONST~src)~(\I32.\CONST~cnt)~(\TABLEINIT~x) &\stepto& S; F; \TRAP - \end{array} - \\ \qquad - (\otherwise) \\ + S; F; (\I32.\CONST~d)~(\I32.\CONST~s)~(\I32.\CONST~n+1)~(\TABLEINIT~x) + \quad\stepto\quad S; F; + \begin{array}[t]{@{}l@{}} + (\I32.\CONST~d)~\funcelem~(\TABLESET~x) \\ + (\I32.\CONST~d+1)~(\I32.\CONST~s+1)~(\I32.\CONST~n)~(\TABLEINIT~x) \\ + \end{array} + \\ \qquad + (\otherwise, \iff \funcelem = S.\SELEMS[F.\AMODULE.\MIELEMS[x]].\EIELEM[s]) \\ \end{array} @@ -1166,9 +1152,9 @@ Table Instructions 3. Let :math:`a` be the :ref:`element address ` :math:`F.\AMODULE.\MIELEMS[x]`. -4. Assert: due to :ref:`validation `, :math:`S.\SELEM[a]` exists. +4. Assert: due to :ref:`validation `, :math:`S.\SELEMS[a]` exists. -5. Replace :math:`S.\SELEM[a]` with the :ref:`element instance ` :math:`\{\EIINIT~\epsilon\}`. +5. Replace :math:`S.\SELEMS[a]` with the :ref:`element instance ` :math:`\{\EIELEM~\epsilon\}`. .. math:: ~\\[-1ex] @@ -1177,7 +1163,7 @@ Table Instructions S; F; (\ELEMDROP~x) &\stepto& S'; F; \epsilon \end{array} \\ \qquad - (\iff S' = S \with \SELEM[F.\AMODULE.\MIELEMS[x]] = \{ \EIINIT~\epsilon \}) \\ + (\iff S' = S \with \SELEMS[F.\AMODULE.\MIELEMS[x]] = \{ \EIELEM~\epsilon \}) \\ \end{array} diff --git a/document/core/exec/modules.rst b/document/core/exec/modules.rst index 005d68223b..b0b51849ba 100644 --- a/document/core/exec/modules.rst +++ b/document/core/exec/modules.rst @@ -381,9 +381,9 @@ New instances of :ref:`functions `, :ref:`tables ` in :math:`S`. -3. Let :math:`\eleminst` be the :ref:`element instance ` :math:`\{ \EIINIT~\funcelem^\ast \}`. +3. Let :math:`\eleminst` be the :ref:`element instance ` :math:`\{ \EIELEM~\funcelem^\ast \}`. -4. Append :math:`\eleminst` to the |SELEM| of :math:`S`. +4. Append :math:`\eleminst` to the |SELEMS| of :math:`S`. 5. Return :math:`a`. @@ -391,9 +391,9 @@ New instances of :ref:`functions `, :ref:`tables `, :ref:`tables ` in :math:`S`. -3. Let :math:`\datainst` be the :ref:`data instance ` :math:`\{ \DIINIT~\bytes \}`. +3. Let :math:`\datainst` be the :ref:`data instance ` :math:`\{ \DIDATA~\bytes \}`. -4. Append :math:`\datainst` to the |SDATA| of :math:`S`. +4. Append :math:`\datainst` to the |SDATAS| of :math:`S`. 5. Return :math:`a`. @@ -417,9 +417,9 @@ New instances of :ref:`functions `, :ref:`tables `. - -.. math:: - \begin{array}{lcl@{\qquad}l} - \vconst_t(x) &=& (t\K{.}\CONST~x) - & (\iff x~\mbox{is well-formed for}~t) \\ - \vconst_t(x) &=& \TRAP - & (\otherwise) \\ - \end{array} - .. index:: ! result, value, trap pair: abstract syntax; result @@ -87,8 +74,8 @@ Syntactically, the store is defined as a :ref:`record ` listing \STABLES & \tableinst^\ast, \\ \SMEMS & \meminst^\ast, \\ \SGLOBALS & \globalinst^\ast, \\ - \SELEM & \eleminst^\ast, \\ - \SDATA & \datainst^\ast ~\} \\ + \SELEMS & \eleminst^\ast, \\ + \SDATAS & \datainst^\ast ~\} \\ \end{array} \end{array} @@ -318,7 +305,7 @@ It holds a vector of function elements. .. math:: \begin{array}{llll} \production{(element instance)} & \eleminst &::=& - \{ \EIINIT~\vec(\funcelem) \} \\ + \{ \EIELEM~\vec(\funcelem) \} \\ \end{array} @@ -336,7 +323,7 @@ It holds a vector of :ref:`bytes `. .. math:: \begin{array}{llll} \production{(data instance)} & \datainst &::=& - \{ \DIINIT~\vec(\byte) \} \\ + \{ \DIDATA~\vec(\byte) \} \\ \end{array} diff --git a/document/core/util/macros.def b/document/core/util/macros.def index d16319b77c..86acdc9850 100644 --- a/document/core/util/macros.def +++ b/document/core/util/macros.def @@ -854,9 +854,9 @@ .. |GIVALUE| mathdef:: \xref{exec/runtime}{syntax-globalinst}{\K{value}} .. |GIMUT| mathdef:: \xref{exec/runtime}{syntax-globalinst}{\K{mut}} -.. |EIINIT| mathdef:: \xref{exec/runtime}{syntax-eleminst}{\K{init}} +.. |EIELEM| mathdef:: \xref{exec/runtime}{syntax-eleminst}{\K{elem}} -.. |DIINIT| mathdef:: \xref{exec/runtime}{syntax-datainst}{\K{init}} +.. |DIDATA| mathdef:: \xref{exec/runtime}{syntax-datainst}{\K{data}} .. |EINAME| mathdef:: \xref{exec/runtime}{syntax-exportinst}{\K{name}} .. |EIVALUE| mathdef:: \xref{exec/runtime}{syntax-exportinst}{\K{value}} @@ -899,7 +899,6 @@ .. |evtables| mathdef:: \xref{exec/runtime}{syntax-externval}{\F{tables}} .. |evmems| mathdef:: \xref{exec/runtime}{syntax-externval}{\F{mems}} .. |evglobals| mathdef:: \xref{exec/runtime}{syntax-externval}{\F{globals}} -.. |vconst| mathdef:: \xref{exec/runtime}{syntax-val}{\F{const}} .. Store, terminals @@ -908,8 +907,8 @@ .. |STABLES| mathdef:: \xref{exec/runtime}{syntax-store}{\K{tables}} .. |SMEMS| mathdef:: \xref{exec/runtime}{syntax-store}{\K{mems}} .. |SGLOBALS| mathdef:: \xref{exec/runtime}{syntax-store}{\K{globals}} -.. |SELEM| mathdef:: \xref{exec/runtime}{syntax-store}{\K{elem}} -.. |SDATA| mathdef:: \xref{exec/runtime}{syntax-store}{\K{data}} +.. |SELEMS| mathdef:: \xref{exec/runtime}{syntax-store}{\K{elems}} +.. |SDATAS| mathdef:: \xref{exec/runtime}{syntax-store}{\K{datas}} .. Store, non-terminals @@ -1067,6 +1066,8 @@ .. |vdashtableinst| mathdef:: \xref{appendix/properties}{valid-tableinst}{\vdash} .. |vdashmeminst| mathdef:: \xref{appendix/properties}{valid-meminst}{\vdash} .. |vdashglobalinst| mathdef:: \xref{appendix/properties}{valid-globalinst}{\vdash} +.. |vdasheleminst| mathdef:: \xref{appendix/properties}{valid-eleminst}{\vdash} +.. |vdashdatainst| mathdef:: \xref{appendix/properties}{valid-datainst}{\vdash} .. |vdashexportinst| mathdef:: \xref{appendix/properties}{valid-exportinst}{\vdash} .. |vdashmoduleinst| mathdef:: \xref{appendix/properties}{valid-moduleinst}{\vdash} @@ -1079,6 +1080,8 @@ .. |vdashtableinstextends| mathdef:: \xref{appendix/properties}{extend-tableinst}{\vdash} .. |vdashmeminstextends| mathdef:: \xref{appendix/properties}{extend-meminst}{\vdash} .. |vdashglobalinstextends| mathdef:: \xref{appendix/properties}{extend-globalinst}{\vdash} +.. |vdasheleminstextends| mathdef:: \xref{appendix/properties}{extend-eleminst}{\vdash} +.. |vdashdatainstextends| mathdef:: \xref{appendix/properties}{extend-datainst}{\vdash} .. |vdashstoreextends| mathdef:: \xref{appendix/properties}{extend-store}{\vdash} From d4bc208c0f62ac19529e9e734b10c17c960549e5 Mon Sep 17 00:00:00 2001 From: Andreas Rossberg Date: Fri, 13 Dec 2019 09:56:37 +0100 Subject: [PATCH 135/199] [spec/interpreter/test] Allow nullref type externally (#66) --- document/core/appendix/index-types.rst | 3 +- document/core/binary/types.rst | 6 +- document/core/syntax/types.rst | 2 - document/core/text/types.rst | 3 +- document/js-api/index.bs | 15 ++++- interpreter/README.md | 2 +- interpreter/binary/decode.ml | 1 + interpreter/binary/encode.ml | 2 +- interpreter/text/lexer.mll | 1 + interpreter/text/parser.mly | 3 +- proposals/reference-types/Overview.md | 4 +- test/core/br_table.wast | 21 +++++- test/core/linking.wast | 90 +++++++++++++++++++++----- test/core/ref_is_null.wast | 13 ++++ test/core/ref_null.wast | 3 + test/core/select.wast | 8 +++ 16 files changed, 142 insertions(+), 35 deletions(-) diff --git a/document/core/appendix/index-types.rst b/document/core/appendix/index-types.rst index 3f13e5532c..37f33c7b23 100644 --- a/document/core/appendix/index-types.rst +++ b/document/core/appendix/index-types.rst @@ -15,7 +15,8 @@ Category Constructor (reserved) :math:`\hex{7B}` .. :math:`\hex{71}` :ref:`Reference type ` |FUNCREF| :math:`\hex{70}` (-16 as |Bs7|) :ref:`Reference type ` |ANYREF| :math:`\hex{6F}` (-17 as |Bs7|) -(reserved) :math:`\hex{6E}` .. :math:`\hex{61}` +:ref:`Reference type ` |NULLREF| :math:`\hex{6E}` (-18 as |Bs7|) +(reserved) :math:`\hex{6D}` .. :math:`\hex{61}` :ref:`Function type ` :math:`[\valtype^\ast] \to [\valtype^\ast]` :math:`\hex{60}` (-32 as |Bs7|) (reserved) :math:`\hex{5F}` .. :math:`\hex{41}` :ref:`Result type ` :math:`[\epsilon]` :math:`\hex{40}` (-64 as |Bs7|) diff --git a/document/core/binary/types.rst b/document/core/binary/types.rst index 541f45dbda..e7a7f8ed9f 100644 --- a/document/core/binary/types.rst +++ b/document/core/binary/types.rst @@ -42,12 +42,10 @@ Reference Types \begin{array}{llclll@{\qquad\qquad}l} \production{reference type} & \Breftype &::=& \hex{70} &\Rightarrow& \FUNCREF \\ &&|& - \hex{6F} &\Rightarrow& \ANYREF \\ + \hex{6F} &\Rightarrow& \ANYREF \\ &&|& + \hex{6E} &\Rightarrow& \NULLREF \\ \end{array} -.. note:: - The type :math:`\NULLREF` cannot occur in a module. - .. index:: value type, number type, reference type pair: binary format; value type diff --git a/document/core/syntax/types.rst b/document/core/syntax/types.rst index 522e479541..c8543df887 100644 --- a/document/core/syntax/types.rst +++ b/document/core/syntax/types.rst @@ -63,8 +63,6 @@ The type |FUNCREF| denotes the infinite union of all references to :ref:`functio The type |NULLREF| only contains a single value: the :ref:`null ` reference. It is a :ref:`subtype ` of all other reference types. -By virtue of being representable in neither the :ref:`binary format ` nor the :ref:`text format `, the |NULLREF| type cannot be used in a program; -it only occurs during :ref:`validation `. .. note:: Future versions of WebAssembly may include reference types that do not include null and hence are not supertypes of |NULLREF|. diff --git a/document/core/text/types.rst b/document/core/text/types.rst index db8c6e9d20..569e7f215a 100644 --- a/document/core/text/types.rst +++ b/document/core/text/types.rst @@ -33,7 +33,8 @@ Reference Types \begin{array}{llcll@{\qquad\qquad}l} \production{reference type} & \Treftype &::=& \text{anyref} &\Rightarrow& \ANYREF \\ &&|& - \text{funcref} &\Rightarrow& \FUNCREF \\ + \text{funcref} &\Rightarrow& \FUNCREF \\ &&|& + \text{nullref} &\Rightarrow& \NULLREF \\ \end{array} diff --git a/document/js-api/index.bs b/document/js-api/index.bs index 4d280fb02d..87598c6faa 100644 --- a/document/js-api/index.bs +++ b/document/js-api/index.bs @@ -152,6 +152,7 @@ urlPrefix: https://webassembly.github.io/spec/core/; spec: WebAssembly; type: df url: syntax/types.html#syntax-reftype text: anyref text: funcref + text: nullref text: function element; url: exec/runtime.html#syntax-funcelem text: import component; url: syntax/modules.html#imports text: external value; url: exec/runtime.html#syntax-externval @@ -704,6 +705,7 @@ Immediately after a WebAssembly [=memory.grow=] instruction executes, perform th
     enum TableKind {
    +  "nullref",
       "anyref",
       "anyfunc",
       // Note: More values may be added in future iterations,
    @@ -868,6 +870,10 @@ which can be simultaneously referenced by multiple {{Instance}} objects. Each
         1. If |s| equals "i64", return [=𝗂𝟨𝟦=].
         1. If |s| equals "f32", return [=𝖿𝟥𝟤=].
         1. If |s| equals "f64", return [=𝖿𝟨𝟦=].
    +    1. If |s| equals "anyref", return [=anyref=].
    +    1. If |s| equals "funcref", return [=funcref=].
    +    1. If |s| equals "nullref", return [=nullref=].
    +    1. Assert: This step is not reached.
     
     
     
    @@ -876,7 +882,7 @@ which can be simultaneously referenced by multiple {{Instance}} objects. Each 1. If |valuetype| equals [=𝗂𝟨𝟦=], return [=𝗂𝟨𝟦.𝖼𝗈𝗇𝗌𝗍=] 0. 1. If |valuetype| equals [=𝖿𝟥𝟤=], return [=𝖿𝟥𝟤.𝖼𝗈𝗇𝗌𝗍=] 0. 1. If |valuetype| equals [=𝖿𝟨𝟦=], return [=𝖿𝟨𝟦.𝖼𝗈𝗇𝗌𝗍=] 0. - 1. Assert: This step is not reached. + 1. Else, return [=ref.null=].
    @@ -1063,11 +1069,14 @@ The algorithm ToWebAssemblyValue(|v|, |type|, |error|) coerces a Java 1. If |type| is [=𝖿𝟨𝟦=], 1. Let |f64| be ? [=ToNumber=](|v|). 1. Return [=𝖿𝟨𝟦.𝖼𝗈𝗇𝗌𝗍=] |f64|. +1. Assert: |type| is a reference type. 1. If |type| is [=anyref=], - 1. Return the result of [=allocating a host address=] for |v|. + 1. Do nothing. 1. If |type| is [=funcref=], 1. If |v| is not an [=Exported function=] or null, throw |error|. - 1. Return the result of [=allocating a host address=] for |v|. +1. If |type| is [=nullref=], + 1. If |v| is not null, throw |error|. +1. Return the result of [=allocating a host address=] for |v|.
    diff --git a/interpreter/README.md b/interpreter/README.md index f21239d62e..77c6a54319 100644 --- a/interpreter/README.md +++ b/interpreter/README.md @@ -184,7 +184,7 @@ align: align=(1|2|4|8|...) cvtop: trunc | extend | wrap | ... num_type: i32 | i64 | f32 | f64 -ref_type: anyref | funcref +ref_type: anyref | funcref | nullref val_type: num_type | ref_type block_type : ( result * )* func_type: ( type )? * * diff --git a/interpreter/binary/decode.ml b/interpreter/binary/decode.ml index 8b9e4d9874..674240bb07 100644 --- a/interpreter/binary/decode.ml +++ b/interpreter/binary/decode.ml @@ -145,6 +145,7 @@ let ref_type s = match vs7 s with | -0x10 -> FuncRefType | -0x11 -> AnyRefType + | -0x12 -> NullRefType | _ -> error s (pos s - 1) "invalid reference type" let value_type s = diff --git a/interpreter/binary/encode.ml b/interpreter/binary/encode.ml index 13a93fbaa1..f44df2158d 100644 --- a/interpreter/binary/encode.ml +++ b/interpreter/binary/encode.ml @@ -99,7 +99,7 @@ let encode m = let ref_type = function | FuncRefType -> vs7 (-0x10) | AnyRefType -> vs7 (-0x11) - | NullRefType -> assert false + | NullRefType -> vs7 (-0x12) let value_type = function | NumType t -> num_type t diff --git a/interpreter/text/lexer.mll b/interpreter/text/lexer.mll index 3b7ec2caa7..9a5cf16630 100644 --- a/interpreter/text/lexer.mll +++ b/interpreter/text/lexer.mll @@ -162,6 +162,7 @@ rule token = parse | "anyref" { ANYREF } | "funcref" { FUNCREF } + | "nullref" { NULLREF } | (nxx as t) { NUM_TYPE (num_type t) } | "mut" { MUT } diff --git a/interpreter/text/parser.mly b/interpreter/text/parser.mly index 6257c3dd0a..c42b3cd326 100644 --- a/interpreter/text/parser.mly +++ b/interpreter/text/parser.mly @@ -147,7 +147,7 @@ let inline_type_explicit (c : context) x ft at = %token LPAR RPAR %token NAT INT FLOAT STRING VAR -%token ANYREF FUNCREF NUM_TYPE MUT +%token ANYREF NULLREF FUNCREF NUM_TYPE MUT %token UNREACHABLE NOP DROP SELECT %token BLOCK END IF THEN ELSE LOOP BR BR_IF BR_TABLE %token CALL CALL_INDIRECT RETURN @@ -209,6 +209,7 @@ string_list : ref_type : | ANYREF { AnyRefType } | FUNCREF { FuncRefType } + | NULLREF { NullRefType } value_type : | NUM_TYPE { NumType $1 } diff --git a/proposals/reference-types/Overview.md b/proposals/reference-types/Overview.md index bc32ffd60b..e051112971 100644 --- a/proposals/reference-types/Overview.md +++ b/proposals/reference-types/Overview.md @@ -26,7 +26,7 @@ Get the most important parts soon! Summary: -* Add a new type `anyref` that can be used as both a value type and a table element type. +* Add new types `anyref` and `nullref` that can be used as both a value types and a table element types. * Also allow `funcref` as a value type. @@ -49,8 +49,6 @@ Typing extensions: * Introduce `anyref`, `funcref`, and `nullref` as a new class of *reference types*. - `reftype ::= anyref | funcref | nullref` - - `nullref` is merely an internal type and is neither expressible in the binary format, nor the text format, nor the JS API. - - Question: should it be? * Value types (of locals, globals, function parameters and results) can now be either numeric types or reference types. - `numtype ::= i32 | i64 | f32 | f64` diff --git a/test/core/br_table.wast b/test/core/br_table.wast index 11b51a715e..4ac79de652 100644 --- a/test/core/br_table.wast +++ b/test/core/br_table.wast @@ -1258,7 +1258,6 @@ ) ) ) - (func (export "meet-funcref-2") (param i32) (result anyref) (block $l1 (result anyref) (block $l2 (result funcref) @@ -1266,7 +1265,6 @@ ) ) ) - (func (export "meet-funcref-3") (param i32) (result anyref) (block $l1 (result anyref) (block $l2 (result funcref) @@ -1274,7 +1272,6 @@ ) ) ) - (func (export "meet-funcref-4") (param i32) (result anyref) (block $l1 (result anyref) (block $l2 (result funcref) @@ -1283,6 +1280,24 @@ ) ) + (func (export "meet-nullref") (param i32) (result funcref) + (block $l1 (result funcref) + (block $l2 (result nullref) + (br_table $l1 $l2 $l1 (ref.null) (local.get 0)) + ) + ) + ) + + (func (export "meet-multi-ref") (param i32) (result anyref) + (block $l1 (result anyref) + (block $l2 (result funcref) + (block $l3 (result nullref) + (br_table $l3 $l2 $l1 (ref.null) (local.get 0)) + ) + ) + ) + ) + (func (export "meet-bottom") (block (result f64) (block (result f32) diff --git a/test/core/linking.wast b/test/core/linking.wast index be561e5110..e72f928b5f 100644 --- a/test/core/linking.wast +++ b/test/core/linking.wast @@ -94,29 +94,63 @@ (module $Mref_ex - (global (export "g-const") funcref (ref.null)) - (global (export "g-var") (mut funcref) (ref.null)) + (global (export "g-const-null") nullref (ref.null)) + (global (export "g-var-null") (mut nullref) (ref.null)) + (global (export "g-const-func") funcref (ref.null)) + (global (export "g-var-func") (mut funcref) (ref.null)) + (global (export "g-const-any") anyref (ref.null)) + (global (export "g-var-any") (mut anyref) (ref.null)) ) (register "Mref_ex" $Mref_ex) (module $Mref_im - (global (import "Mref_ex" "g-const") anyref) + (global (import "Mref_ex" "g-const-null") nullref) + (global (import "Mref_ex" "g-const-null") funcref) + (global (import "Mref_ex" "g-const-null") anyref) + (global (import "Mref_ex" "g-const-func") funcref) + (global (import "Mref_ex" "g-const-func") anyref) + (global (import "Mref_ex" "g-const-any") anyref) + + (global (import "Mref_ex" "g-var-null") (mut nullref)) + (global (import "Mref_ex" "g-var-func") (mut funcref)) + (global (import "Mref_ex" "g-var-any") (mut anyref)) ) (assert_unlinkable - (module (global (import "Mref_ex" "g-var") (mut anyref))) + (module (global (import "Mref_ex" "g-const-func") nullref)) "incompatible import type" ) - - -(module $Mglobal_ex - (func $f) - (global (export "g") anyref (ref.func $f)) +(assert_unlinkable + (module (global (import "Mref_ex" "g-const-any") nullref)) + "incompatible import type" +) +(assert_unlinkable + (module (global (import "Mref_ex" "g-const-any") funcref)) + "incompatible import type" ) -(register "Mglobal_ex" $Mglobal_ex) (assert_unlinkable - (module (global (import "Mglobal_ex" "g") funcref)) + (module (global (import "Mref_ex" "g-var-null") (mut funcref))) + "incompatible import type" +) +(assert_unlinkable + (module (global (import "Mref_ex" "g-var-null") (mut anyref))) + "incompatible import type" +) +(assert_unlinkable + (module (global (import "Mref_ex" "g-var-func") (mut nullref))) + "incompatible import type" +) +(assert_unlinkable + (module (global (import "Mref_ex" "g-var-func") (mut anyref))) + "incompatible import type" +) +(assert_unlinkable + (module (global (import "Mref_ex" "g-var-any") (mut nullref))) + "incompatible import type" +) +(assert_unlinkable + (module (global (import "Mref_ex" "g-var-any") (mut funcref))) "incompatible import type" ) @@ -278,14 +312,40 @@ (module $Mtable_ex - (func $f) - (table $t (export "t") 1 anyref) - (elem (i32.const 0) $f) + (table $t1 (export "t-null") 1 nullref) + (table $t2 (export "t-func") 1 funcref) + (table $t3 (export "t-any") 1 anyref) ) (register "Mtable_ex" $Mtable_ex) +(module + (table (import "Mtable_ex" "t-null") 1 nullref) + (table (import "Mtable_ex" "t-func") 1 funcref) + (table (import "Mtable_ex" "t-any") 1 anyref) +) + +(assert_unlinkable + (module (table (import "Mtable_ex" "t-null") 1 funcref)) + "incompatible import type" +) +(assert_unlinkable + (module (table (import "Mtable_ex" "t-null") 1 anyref)) + "incompatible import type" +) +(assert_unlinkable + (module (table (import "Mtable_ex" "t-func") 1 nullref)) + "incompatible import type" +) +(assert_unlinkable + (module (table (import "Mtable_ex" "t-func") 1 anyref)) + "incompatible import type" +) +(assert_unlinkable + (module (table (import "Mtable_ex" "t-any") 1 nullref)) + "incompatible import type" +) (assert_unlinkable - (module (table (import "Mtable_ex" "t") 1 funcref)) + (module (table (import "Mtable_ex" "t-any") 1 funcref)) "incompatible import type" ) diff --git a/test/core/ref_is_null.wast b/test/core/ref_is_null.wast index 7edc8e2832..3e9a678314 100644 --- a/test/core/ref_is_null.wast +++ b/test/core/ref_is_null.wast @@ -1,4 +1,7 @@ (module + (func $f1 (export "nullref") (param $x nullref) (result i32) + (ref.is_null (local.get $x)) + ) (func $f2 (export "anyref") (param $x anyref) (result i32) (ref.is_null (local.get $x)) ) @@ -6,6 +9,7 @@ (ref.is_null (local.get $x)) ) + (table $t1 2 nullref) (table $t2 2 anyref) (table $t3 2 funcref) (elem $t3 (i32.const 1) $dummy) (func $dummy) @@ -14,10 +18,14 @@ (table.set $t2 (i32.const 1) (local.get $r)) ) (func (export "deinit") + (table.set $t1 (i32.const 1) (ref.null)) (table.set $t2 (i32.const 1) (ref.null)) (table.set $t3 (i32.const 1) (ref.null)) ) + (func (export "nullref-elem") (param $x i32) (result i32) + (call $f1 (table.get $t1 (local.get $x))) + ) (func (export "anyref-elem") (param $x i32) (result i32) (call $f2 (table.get $t2 (local.get $x))) ) @@ -26,6 +34,7 @@ ) ) +(assert_return (invoke "nullref" (ref.null)) (i32.const 1)) (assert_return (invoke "anyref" (ref.null)) (i32.const 1)) (assert_return (invoke "funcref" (ref.null)) (i32.const 1)) @@ -33,16 +42,20 @@ (invoke "init" (ref.host 0)) +(assert_return (invoke "nullref-elem" (i32.const 0)) (i32.const 1)) (assert_return (invoke "anyref-elem" (i32.const 0)) (i32.const 1)) (assert_return (invoke "funcref-elem" (i32.const 0)) (i32.const 1)) +(assert_return (invoke "nullref-elem" (i32.const 1)) (i32.const 1)) (assert_return (invoke "anyref-elem" (i32.const 1)) (i32.const 0)) (assert_return (invoke "funcref-elem" (i32.const 1)) (i32.const 0)) (invoke "deinit") +(assert_return (invoke "nullref-elem" (i32.const 0)) (i32.const 1)) (assert_return (invoke "anyref-elem" (i32.const 0)) (i32.const 1)) (assert_return (invoke "funcref-elem" (i32.const 0)) (i32.const 1)) +(assert_return (invoke "nullref-elem" (i32.const 0)) (i32.const 1)) (assert_return (invoke "anyref-elem" (i32.const 1)) (i32.const 1)) (assert_return (invoke "funcref-elem" (i32.const 1)) (i32.const 1)) diff --git a/test/core/ref_null.wast b/test/core/ref_null.wast index 30384802be..96cac314ad 100644 --- a/test/core/ref_null.wast +++ b/test/core/ref_null.wast @@ -1,10 +1,13 @@ (module (func (export "anyref") (result anyref) (ref.null)) (func (export "funcref") (result funcref) (ref.null)) + (func (export "nullref") (result nullref) (ref.null)) (global anyref (ref.null)) (global funcref (ref.null)) + (global nullref (ref.null)) ) (assert_return (invoke "anyref") (ref.null)) (assert_return (invoke "funcref") (ref.null)) +(assert_return (invoke "nullref") (ref.null)) diff --git a/test/core/select.wast b/test/core/select.wast index 33b7f6246c..090b052b6c 100644 --- a/test/core/select.wast +++ b/test/core/select.wast @@ -29,6 +29,12 @@ (func (export "select-f64-t") (param f64 f64 i32) (result f64) (select (result f64) (local.get 0) (local.get 1) (local.get 2)) ) + (func (export "select-nullref") (param nullref nullref i32) (result nullref) + (select (result nullref) (local.get 0) (local.get 1) (local.get 2)) + ) + (func (export "select-funcref") (param funcref funcref i32) (result funcref) + (select (result funcref) (local.get 0) (local.get 1) (local.get 2)) + ) (func (export "select-anyref") (param anyref anyref i32) (result anyref) (select (result anyref) (local.get 0) (local.get 1) (local.get 2)) ) @@ -244,6 +250,8 @@ (assert_return (invoke "select-i64-t" (i64.const 2) (i64.const 1) (i32.const 1)) (i64.const 2)) (assert_return (invoke "select-f32-t" (f32.const 1) (f32.const 2) (i32.const 1)) (f32.const 1)) (assert_return (invoke "select-f64-t" (f64.const 1) (f64.const 2) (i32.const 1)) (f64.const 1)) +(assert_return (invoke "select-nullref" (ref.null) (ref.null) (i32.const 1)) (ref.null)) +(assert_return (invoke "select-funcref" (ref.null) (ref.null) (i32.const 1)) (ref.null)) (assert_return (invoke "select-anyref" (ref.host 1) (ref.host 2) (i32.const 1)) (ref.host 1)) (assert_return (invoke "select-i32-t" (i32.const 1) (i32.const 2) (i32.const 0)) (i32.const 2)) From 82be3c0f6108ecf1f67fca81886cd46fa5fd483c Mon Sep 17 00:00:00 2001 From: Lars T Hansen Date: Mon, 16 Dec 2019 09:16:27 +0100 Subject: [PATCH 136/199] New segment encoding (#130) * Fix outdated stuff * Update Overview.md * Update Overview.md * Update Overview.md * Clarify zero table index * Address review comments --- proposals/bulk-memory-operations/Overview.md | 202 +++++++++---------- 1 file changed, 97 insertions(+), 105 deletions(-) diff --git a/proposals/bulk-memory-operations/Overview.md b/proposals/bulk-memory-operations/Overview.md index a743504599..74849a037c 100644 --- a/proposals/bulk-memory-operations/Overview.md +++ b/proposals/bulk-memory-operations/Overview.md @@ -45,11 +45,11 @@ the following contents: ```wasm (func (param $dst i32) (param $src i32) (param $size i32) (result i32) - get_local $dst - get_local $src - get_local $size + local.get $dst + local.get $src + local.get $size memory.copy - get_local $dst) + local.get $dst) ``` Here are the results on my machine (x86_64, 2.9GHz, L1 32k, L2 256k, L3 256k): @@ -160,8 +160,6 @@ Filling a memory region can be accomplished with `memory.fill`: * `memory.fill`: fill a region of linear memory with a given byte value -TODO: should we provide `memory.clear` and `table.clear` instead? - The [binary format for the data section](https://webassembly.github.io/spec/core/binary/modules.html#binary-datasec) currently has a collection of segments, each of which has a memory index, an @@ -171,9 +169,10 @@ Since WebAssembly currently does not allow for multiple memories, the memory index of each segment must be zero. We can repurpose this 32-bit integer as a flags field where new meaning is attached to nonzero values. -When the new flags field is `1`, this segment is _passive_. A passive segment -will not be automatically copied into the memory or table on instantiation, and -must instead be applied manually using the following new instructions: +When the low bit of the new flags field is `1`, this segment is _passive_. A +passive segment will not be automatically copied into the memory or table on +instantiation, and must instead be applied manually using the following new +instructions: * `memory.init`: copy a region from a data segment * `table.init`: copy a region from an element segment @@ -181,83 +180,100 @@ must instead be applied manually using the following new instructions: A passive segment has no initializer expression, since it will be specified as an operand to `memory.init` or `table.init`. -Segments can also be discarded by using the following new instructions: +Segments can also be shrunk to size zero by using the following new instructions: -* `data.drop`: prevent further use of a data segment -* `elem.drop`: prevent further use of an element segment +* `data.drop`: discard the data in an data segment +* `elem.drop`: discard the data in an element segment An active segment is equivalent to a passive segment, but with an implicit `memory.init` followed by a `data.drop` (or `table.init` followed by a `elem.drop`) that is prepended to the module's start function. -The new encoding of a data segment is now: +Additionally, the reference-types proposal introduces the notion of a function +reference (a function whose address is a program value). To support this, +element segments can have several encodings, and can also be used to +forward-declare functions whose address will be taken; see below. + +The reference-types proposal also introduces the bulk instructions `table.fill` +and `table.grow`, both of which take a function reference as an initializer +argument. + +### Data segments + +The meaning of the bits of the flag field (a `varuint32`) for data segments is: + +| Bit | Meaning | +| - | - | +| 0 | 0=is active, 1=is passive | +| 1 | if bit 0 clear: 0=memory 0, 1=has memory index | + +which yields this view, with the fields carried by each flag value: -| Field | Type | Present? | Description | -| - | - | - | - | -| flags | `varuint32` | always | Flags for passive and presence of fields below, only values of 0, 1, and 2 are valid | -| index | `varuint32`? | flags = 2 | Memory index; 0 if the field is not present | -| offset | `init_expr`? | flags != 1 | an `i32` initializer expression for offset | -| size | `varuint32` | always | size of `data` (in bytes) | -| data | `bytes` | always | sequence of `size` bytes | +| Flags | Meaning | Memory index | Offset in memory | Count | Payload | +| - | - | - | - | - | - | +| 0 | Active | | `init_expr` | `varuint32` | `u8`* | +| 1 | Passive | | | `varuint32` | `u8`* | +| 2 | Active with memory index | `varuint32` | `init_expr` | `varuint32` | `u8`* | -Another way of looking at it: +All other flag values are illegal. At present the memory index must be zero, +but the upcoming multi-memory proposal changes that. -| Flags | Active? | index | offset | -| - | - | - | - | -| 0 | Active | Always 0 | Present | -| 1 | Passive | - | - | -| 2 | Active | Present | Present | ### Element segments -The new binary format for element segments is similar to the new format for data segments, but -also includes an element type when the segment is passive. A passive segment also has a sequence -of `expr`s instead of function indices. +The meaning of the bits of the flag field (a `varuint32`) for element segments is: -| Field | Type | Present? | Description | -| - | - | - | - | -| flags | `varuint32` | always | Flags for passive and presence of fields below, only values of 0, 1, and 2 are valid | -| index | `varuint32`? | flags = 2 | Table index; 0 if the field is not present | -| element_type | `elem_type`? | flags = 1 | element type of this segment; `anyfunc` if not present | -| offset | `init_expr`? | flags != 1 | an `i32` initializer expression for offset | -| count | `varuint32` | always | number of elements | -| elems | `varuint32*` | flags != 1 | sequence of function indices | -| elems | `elem_expr*` | flags = 1 | sequence of element expressions | +| Bit | Meaning | +| - | - | +| 0 | 0=is active, 1=is passive | +| 1 | if bit 0 clear: 0=table 0, 1=has table index | +| | if bit 0 set: 0=active, 1=declared | +| 2 | 0=carries indicies; 1=carries elemexprs | -Another way of looking at it: +which yields this view, with the fields carried by each flag value: -| Flags | Active? | index | element_type | offset | -| - | - | - | - | - | -| 0 | Active | Always 0 | Always `anyfunc` | Present | -| 1 | Passive | - | Present | - | -| 2 | Active | Present | Always `anyfunc` | Present | +| Flag | Meaning | Table index | Offset in table | Encoding | Count | Payload | +| - | - | - | - | - | - | - | +| 0 | Legacy active, funcref externval | | `init_expr` | | `varuint32` | `idx`* | +| 1 | Passive, externval | | | `extern_kind` | `varuint32` | `idx`* | +| 2 | Active, externval | `varuint32` | `init_expr` | `extern_kind` | `varuint32` | `idx`* | +| 3 | Declared, externval | | | `extern_kind` | `varuint32` | `idx`* | +| 4 | Legacy active, funcref elemexpr | | `init_expr` | | `varuint32` | `elem_expr`* | +| 5 | Passive, elemexpr | | | `elem_type` | `varuint32` | `elem_expr`* | +| 6 | Active, elemexpr | `varuint32` | `init_expr` | `elem_type` | `varuint32` | `elem_expr`* | +| 7 | Declared, elemexpr | | | `elem_type` | `varuint32` | `elem_expr`* | + +All other flag values are illegal. Note that the "declared" attribute +is not used by this proposal, but is used by the reference-types +proposal. + +The `extern_kind` must be zero, signifying a function definition. An `idx` is a +`varuint32` that references an entity in the module, currently only its function +table. + +At present the table index must be zero, but the reference-types +proposal introduces a notion of multiple tables. An `elem_expr` is like an `init_expr`, but can only contain expressions of the following sequences: -| Binary | Text | Description | -| - | - | - | -| `0xd0 0x0b` | `ref.null end` | Returns a null reference | +| Binary | Text | Description | +| - | - | - | +| `0xd0 0x0b` | `ref.null end` | Returns a null reference | | `0xd2 varuint32 0x0b` | `ref.func $funcidx end` | Returns a reference to function `$funcidx` | -TODO: coordinate with other proposals to determine the binary encoding for `ref.null` and `ref.func`. - ### Segment Initialization In the MVP, segments are initialized during module instantiation. If any segment would be initialized out-of-bounds, then the memory or table instance is not modified. -This behavior is changed in the bulk memory proposal. - -Each active segment is initialized in module-definition order. For each -segment, each byte in the data segment is copied into the memory, in order of -lowest to highest addresses. If, for a given byte, the copy is out-of-bounds, -instantiation fails and no further bytes in this segment nor further segments -are copied. Bytes written before this point stay written. +This behavior is changed in the bulk memory proposal: -The behavior of element segment initialization is changed similarly, with the -difference that elements are copied from element segments into tables, instead -of bytes being copied from data segments into memories. +Each active segment is initialized in module-definition order. For +each segment, if reading the source or writing the destination would +go out of bounds, then instantiation fails at that point. Data that +had already been written for previous (in-bounds) segments stays +written. ### `memory.init` instruction @@ -273,41 +289,27 @@ The instruction has the signature `[i32 i32 i32] -> []`. The parameters are, in It is a validation error to use `memory.init` with an out-of-bounds segment index. A trap occurs if: + * the source offset plus size is greater than the length of the source data segment; this includes the case that the segment has been dropped via `data.drop` * the destination offset plus size is greater than the length of the target memory +The order of writing is unspecified, though this is currently unobservable. + Note that it is allowed to use `memory.init` on the same data segment more than once. -Initialization takes place bytewise from lower addresses toward higher -addresses. A trap resulting from an access outside the source data -segment or target memory only occurs once the first byte that is -outside the source or target is reached. Bytes written before the -trap stay written. - -(Data are read and written as-if individual bytes were read and -written, but various optimizations are possible that avoid reading and -writing only individual bytes.) - -Note that the semantics require bytewise accesses, so a trap that -might result from, say, reading a sequence of several words before -writing any, will have to be handled carefully: the reads that -succeeded will have to be written, if possible. - ### `data.drop` instruction -The `data.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 `memory.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. +The `data.drop` instruction shrinks the size of the segment to zero. After a +data segment has been dropped, it can still be used in a `memory.init` +instruction, but only a zero-length access at offset zero will not trap. 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. It is a validation error to use `data.drop` with an out-of-bounds segment index. -A trap occurs if the segment was already dropped. This includes active segments -that were dropped after being copied into memory during module instantiation. - ### `memory.copy` instruction Copy data from a source memory region to destination region. The @@ -336,17 +338,11 @@ The instruction has the signature `[i32 i32 i32] -> []`. The parameters are, in - top-0: size of memory region in bytes A trap occurs if: + * the source offset plus size is greater than the length of the source memory * the destination offset plus size is greater than the length of the target memory -A trap resulting from an access outside the source or target region -only occurs once the first byte that is outside the source or target -is reached (in the defined copy order). Bytes written before the trap -stay written. - -(Data are read and written as-if individual bytes were read and -written, but various optimizations are possible that avoid reading and -writing only individual bytes.) +The bounds check is performed before any data are written. ### `memory.fill` instruction @@ -360,15 +356,11 @@ The instruction has the signature `[i32 i32 i32] -> []`. The parameters are, in - top-0: size of memory region in bytes A trap occurs if: -* the destination offset plus size is greater than the length of the target memory -Filling takes place bytewise from lower addresses toward higher -addresses. A trap resulting from an access outside the target memory -only occurs once the first byte that is outside the target is reached. -Bytes written before the trap stay written. +* the destination offset plus size is greater than the length of the target memory + +The bounds check is performed before any data are written. -(Data are written as-if individual bytes were written, but various -optimizations are possible that avoid writing only individual bytes.) ### `table.init`, `elem.drop`, and `table.copy` instructions @@ -390,7 +382,7 @@ implemented as follows: (data passive "goodbye") ;; data segment 1, is passive (func $start - (if (get_global 0) + (if (global.get 0) ;; copy data segment 1 into memory 0 (the 0 is implicit) (memory.init 1 @@ -416,13 +408,13 @@ instr ::= ... | Name | Opcode | Immediate | Description | | ---- | ---- | ---- | ---- | -| `memory.init` | `0xfc 0x08` | `segment:varuint32`, `memory:0x00` | :thinking: copy from a passive data segment to linear memory | -| `data.drop` | `0xfc 0x09` | `segment:varuint32` | :thinking: prevent further use of passive data segment | -| `memory.copy` | `0xfc 0x0a` | `memory_dst:0x00` `memory_src:0x00` | :thinking: copy from one region of linear memory to another region | -| `memory.fill` | `0xfc 0x0b` | `memory:0x00` | :thinking: fill a region of linear memory with a given byte value | -| `table.init` | `0xfc 0x0c` | `segment:varuint32`, `table:0x00` | :thinking: copy from a passive element segment to a table | -| `elem.drop` | `0xfc 0x0d` | `segment:varuint32` | :thinking: prevent further use of a passive element segment | -| `table.copy` | `0xfc 0x0e` | `table_dst:0x00` `table_src:0x00` | :thinking: copy from one region of a table to another region | +| `memory.init` | `0xfc 0x08` | `segment:varuint32`, `memory:0x00` | copy from a passive data segment to linear memory | +| `data.drop` | `0xfc 0x09` | `segment:varuint32` | prevent further use of passive data segment | +| `memory.copy` | `0xfc 0x0a` | `memory_dst:0x00` `memory_src:0x00` | copy from one region of linear memory to another region | +| `memory.fill` | `0xfc 0x0b` | `memory:0x00` | fill a region of linear memory with a given byte value | +| `table.init` | `0xfc 0x0c` | `segment:varuint32`, `table:0x00` | copy from a passive element segment to a table | +| `elem.drop` | `0xfc 0x0d` | `segment:varuint32` | prevent further use of a passive element segment | +| `table.copy` | `0xfc 0x0e` | `table_dst:0x00` `table_src:0x00` | copy from one region of a table to another region | ### `DataCount` section From a00705b66dcd9a4cbe5194e7c85d78ea327738cd Mon Sep 17 00:00:00 2001 From: Heejin Ahn Date: Mon, 16 Dec 2019 01:06:33 -0800 Subject: [PATCH 137/199] Delete mentions of copying order in Overview.md (#134) After the spec change in #126, byte copying order is not observable. --- proposals/bulk-memory-operations/Overview.md | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) diff --git a/proposals/bulk-memory-operations/Overview.md b/proposals/bulk-memory-operations/Overview.md index 74849a037c..09fd953c30 100644 --- a/proposals/bulk-memory-operations/Overview.md +++ b/proposals/bulk-memory-operations/Overview.md @@ -320,16 +320,8 @@ written (by the copy operation) in the other region. This instruction has two immediate arguments: the source and destination memory indices. They currently both must be zero. -If the source region starts at a lower address than the target region, then the -copy takes place as if from higher to lower addresses: the highest source -address is read first and the value is written to the highest target address, -then the next highest, and so on. Otherwise, the copy takes place as if from -lower to higher addresses: the lowest source address is read first and the -value is written to the lowest target address, then the next lowest, and so on. - -(The direction of the copy is defined in order to future-proof -`memory.copy` for shared memory and a memory read/write protection -feature.) +Copying takes place as if an intermediate buffer were used, allowing the +destination and source to overlap. The instruction has the signature `[i32 i32 i32] -> []`. The parameters are, in order: From e383b993db02ac4d8e61521afaa2d5ccf07d5606 Mon Sep 17 00:00:00 2001 From: Andreas Rossberg Date: Fri, 10 Jan 2020 18:03:01 +0100 Subject: [PATCH 138/199] Rebase on bulk proposal (#65) Lots of merge conflicts to resolve. I hope I didn't screw up... --- README.md | 4 +- document/core/appendix/index-instructions.rst | 408 +- document/core/appendix/index-rules.rst | 6 + document/core/appendix/properties.rst | 169 +- document/core/binary/conventions.rst | 3 + document/core/binary/instructions.rst | 29 +- document/core/binary/modules.rst | 127 +- document/core/exec/conventions.rst | 2 +- document/core/exec/instructions.rst | 553 +- document/core/exec/modules.rst | 232 +- document/core/exec/runtime.rst | 73 +- document/core/index.rst | 2 +- document/core/syntax/conventions.rst | 4 + document/core/syntax/instructions.rst | 22 +- document/core/syntax/modules.rst | 73 +- document/core/text/conventions.rst | 4 + document/core/text/instructions.rst | 18 +- document/core/text/modules.rst | 97 +- document/core/util/macros.def | 80 +- document/core/valid/conventions.rst | 4 + document/core/valid/instructions.rst | 131 +- document/core/valid/modules.rst | 116 +- interpreter/README.md | 7 + interpreter/binary/decode.ml | 148 +- interpreter/binary/encode.ml | 91 +- interpreter/exec/eval.ml | 283 +- interpreter/runtime/instance.ml | 8 +- interpreter/runtime/memory.ml | 1 + interpreter/runtime/memory.mli | 1 + interpreter/runtime/table.ml | 24 + interpreter/runtime/table.mli | 6 + interpreter/syntax/ast.ml | 47 +- interpreter/syntax/free.ml | 140 + interpreter/syntax/free.mli | 34 + interpreter/syntax/operators.ml | 14 +- interpreter/syntax/values.ml | 11 + interpreter/text/arrange.ml | 62 +- interpreter/text/lexer.mll | 13 +- interpreter/text/parser.mly | 140 +- interpreter/util/lib.ml | 5 + interpreter/util/lib.mli | 1 + interpreter/util/source.ml | 1 + interpreter/util/source.mli | 1 + interpreter/valid/valid.ml | 84 +- proposals/bulk-memory-operations/Overview.md | 469 ++ test/core/binary.wast | 331 +- test/core/bulk.wast | 307 + test/core/custom.wast | 10 + test/core/data.wast | 88 +- test/core/elem.wast | 122 +- test/core/imports.wast | 8 +- test/core/linking.wast | 40 +- test/core/memory_copy.wast | 5577 +++++++++++++++++ test/core/memory_fill.wast | 685 ++ test/core/memory_init.wast | 951 +++ test/core/ref_is_null.wast | 3 +- test/core/table_copy.wast | 1595 +++++ test/core/table_fill.wast | 4 +- test/core/table_get.wast | 3 +- test/core/table_init.wast | 1752 ++++++ test/core/table_set.wast | 3 +- test/meta/Makefile | 32 + test/meta/README.md | 1 + test/meta/common.js | 28 + test/meta/generate_memory_copy.js | 768 +++ test/meta/generate_memory_fill.js | 157 + test/meta/generate_memory_init.js | 294 + test/meta/generate_table_copy.js | 317 + test/meta/generate_table_init.js | 338 + test/meta/noderun.sh | 16 + 70 files changed, 16378 insertions(+), 800 deletions(-) create mode 100644 interpreter/syntax/free.ml create mode 100644 interpreter/syntax/free.mli create mode 100644 proposals/bulk-memory-operations/Overview.md create mode 100644 test/core/bulk.wast create mode 100644 test/core/memory_copy.wast create mode 100644 test/core/memory_fill.wast create mode 100644 test/core/memory_init.wast create mode 100644 test/core/table_copy.wast create mode 100644 test/core/table_init.wast create mode 100644 test/meta/Makefile create mode 100644 test/meta/README.md create mode 100644 test/meta/common.js create mode 100644 test/meta/generate_memory_copy.js create mode 100644 test/meta/generate_memory_fill.js create mode 100644 test/meta/generate_memory_init.js create mode 100644 test/meta/generate_table_copy.js create mode 100644 test/meta/generate_table_init.js create mode 100755 test/meta/noderun.sh diff --git a/README.md b/README.md index 226bb1d847..cb024e63f0 100644 --- a/README.md +++ b/README.md @@ -9,7 +9,9 @@ It is meant for discussion, prototype specification and implementation of a prop * See the [modified spec](https://webassembly.github.io/reference-types/core/) for details. -Original `README` from upstream repository follows... +The repository is now based on the [bulk operations proposal](proposals/bulk-memory-operations/Overview.md) and includes all respective changes. + +Original README from upstream repository follows... # spec diff --git a/document/core/appendix/index-instructions.rst b/document/core/appendix/index-instructions.rst index 394a98e504..e94643a94b 100644 --- a/document/core/appendix/index-instructions.rst +++ b/document/core/appendix/index-instructions.rst @@ -4,201 +4,201 @@ Index of Instructions --------------------- -====================================== ================ ========================================== ======================================== =============================================================== -Instruction Binary Opcode Type Validation Execution -====================================== ================ ========================================== ======================================== =============================================================== -:math:`\UNREACHABLE` :math:`\hex{00}` :math:`[t_1^\ast] \to [t_2^\ast]` :ref:`validation ` :ref:`execution ` -:math:`\NOP` :math:`\hex{01}` :math:`[] \to []` :ref:`validation ` :ref:`execution ` -:math:`\BLOCK~[t^?]` :math:`\hex{02}` :math:`[] \to [t^\ast]` :ref:`validation ` :ref:`execution ` -:math:`\LOOP~[t^?]` :math:`\hex{03}` :math:`[] \to [t^\ast]` :ref:`validation ` :ref:`execution ` -:math:`\IF~[t^?]` :math:`\hex{04}` :math:`[\I32] \to [t^\ast]` :ref:`validation ` :ref:`execution ` -:math:`\ELSE` :math:`\hex{05}` -(reserved) :math:`\hex{06}` -(reserved) :math:`\hex{07}` -(reserved) :math:`\hex{08}` -(reserved) :math:`\hex{09}` -(reserved) :math:`\hex{0A}` -:math:`\END` :math:`\hex{0B}` -:math:`\BR~l` :math:`\hex{0C}` :math:`[t_1^\ast~t^?] \to [t_2^\ast]` :ref:`validation ` :ref:`execution ` -:math:`\BRIF~l` :math:`\hex{0D}` :math:`[t^?~\I32] \to [t^?]` :ref:`validation ` :ref:`execution ` -:math:`\BRTABLE~l^\ast~l` :math:`\hex{0E}` :math:`[t_1^\ast~t^?~\I32] \to [t_2^\ast]` :ref:`validation ` :ref:`execution ` -:math:`\RETURN` :math:`\hex{0F}` :math:`[t_1^\ast~t^?] \to [t_2^\ast]` :ref:`validation ` :ref:`execution ` -:math:`\CALL~x` :math:`\hex{10}` :math:`[t_1^\ast] \to [t_2^\ast]` :ref:`validation ` :ref:`execution ` -:math:`\CALLINDIRECT~x` :math:`\hex{11}` :math:`[t_1^\ast~\I32] \to [t_2^\ast]` :ref:`validation ` :ref:`execution ` -(reserved) :math:`\hex{12}` -(reserved) :math:`\hex{13}` -(reserved) :math:`\hex{14}` -(reserved) :math:`\hex{15}` -(reserved) :math:`\hex{16}` -(reserved) :math:`\hex{17}` -(reserved) :math:`\hex{18}` -(reserved) :math:`\hex{19}` -:math:`\DROP` :math:`\hex{1A}` :math:`[t] \to []` :ref:`validation ` :ref:`execution ` -:math:`\SELECT` :math:`\hex{1B}` :math:`[t~t~\I32] \to [t]` :ref:`validation ` :ref:`execution ` -:math:`\SELECT~t` :math:`\hex{1C}` :math:`[t~t~\I32] \to [t]` :ref:`validation ` :ref:`execution ` -(reserved) :math:`\hex{1D}` -(reserved) :math:`\hex{1E}` -(reserved) :math:`\hex{1F}` -:math:`\LOCALGET~x` :math:`\hex{20}` :math:`[] \to [t]` :ref:`validation ` :ref:`execution ` -:math:`\LOCALSET~x` :math:`\hex{21}` :math:`[t] \to []` :ref:`validation ` :ref:`execution ` -:math:`\LOCALTEE~x` :math:`\hex{22}` :math:`[t] \to [t]` :ref:`validation ` :ref:`execution ` -:math:`\GLOBALGET~x` :math:`\hex{23}` :math:`[] \to [t]` :ref:`validation ` :ref:`execution ` -:math:`\GLOBALSET~x` :math:`\hex{24}` :math:`[t] \to []` :ref:`validation ` :ref:`execution ` -:math:`\TABLEGET~x` :math:`\hex{25}` :math:`[\I32] \to [t]` :ref:`validation ` :ref:`execution ` -:math:`\TABLESET~x` :math:`\hex{26}` :math:`[\I32~t] \to []` :ref:`validation ` :ref:`execution ` -(reserved) :math:`\hex{27}` -:math:`\I32.\LOAD~\memarg` :math:`\hex{28}` :math:`[\I32] \to [\I32]` :ref:`validation ` :ref:`execution ` -:math:`\I64.\LOAD~\memarg` :math:`\hex{29}` :math:`[\I32] \to [\I64]` :ref:`validation ` :ref:`execution ` -:math:`\F32.\LOAD~\memarg` :math:`\hex{2A}` :math:`[\I32] \to [\F32]` :ref:`validation ` :ref:`execution ` -:math:`\F64.\LOAD~\memarg` :math:`\hex{2B}` :math:`[\I32] \to [\F64]` :ref:`validation ` :ref:`execution ` -:math:`\I32.\LOAD\K{8\_s}~\memarg` :math:`\hex{2C}` :math:`[\I32] \to [\I32]` :ref:`validation ` :ref:`execution ` -:math:`\I32.\LOAD\K{8\_u}~\memarg` :math:`\hex{2D}` :math:`[\I32] \to [\I32]` :ref:`validation ` :ref:`execution ` -:math:`\I32.\LOAD\K{16\_s}~\memarg` :math:`\hex{2E}` :math:`[\I32] \to [\I32]` :ref:`validation ` :ref:`execution ` -:math:`\I32.\LOAD\K{16\_u}~\memarg` :math:`\hex{2F}` :math:`[\I32] \to [\I32]` :ref:`validation ` :ref:`execution ` -:math:`\I64.\LOAD\K{8\_s}~\memarg` :math:`\hex{30}` :math:`[\I32] \to [\I64]` :ref:`validation ` :ref:`execution ` -:math:`\I64.\LOAD\K{8\_u}~\memarg` :math:`\hex{31}` :math:`[\I32] \to [\I64]` :ref:`validation ` :ref:`execution ` -:math:`\I64.\LOAD\K{16\_s}~\memarg` :math:`\hex{32}` :math:`[\I32] \to [\I64]` :ref:`validation ` :ref:`execution ` -:math:`\I64.\LOAD\K{16\_u}~\memarg` :math:`\hex{33}` :math:`[\I32] \to [\I64]` :ref:`validation ` :ref:`execution ` -:math:`\I64.\LOAD\K{32\_s}~\memarg` :math:`\hex{34}` :math:`[\I32] \to [\I64]` :ref:`validation ` :ref:`execution ` -:math:`\I64.\LOAD\K{32\_u}~\memarg` :math:`\hex{35}` :math:`[\I32] \to [\I64]` :ref:`validation ` :ref:`execution ` -:math:`\I32.\STORE~\memarg` :math:`\hex{36}` :math:`[\I32~\I32] \to []` :ref:`validation ` :ref:`execution ` -:math:`\I64.\STORE~\memarg` :math:`\hex{37}` :math:`[\I32~\I64] \to []` :ref:`validation ` :ref:`execution ` -:math:`\F32.\STORE~\memarg` :math:`\hex{38}` :math:`[\I32~\F32] \to []` :ref:`validation ` :ref:`execution ` -:math:`\F64.\STORE~\memarg` :math:`\hex{39}` :math:`[\I32~\F64] \to []` :ref:`validation ` :ref:`execution ` -:math:`\I32.\STORE\K{8}~\memarg` :math:`\hex{3A}` :math:`[\I32~\I32] \to []` :ref:`validation ` :ref:`execution ` -:math:`\I32.\STORE\K{16}~\memarg` :math:`\hex{3B}` :math:`[\I32~\I32] \to []` :ref:`validation ` :ref:`execution ` -:math:`\I64.\STORE\K{8}~\memarg` :math:`\hex{3C}` :math:`[\I32~\I64] \to []` :ref:`validation ` :ref:`execution ` -:math:`\I64.\STORE\K{16}~\memarg` :math:`\hex{3D}` :math:`[\I32~\I64] \to []` :ref:`validation ` :ref:`execution ` -:math:`\I64.\STORE\K{32}~\memarg` :math:`\hex{3E}` :math:`[\I32~\I64] \to []` :ref:`validation ` :ref:`execution ` -:math:`\MEMORYSIZE` :math:`\hex{3F}` :math:`[] \to [\I32]` :ref:`validation ` :ref:`execution ` -:math:`\MEMORYGROW` :math:`\hex{40}` :math:`[\I32] \to [\I32]` :ref:`validation ` :ref:`execution ` -:math:`\I32.\CONST~\i32` :math:`\hex{41}` :math:`[] \to [\I32]` :ref:`validation ` :ref:`execution ` -:math:`\I64.\CONST~\i64` :math:`\hex{42}` :math:`[] \to [\I64]` :ref:`validation ` :ref:`execution ` -:math:`\F32.\CONST~\f32` :math:`\hex{43}` :math:`[] \to [\F32]` :ref:`validation ` :ref:`execution ` -:math:`\F64.\CONST~\f64` :math:`\hex{44}` :math:`[] \to [\F64]` :ref:`validation ` :ref:`execution ` -:math:`\I32.\EQZ` :math:`\hex{45}` :math:`[\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I32.\EQ` :math:`\hex{46}` :math:`[\I32~\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I32.\NE` :math:`\hex{47}` :math:`[\I32~\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I32.\LT\K{\_s}` :math:`\hex{48}` :math:`[\I32~\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I32.\LT\K{\_u}` :math:`\hex{49}` :math:`[\I32~\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I32.\GT\K{\_s}` :math:`\hex{4A}` :math:`[\I32~\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I32.\GT\K{\_u}` :math:`\hex{4B}` :math:`[\I32~\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I32.\LE\K{\_s}` :math:`\hex{4C}` :math:`[\I32~\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I32.\LE\K{\_u}` :math:`\hex{4D}` :math:`[\I32~\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I32.\GE\K{\_s}` :math:`\hex{4E}` :math:`[\I32~\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I32.\GE\K{\_u}` :math:`\hex{4F}` :math:`[\I32~\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I64.\EQZ` :math:`\hex{50}` :math:`[\I64] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I64.\EQ` :math:`\hex{51}` :math:`[\I64~\I64] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I64.\NE` :math:`\hex{52}` :math:`[\I64~\I64] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I64.\LT\K{\_s}` :math:`\hex{53}` :math:`[\I64~\I64] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I64.\LT\K{\_u}` :math:`\hex{54}` :math:`[\I64~\I64] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I64.\GT\K{\_s}` :math:`\hex{55}` :math:`[\I64~\I64] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I64.\GT\K{\_u}` :math:`\hex{56}` :math:`[\I64~\I64] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I64.\LE\K{\_s}` :math:`\hex{57}` :math:`[\I64~\I64] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I64.\LE\K{\_u}` :math:`\hex{58}` :math:`[\I64~\I64] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I64.\GE\K{\_s}` :math:`\hex{59}` :math:`[\I64~\I64] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I64.\GE\K{\_u}` :math:`\hex{5A}` :math:`[\I64~\I64] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F32.\EQ` :math:`\hex{5B}` :math:`[\F32~\F32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F32.\NE` :math:`\hex{5C}` :math:`[\F32~\F32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F32.\LT` :math:`\hex{5D}` :math:`[\F32~\F32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F32.\GT` :math:`\hex{5E}` :math:`[\F32~\F32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F32.\LE` :math:`\hex{5F}` :math:`[\F32~\F32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F32.\GE` :math:`\hex{60}` :math:`[\F32~\F32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F64.\EQ` :math:`\hex{61}` :math:`[\F64~\F64] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F64.\NE` :math:`\hex{62}` :math:`[\F64~\F64] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F64.\LT` :math:`\hex{63}` :math:`[\F64~\F64] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F64.\GT` :math:`\hex{64}` :math:`[\F64~\F64] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F64.\LE` :math:`\hex{65}` :math:`[\F64~\F64] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F64.\GE` :math:`\hex{66}` :math:`[\F64~\F64] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I32.\CLZ` :math:`\hex{67}` :math:`[\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I32.\CTZ` :math:`\hex{68}` :math:`[\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I32.\POPCNT` :math:`\hex{69}` :math:`[\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I32.\ADD` :math:`\hex{6A}` :math:`[\I32~\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I32.\SUB` :math:`\hex{6B}` :math:`[\I32~\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I32.\MUL` :math:`\hex{6C}` :math:`[\I32~\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I32.\DIV\K{\_s}` :math:`\hex{6D}` :math:`[\I32~\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I32.\DIV\K{\_u}` :math:`\hex{6E}` :math:`[\I32~\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I32.\REM\K{\_s}` :math:`\hex{6F}` :math:`[\I32~\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I32.\REM\K{\_u}` :math:`\hex{70}` :math:`[\I32~\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I32.\AND` :math:`\hex{71}` :math:`[\I32~\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I32.\OR` :math:`\hex{72}` :math:`[\I32~\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I32.\XOR` :math:`\hex{73}` :math:`[\I32~\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I32.\SHL` :math:`\hex{74}` :math:`[\I32~\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I32.\SHR\K{\_s}` :math:`\hex{75}` :math:`[\I32~\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I32.\SHR\K{\_u}` :math:`\hex{76}` :math:`[\I32~\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I32.\ROTL` :math:`\hex{77}` :math:`[\I32~\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I32.\ROTR` :math:`\hex{78}` :math:`[\I32~\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I64.\CLZ` :math:`\hex{79}` :math:`[\I64] \to [\I64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I64.\CTZ` :math:`\hex{7A}` :math:`[\I64] \to [\I64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I64.\POPCNT` :math:`\hex{7B}` :math:`[\I64] \to [\I64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I64.\ADD` :math:`\hex{7C}` :math:`[\I64~\I64] \to [\I64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I64.\SUB` :math:`\hex{7D}` :math:`[\I64~\I64] \to [\I64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I64.\MUL` :math:`\hex{7E}` :math:`[\I64~\I64] \to [\I64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I64.\DIV\K{\_s}` :math:`\hex{7F}` :math:`[\I64~\I64] \to [\I64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I64.\DIV\K{\_u}` :math:`\hex{80}` :math:`[\I64~\I64] \to [\I64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I64.\REM\K{\_s}` :math:`\hex{81}` :math:`[\I64~\I64] \to [\I64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I64.\REM\K{\_u}` :math:`\hex{82}` :math:`[\I64~\I64] \to [\I64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I64.\AND` :math:`\hex{83}` :math:`[\I64~\I64] \to [\I64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I64.\OR` :math:`\hex{84}` :math:`[\I64~\I64] \to [\I64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I64.\XOR` :math:`\hex{85}` :math:`[\I64~\I64] \to [\I64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I64.\SHL` :math:`\hex{86}` :math:`[\I64~\I64] \to [\I64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I64.\SHR\K{\_s}` :math:`\hex{87}` :math:`[\I64~\I64] \to [\I64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I64.\SHR\K{\_u}` :math:`\hex{88}` :math:`[\I64~\I64] \to [\I64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I64.\ROTL` :math:`\hex{89}` :math:`[\I64~\I64] \to [\I64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I64.\ROTR` :math:`\hex{8A}` :math:`[\I64~\I64] \to [\I64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F32.\ABS` :math:`\hex{8B}` :math:`[\F32] \to [\F32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F32.\NEG` :math:`\hex{8C}` :math:`[\F32] \to [\F32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F32.\CEIL` :math:`\hex{8D}` :math:`[\F32] \to [\F32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F32.\FLOOR` :math:`\hex{8E}` :math:`[\F32] \to [\F32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F32.\TRUNC` :math:`\hex{8F}` :math:`[\F32] \to [\F32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F32.\NEAREST` :math:`\hex{90}` :math:`[\F32] \to [\F32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F32.\SQRT` :math:`\hex{91}` :math:`[\F32] \to [\F32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F32.\ADD` :math:`\hex{92}` :math:`[\F32~\F32] \to [\F32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F32.\SUB` :math:`\hex{93}` :math:`[\F32~\F32] \to [\F32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F32.\MUL` :math:`\hex{94}` :math:`[\F32~\F32] \to [\F32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F32.\DIV` :math:`\hex{95}` :math:`[\F32~\F32] \to [\F32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F32.\FMIN` :math:`\hex{96}` :math:`[\F32~\F32] \to [\F32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F32.\FMAX` :math:`\hex{97}` :math:`[\F32~\F32] \to [\F32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F32.\COPYSIGN` :math:`\hex{98}` :math:`[\F32~\F32] \to [\F32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F64.\ABS` :math:`\hex{99}` :math:`[\F64] \to [\F64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F64.\NEG` :math:`\hex{9A}` :math:`[\F64] \to [\F64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F64.\CEIL` :math:`\hex{9B}` :math:`[\F64] \to [\F64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F64.\FLOOR` :math:`\hex{9C}` :math:`[\F64] \to [\F64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F64.\TRUNC` :math:`\hex{9D}` :math:`[\F64] \to [\F64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F64.\NEAREST` :math:`\hex{9E}` :math:`[\F64] \to [\F64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F64.\SQRT` :math:`\hex{9F}` :math:`[\F64] \to [\F64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F64.\ADD` :math:`\hex{A0}` :math:`[\F64~\F64] \to [\F64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F64.\SUB` :math:`\hex{A1}` :math:`[\F64~\F64] \to [\F64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F64.\MUL` :math:`\hex{A2}` :math:`[\F64~\F64] \to [\F64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F64.\DIV` :math:`\hex{A3}` :math:`[\F64~\F64] \to [\F64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F64.\FMIN` :math:`\hex{A4}` :math:`[\F64~\F64] \to [\F64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F64.\FMAX` :math:`\hex{A5}` :math:`[\F64~\F64] \to [\F64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F64.\COPYSIGN` :math:`\hex{A6}` :math:`[\F64~\F64] \to [\F64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I32.\WRAP\K{\_}\I64` :math:`\hex{A7}` :math:`[\I64] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I32.\TRUNC\K{\_}\F32\K{\_s}` :math:`\hex{A8}` :math:`[\F32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I32.\TRUNC\K{\_}\F32\K{\_u}` :math:`\hex{A9}` :math:`[\F32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I32.\TRUNC\K{\_}\F64\K{\_s}` :math:`\hex{AA}` :math:`[\F64] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I32.\TRUNC\K{\_}\F64\K{\_u}` :math:`\hex{AB}` :math:`[\F64] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I64.\EXTEND\K{\_}\I32\K{\_s}` :math:`\hex{AC}` :math:`[\I32] \to [\I64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I64.\EXTEND\K{\_}\I32\K{\_u}` :math:`\hex{AD}` :math:`[\I32] \to [\I64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I64.\TRUNC\K{\_}\F32\K{\_s}` :math:`\hex{AE}` :math:`[\F32] \to [\I64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I64.\TRUNC\K{\_}\F32\K{\_u}` :math:`\hex{AF}` :math:`[\F32] \to [\I64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I64.\TRUNC\K{\_}\F64\K{\_s}` :math:`\hex{B0}` :math:`[\F64] \to [\I64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I64.\TRUNC\K{\_}\F64\K{\_u}` :math:`\hex{B1}` :math:`[\F64] \to [\I64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F32.\CONVERT\K{\_}\I32\K{\_s}` :math:`\hex{B2}` :math:`[\I32] \to [\F32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F32.\CONVERT\K{\_}\I32\K{\_u}` :math:`\hex{B3}` :math:`[\I32] \to [\F32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F32.\CONVERT\K{\_}\I64\K{\_s}` :math:`\hex{B4}` :math:`[\I64] \to [\F32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F32.\CONVERT\K{\_}\I64\K{\_u}` :math:`\hex{B5}` :math:`[\I64] \to [\F32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F32.\DEMOTE\K{\_}\F64` :math:`\hex{B6}` :math:`[\F64] \to [\F32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F64.\CONVERT\K{\_}\I32\K{\_s}` :math:`\hex{B7}` :math:`[\I32] \to [\F64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F64.\CONVERT\K{\_}\I32\K{\_u}` :math:`\hex{B8}` :math:`[\I32] \to [\F64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F64.\CONVERT\K{\_}\I64\K{\_s}` :math:`\hex{B9}` :math:`[\I64] \to [\F64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F64.\CONVERT\K{\_}\I64\K{\_u}` :math:`\hex{BA}` :math:`[\I64] \to [\F64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F64.\PROMOTE\K{\_}\F32` :math:`\hex{BB}` :math:`[\F32] \to [\F64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I32.\REINTERPRET\K{\_}\F32` :math:`\hex{BC}` :math:`[\F32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I64.\REINTERPRET\K{\_}\F64` :math:`\hex{BD}` :math:`[\F64] \to [\I64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F32.\REINTERPRET\K{\_}\I32` :math:`\hex{BE}` :math:`[\I32] \to [\F32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F64.\REINTERPRET\K{\_}\I64` :math:`\hex{BF}` :math:`[\I64] \to [\F64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +====================================== ================== ========================================== ======================================== =============================================================== +Instruction Binary Opcode Type Validation Execution +====================================== ================== ========================================== ======================================== =============================================================== +:math:`\UNREACHABLE` :math:`\hex{00}` :math:`[t_1^\ast] \to [t_2^\ast]` :ref:`validation ` :ref:`execution ` +:math:`\NOP` :math:`\hex{01}` :math:`[] \to []` :ref:`validation ` :ref:`execution ` +:math:`\BLOCK~[t^?]` :math:`\hex{02}` :math:`[] \to [t^\ast]` :ref:`validation ` :ref:`execution ` +:math:`\LOOP~[t^?]` :math:`\hex{03}` :math:`[] \to [t^\ast]` :ref:`validation ` :ref:`execution ` +:math:`\IF~[t^?]` :math:`\hex{04}` :math:`[\I32] \to [t^\ast]` :ref:`validation ` :ref:`execution ` +:math:`\ELSE` :math:`\hex{05}` +(reserved) :math:`\hex{06}` +(reserved) :math:`\hex{07}` +(reserved) :math:`\hex{08}` +(reserved) :math:`\hex{09}` +(reserved) :math:`\hex{0A}` +:math:`\END` :math:`\hex{0B}` +:math:`\BR~l` :math:`\hex{0C}` :math:`[t_1^\ast~t^?] \to [t_2^\ast]` :ref:`validation ` :ref:`execution ` +:math:`\BRIF~l` :math:`\hex{0D}` :math:`[t^?~\I32] \to [t^?]` :ref:`validation ` :ref:`execution ` +:math:`\BRTABLE~l^\ast~l` :math:`\hex{0E}` :math:`[t_1^\ast~t^?~\I32] \to [t_2^\ast]` :ref:`validation ` :ref:`execution ` +:math:`\RETURN` :math:`\hex{0F}` :math:`[t_1^\ast~t^?] \to [t_2^\ast]` :ref:`validation ` :ref:`execution ` +:math:`\CALL~x` :math:`\hex{10}` :math:`[t_1^\ast] \to [t_2^\ast]` :ref:`validation ` :ref:`execution ` +:math:`\CALLINDIRECT~x` :math:`\hex{11}` :math:`[t_1^\ast~\I32] \to [t_2^\ast]` :ref:`validation ` :ref:`execution ` +(reserved) :math:`\hex{12}` +(reserved) :math:`\hex{13}` +(reserved) :math:`\hex{14}` +(reserved) :math:`\hex{15}` +(reserved) :math:`\hex{16}` +(reserved) :math:`\hex{17}` +(reserved) :math:`\hex{18}` +(reserved) :math:`\hex{19}` +:math:`\DROP` :math:`\hex{1A}` :math:`[t] \to []` :ref:`validation ` :ref:`execution ` +:math:`\SELECT` :math:`\hex{1B}` :math:`[t~t~\I32] \to [t]` :ref:`validation ` :ref:`execution ` +:math:`\SELECT~t` :math:`\hex{1C}` :math:`[t~t~\I32] \to [t]` :ref:`validation ` :ref:`execution ` +(reserved) :math:`\hex{1D}` +(reserved) :math:`\hex{1E}` +(reserved) :math:`\hex{1F}` +:math:`\LOCALGET~x` :math:`\hex{20}` :math:`[] \to [t]` :ref:`validation ` :ref:`execution ` +:math:`\LOCALSET~x` :math:`\hex{21}` :math:`[t] \to []` :ref:`validation ` :ref:`execution ` +:math:`\LOCALTEE~x` :math:`\hex{22}` :math:`[t] \to [t]` :ref:`validation ` :ref:`execution ` +:math:`\GLOBALGET~x` :math:`\hex{23}` :math:`[] \to [t]` :ref:`validation ` :ref:`execution ` +:math:`\GLOBALSET~x` :math:`\hex{24}` :math:`[t] \to []` :ref:`validation ` :ref:`execution ` ++:math:`\TABLEGET~x` :math:`\hex{25}` :math:`[\I32] \to [t]` :ref:`validation ` :ref:`execution ` ++:math:`\TABLESET~x` :math:`\hex{26}` :math:`[\I32~t] \to []` :ref:`validation ` :ref:`execution ` +(reserved) :math:`\hex{27}` +:math:`\I32.\LOAD~\memarg` :math:`\hex{28}` :math:`[\I32] \to [\I32]` :ref:`validation ` :ref:`execution ` +:math:`\I64.\LOAD~\memarg` :math:`\hex{29}` :math:`[\I32] \to [\I64]` :ref:`validation ` :ref:`execution ` +:math:`\F32.\LOAD~\memarg` :math:`\hex{2A}` :math:`[\I32] \to [\F32]` :ref:`validation ` :ref:`execution ` +:math:`\F64.\LOAD~\memarg` :math:`\hex{2B}` :math:`[\I32] \to [\F64]` :ref:`validation ` :ref:`execution ` +:math:`\I32.\LOAD\K{8\_s}~\memarg` :math:`\hex{2C}` :math:`[\I32] \to [\I32]` :ref:`validation ` :ref:`execution ` +:math:`\I32.\LOAD\K{8\_u}~\memarg` :math:`\hex{2D}` :math:`[\I32] \to [\I32]` :ref:`validation ` :ref:`execution ` +:math:`\I32.\LOAD\K{16\_s}~\memarg` :math:`\hex{2E}` :math:`[\I32] \to [\I32]` :ref:`validation ` :ref:`execution ` +:math:`\I32.\LOAD\K{16\_u}~\memarg` :math:`\hex{2F}` :math:`[\I32] \to [\I32]` :ref:`validation ` :ref:`execution ` +:math:`\I64.\LOAD\K{8\_s}~\memarg` :math:`\hex{30}` :math:`[\I32] \to [\I64]` :ref:`validation ` :ref:`execution ` +:math:`\I64.\LOAD\K{8\_u}~\memarg` :math:`\hex{31}` :math:`[\I32] \to [\I64]` :ref:`validation ` :ref:`execution ` +:math:`\I64.\LOAD\K{16\_s}~\memarg` :math:`\hex{32}` :math:`[\I32] \to [\I64]` :ref:`validation ` :ref:`execution ` +:math:`\I64.\LOAD\K{16\_u}~\memarg` :math:`\hex{33}` :math:`[\I32] \to [\I64]` :ref:`validation ` :ref:`execution ` +:math:`\I64.\LOAD\K{32\_s}~\memarg` :math:`\hex{34}` :math:`[\I32] \to [\I64]` :ref:`validation ` :ref:`execution ` +:math:`\I64.\LOAD\K{32\_u}~\memarg` :math:`\hex{35}` :math:`[\I32] \to [\I64]` :ref:`validation ` :ref:`execution ` +:math:`\I32.\STORE~\memarg` :math:`\hex{36}` :math:`[\I32~\I32] \to []` :ref:`validation ` :ref:`execution ` +:math:`\I64.\STORE~\memarg` :math:`\hex{37}` :math:`[\I32~\I64] \to []` :ref:`validation ` :ref:`execution ` +:math:`\F32.\STORE~\memarg` :math:`\hex{38}` :math:`[\I32~\F32] \to []` :ref:`validation ` :ref:`execution ` +:math:`\F64.\STORE~\memarg` :math:`\hex{39}` :math:`[\I32~\F64] \to []` :ref:`validation ` :ref:`execution ` +:math:`\I32.\STORE\K{8}~\memarg` :math:`\hex{3A}` :math:`[\I32~\I32] \to []` :ref:`validation ` :ref:`execution ` +:math:`\I32.\STORE\K{16}~\memarg` :math:`\hex{3B}` :math:`[\I32~\I32] \to []` :ref:`validation ` :ref:`execution ` +:math:`\I64.\STORE\K{8}~\memarg` :math:`\hex{3C}` :math:`[\I32~\I64] \to []` :ref:`validation ` :ref:`execution ` +:math:`\I64.\STORE\K{16}~\memarg` :math:`\hex{3D}` :math:`[\I32~\I64] \to []` :ref:`validation ` :ref:`execution ` +:math:`\I64.\STORE\K{32}~\memarg` :math:`\hex{3E}` :math:`[\I32~\I64] \to []` :ref:`validation ` :ref:`execution ` +:math:`\MEMORYSIZE` :math:`\hex{3F}` :math:`[] \to [\I32]` :ref:`validation ` :ref:`execution ` +:math:`\MEMORYGROW` :math:`\hex{40}` :math:`[\I32] \to [\I32]` :ref:`validation ` :ref:`execution ` +:math:`\I32.\CONST~\i32` :math:`\hex{41}` :math:`[] \to [\I32]` :ref:`validation ` :ref:`execution ` +:math:`\I64.\CONST~\i64` :math:`\hex{42}` :math:`[] \to [\I64]` :ref:`validation ` :ref:`execution ` +:math:`\F32.\CONST~\f32` :math:`\hex{43}` :math:`[] \to [\F32]` :ref:`validation ` :ref:`execution ` +:math:`\F64.\CONST~\f64` :math:`\hex{44}` :math:`[] \to [\F64]` :ref:`validation ` :ref:`execution ` +:math:`\I32.\EQZ` :math:`\hex{45}` :math:`[\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I32.\EQ` :math:`\hex{46}` :math:`[\I32~\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I32.\NE` :math:`\hex{47}` :math:`[\I32~\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I32.\LT\K{\_s}` :math:`\hex{48}` :math:`[\I32~\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I32.\LT\K{\_u}` :math:`\hex{49}` :math:`[\I32~\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I32.\GT\K{\_s}` :math:`\hex{4A}` :math:`[\I32~\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I32.\GT\K{\_u}` :math:`\hex{4B}` :math:`[\I32~\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I32.\LE\K{\_s}` :math:`\hex{4C}` :math:`[\I32~\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I32.\LE\K{\_u}` :math:`\hex{4D}` :math:`[\I32~\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I32.\GE\K{\_s}` :math:`\hex{4E}` :math:`[\I32~\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I32.\GE\K{\_u}` :math:`\hex{4F}` :math:`[\I32~\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I64.\EQZ` :math:`\hex{50}` :math:`[\I64] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I64.\EQ` :math:`\hex{51}` :math:`[\I64~\I64] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I64.\NE` :math:`\hex{52}` :math:`[\I64~\I64] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I64.\LT\K{\_s}` :math:`\hex{53}` :math:`[\I64~\I64] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I64.\LT\K{\_u}` :math:`\hex{54}` :math:`[\I64~\I64] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I64.\GT\K{\_s}` :math:`\hex{55}` :math:`[\I64~\I64] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I64.\GT\K{\_u}` :math:`\hex{56}` :math:`[\I64~\I64] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I64.\LE\K{\_s}` :math:`\hex{57}` :math:`[\I64~\I64] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I64.\LE\K{\_u}` :math:`\hex{58}` :math:`[\I64~\I64] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I64.\GE\K{\_s}` :math:`\hex{59}` :math:`[\I64~\I64] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I64.\GE\K{\_u}` :math:`\hex{5A}` :math:`[\I64~\I64] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\F32.\EQ` :math:`\hex{5B}` :math:`[\F32~\F32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\F32.\NE` :math:`\hex{5C}` :math:`[\F32~\F32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\F32.\LT` :math:`\hex{5D}` :math:`[\F32~\F32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\F32.\GT` :math:`\hex{5E}` :math:`[\F32~\F32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\F32.\LE` :math:`\hex{5F}` :math:`[\F32~\F32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\F32.\GE` :math:`\hex{60}` :math:`[\F32~\F32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\F64.\EQ` :math:`\hex{61}` :math:`[\F64~\F64] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\F64.\NE` :math:`\hex{62}` :math:`[\F64~\F64] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\F64.\LT` :math:`\hex{63}` :math:`[\F64~\F64] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\F64.\GT` :math:`\hex{64}` :math:`[\F64~\F64] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\F64.\LE` :math:`\hex{65}` :math:`[\F64~\F64] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\F64.\GE` :math:`\hex{66}` :math:`[\F64~\F64] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I32.\CLZ` :math:`\hex{67}` :math:`[\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I32.\CTZ` :math:`\hex{68}` :math:`[\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I32.\POPCNT` :math:`\hex{69}` :math:`[\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I32.\ADD` :math:`\hex{6A}` :math:`[\I32~\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I32.\SUB` :math:`\hex{6B}` :math:`[\I32~\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I32.\MUL` :math:`\hex{6C}` :math:`[\I32~\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I32.\DIV\K{\_s}` :math:`\hex{6D}` :math:`[\I32~\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I32.\DIV\K{\_u}` :math:`\hex{6E}` :math:`[\I32~\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I32.\REM\K{\_s}` :math:`\hex{6F}` :math:`[\I32~\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I32.\REM\K{\_u}` :math:`\hex{70}` :math:`[\I32~\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I32.\AND` :math:`\hex{71}` :math:`[\I32~\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I32.\OR` :math:`\hex{72}` :math:`[\I32~\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I32.\XOR` :math:`\hex{73}` :math:`[\I32~\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I32.\SHL` :math:`\hex{74}` :math:`[\I32~\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I32.\SHR\K{\_s}` :math:`\hex{75}` :math:`[\I32~\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I32.\SHR\K{\_u}` :math:`\hex{76}` :math:`[\I32~\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I32.\ROTL` :math:`\hex{77}` :math:`[\I32~\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I32.\ROTR` :math:`\hex{78}` :math:`[\I32~\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I64.\CLZ` :math:`\hex{79}` :math:`[\I64] \to [\I64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I64.\CTZ` :math:`\hex{7A}` :math:`[\I64] \to [\I64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I64.\POPCNT` :math:`\hex{7B}` :math:`[\I64] \to [\I64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I64.\ADD` :math:`\hex{7C}` :math:`[\I64~\I64] \to [\I64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I64.\SUB` :math:`\hex{7D}` :math:`[\I64~\I64] \to [\I64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I64.\MUL` :math:`\hex{7E}` :math:`[\I64~\I64] \to [\I64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I64.\DIV\K{\_s}` :math:`\hex{7F}` :math:`[\I64~\I64] \to [\I64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I64.\DIV\K{\_u}` :math:`\hex{80}` :math:`[\I64~\I64] \to [\I64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I64.\REM\K{\_s}` :math:`\hex{81}` :math:`[\I64~\I64] \to [\I64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I64.\REM\K{\_u}` :math:`\hex{82}` :math:`[\I64~\I64] \to [\I64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I64.\AND` :math:`\hex{83}` :math:`[\I64~\I64] \to [\I64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I64.\OR` :math:`\hex{84}` :math:`[\I64~\I64] \to [\I64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I64.\XOR` :math:`\hex{85}` :math:`[\I64~\I64] \to [\I64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I64.\SHL` :math:`\hex{86}` :math:`[\I64~\I64] \to [\I64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I64.\SHR\K{\_s}` :math:`\hex{87}` :math:`[\I64~\I64] \to [\I64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I64.\SHR\K{\_u}` :math:`\hex{88}` :math:`[\I64~\I64] \to [\I64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I64.\ROTL` :math:`\hex{89}` :math:`[\I64~\I64] \to [\I64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I64.\ROTR` :math:`\hex{8A}` :math:`[\I64~\I64] \to [\I64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\F32.\ABS` :math:`\hex{8B}` :math:`[\F32] \to [\F32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\F32.\NEG` :math:`\hex{8C}` :math:`[\F32] \to [\F32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\F32.\CEIL` :math:`\hex{8D}` :math:`[\F32] \to [\F32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\F32.\FLOOR` :math:`\hex{8E}` :math:`[\F32] \to [\F32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\F32.\TRUNC` :math:`\hex{8F}` :math:`[\F32] \to [\F32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\F32.\NEAREST` :math:`\hex{90}` :math:`[\F32] \to [\F32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\F32.\SQRT` :math:`\hex{91}` :math:`[\F32] \to [\F32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\F32.\ADD` :math:`\hex{92}` :math:`[\F32~\F32] \to [\F32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\F32.\SUB` :math:`\hex{93}` :math:`[\F32~\F32] \to [\F32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\F32.\MUL` :math:`\hex{94}` :math:`[\F32~\F32] \to [\F32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\F32.\DIV` :math:`\hex{95}` :math:`[\F32~\F32] \to [\F32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\F32.\FMIN` :math:`\hex{96}` :math:`[\F32~\F32] \to [\F32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\F32.\FMAX` :math:`\hex{97}` :math:`[\F32~\F32] \to [\F32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\F32.\COPYSIGN` :math:`\hex{98}` :math:`[\F32~\F32] \to [\F32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\F64.\ABS` :math:`\hex{99}` :math:`[\F64] \to [\F64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\F64.\NEG` :math:`\hex{9A}` :math:`[\F64] \to [\F64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\F64.\CEIL` :math:`\hex{9B}` :math:`[\F64] \to [\F64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\F64.\FLOOR` :math:`\hex{9C}` :math:`[\F64] \to [\F64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\F64.\TRUNC` :math:`\hex{9D}` :math:`[\F64] \to [\F64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\F64.\NEAREST` :math:`\hex{9E}` :math:`[\F64] \to [\F64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\F64.\SQRT` :math:`\hex{9F}` :math:`[\F64] \to [\F64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\F64.\ADD` :math:`\hex{A0}` :math:`[\F64~\F64] \to [\F64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\F64.\SUB` :math:`\hex{A1}` :math:`[\F64~\F64] \to [\F64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\F64.\MUL` :math:`\hex{A2}` :math:`[\F64~\F64] \to [\F64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\F64.\DIV` :math:`\hex{A3}` :math:`[\F64~\F64] \to [\F64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\F64.\FMIN` :math:`\hex{A4}` :math:`[\F64~\F64] \to [\F64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\F64.\FMAX` :math:`\hex{A5}` :math:`[\F64~\F64] \to [\F64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\F64.\COPYSIGN` :math:`\hex{A6}` :math:`[\F64~\F64] \to [\F64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I32.\WRAP\K{\_}\I64` :math:`\hex{A7}` :math:`[\I64] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I32.\TRUNC\K{\_}\F32\K{\_s}` :math:`\hex{A8}` :math:`[\F32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I32.\TRUNC\K{\_}\F32\K{\_u}` :math:`\hex{A9}` :math:`[\F32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I32.\TRUNC\K{\_}\F64\K{\_s}` :math:`\hex{AA}` :math:`[\F64] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I32.\TRUNC\K{\_}\F64\K{\_u}` :math:`\hex{AB}` :math:`[\F64] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I64.\EXTEND\K{\_}\I32\K{\_s}` :math:`\hex{AC}` :math:`[\I32] \to [\I64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I64.\EXTEND\K{\_}\I32\K{\_u}` :math:`\hex{AD}` :math:`[\I32] \to [\I64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I64.\TRUNC\K{\_}\F32\K{\_s}` :math:`\hex{AE}` :math:`[\F32] \to [\I64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I64.\TRUNC\K{\_}\F32\K{\_u}` :math:`\hex{AF}` :math:`[\F32] \to [\I64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I64.\TRUNC\K{\_}\F64\K{\_s}` :math:`\hex{B0}` :math:`[\F64] \to [\I64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I64.\TRUNC\K{\_}\F64\K{\_u}` :math:`\hex{B1}` :math:`[\F64] \to [\I64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\F32.\CONVERT\K{\_}\I32\K{\_s}` :math:`\hex{B2}` :math:`[\I32] \to [\F32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\F32.\CONVERT\K{\_}\I32\K{\_u}` :math:`\hex{B3}` :math:`[\I32] \to [\F32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\F32.\CONVERT\K{\_}\I64\K{\_s}` :math:`\hex{B4}` :math:`[\I64] \to [\F32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\F32.\CONVERT\K{\_}\I64\K{\_u}` :math:`\hex{B5}` :math:`[\I64] \to [\F32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\F32.\DEMOTE\K{\_}\F64` :math:`\hex{B6}` :math:`[\F64] \to [\F32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\F64.\CONVERT\K{\_}\I32\K{\_s}` :math:`\hex{B7}` :math:`[\I32] \to [\F64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\F64.\CONVERT\K{\_}\I32\K{\_u}` :math:`\hex{B8}` :math:`[\I32] \to [\F64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\F64.\CONVERT\K{\_}\I64\K{\_s}` :math:`\hex{B9}` :math:`[\I64] \to [\F64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\F64.\CONVERT\K{\_}\I64\K{\_u}` :math:`\hex{BA}` :math:`[\I64] \to [\F64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\F64.\PROMOTE\K{\_}\F32` :math:`\hex{BB}` :math:`[\F32] \to [\F64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I32.\REINTERPRET\K{\_}\F32` :math:`\hex{BC}` :math:`[\F32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I64.\REINTERPRET\K{\_}\F64` :math:`\hex{BD}` :math:`[\F64] \to [\I64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\F32.\REINTERPRET\K{\_}\I32` :math:`\hex{BE}` :math:`[\I32] \to [\F32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\F64.\REINTERPRET\K{\_}\I64` :math:`\hex{BF}` :math:`[\I64] \to [\F64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` (reserved) :math:`\hex{C0}` (reserved) :math:`\hex{C1}` (reserved) :math:`\hex{C2}` @@ -215,7 +215,17 @@ Instruction Binary Opcode Type (reserved) :math:`\hex{CD}` (reserved) :math:`\hex{CE}` (reserved) :math:`\hex{CF}` -:math:`\REFNULL` :math:`\hex{D0}` :math:`[] \to [\NULLREF]` :ref:`validation ` :ref:`execution ` -:math:`\REFISNULL` :math:`\hex{D1}` :math:`[\ANYREF] \to [\I32]` :ref:`validation ` :ref:`execution ` -:math:`\REFFUNC~x` :math:`\hex{D2}` :math:`[] \to [\FUNCREF]` :ref:`validation ` :ref:`execution ` -====================================== ================ ========================================== ======================================== =============================================================== +:math:`\REFNULL` :math:`\hex{D0}` :math:`[] \to [\NULLREF]` :ref:`validation ` :ref:`execution ` +:math:`\REFISNULL` :math:`\hex{D1}` :math:`[\ANYREF] \to [\I32]` :ref:`validation ` :ref:`execution ` +:math:`\REFFUNC~x` :math:`\hex{D2}` :math:`[] \to [\FUNCREF]` :ref:`validation ` :ref:`execution ` +:math:`\MEMORYINIT` :math:`\hex{FC08}` :math:`[\I32~\I32~\I32] \to []` :ref:`validation ` :ref:`execution ` +:math:`\DATADROP` :math:`\hex{FC09}` :math:`[] \to []` :ref:`validation ` :ref:`execution ` +:math:`\MEMORYCOPY` :math:`\hex{FC0A}` :math:`[\I32~\I32~\I32] \to []` :ref:`validation ` :ref:`execution ` +:math:`\MEMORYFILL` :math:`\hex{FC0B}` :math:`[\I32~\I32~\I32] \to []` :ref:`validation ` :ref:`execution ` +:math:`\TABLEINIT` :math:`\hex{FC0C}` :math:`[\I32~\I32~\I32] \to []` :ref:`validation ` :ref:`execution ` +:math:`\ELEMDROP` :math:`\hex{FC0D}` :math:`[] \to []` :ref:`validation ` :ref:`execution ` +:math:`\TABLECOPY` :math:`\hex{FC0E}` :math:`[\I32~\I32~\I32] \to []` :ref:`validation ` :ref:`execution ` +:math:`\TABLEGROW` :math:`\hex{FC0F}` :math:`[t~\I32] \to []` :ref:`validation ` :ref:`execution ` +:math:`\TABLESIZE` :math:`\hex{FC10}` :math:`[] \to []` :ref:`validation ` :ref:`execution ` +:math:`\TABLEFILL` :math:`\hex{FC11}` :math:`[\I32~t~\I32] \to []` :ref:`validation ` :ref:`execution ` +====================================== ================== ========================================== ======================================== =============================================================== diff --git a/document/core/appendix/index-rules.rst b/document/core/appendix/index-rules.rst index fe1fb3f2ff..4d3db62f16 100644 --- a/document/core/appendix/index-rules.rst +++ b/document/core/appendix/index-rules.rst @@ -27,7 +27,9 @@ Construct Judgement :ref:`Memory ` :math:`C \vdashmem \mem : \memtype` :ref:`Global ` :math:`C \vdashglobal \global : \globaltype` :ref:`Element segment ` :math:`C \vdashelem \elem \ok` +:ref:`Element mode ` :math:`C \vdashelemmode \elemmode \ok` :ref:`Data segment ` :math:`C \vdashdata \data \ok` +:ref:`Data mode ` :math:`C \vdashdatamode \datamode \ok` :ref:`Start function ` :math:`C \vdashstart \start \ok` :ref:`Export ` :math:`C \vdashexport \export : \externtype` :ref:`Export description ` :math:`C \vdashexportdesc \exportdesc : \externtype` @@ -52,6 +54,8 @@ Construct Judgement :ref:`Table instance ` :math:`S \vdashtableinst \tableinst : \tabletype` :ref:`Memory instance ` :math:`S \vdashmeminst \meminst : \memtype` :ref:`Global instance ` :math:`S \vdashglobalinst \globalinst : \globaltype` +:ref:`Element instance ` :math:`S \vdasheleminst \eleminst \ok` +:ref:`Data instance ` :math:`S \vdashdatainst \datainst \ok` :ref:`Export instance ` :math:`S \vdashexportinst \exportinst \ok` :ref:`Module instance ` :math:`S \vdashmoduleinst \moduleinst : C` :ref:`Store ` :math:`\vdashstore \store \ok` @@ -97,6 +101,8 @@ Construct Judgement :ref:`Table instance ` :math:`\vdashtableinstextends \tableinst_1 \extendsto \tableinst_2` :ref:`Memory instance ` :math:`\vdashmeminstextends \meminst_1 \extendsto \meminst_2` :ref:`Global instance ` :math:`\vdashglobalinstextends \globalinst_1 \extendsto \globalinst_2` +:ref:`Element instance ` :math:`\vdasheleminstextends \eleminst_1 \extendsto \eleminst_2` +:ref:`Data instance ` :math:`\vdashdatainstextends \datainst_1 \extendsto \datainst_2` :ref:`Store ` :math:`\vdashstoreextends \store_1 \extendsto \store_2` =============================================== =============================================================================== diff --git a/document/core/appendix/properties.rst b/document/core/appendix/properties.rst index 490e2c5545..9956e528be 100644 --- a/document/core/appendix/properties.rst +++ b/document/core/appendix/properties.rst @@ -87,6 +87,10 @@ Module instances are classified by *module contexts*, which are regular :ref:`co * Each :ref:`global instance ` :math:`\globalinst_i` in :math:`S.\SGLOBALS` must be :ref:`valid ` with some :ref:`global type ` :math:`\globaltype_i`. +* Each :ref:`element instance ` :math:`\eleminst_i` in :math:`S.\SELEMS` must be :ref:`valid `. + +* Each :ref:`data instance ` :math:`\datainst_i` in :math:`S.\SDATAS` must be :ref:`valid `. + * Then the store is valid. .. math:: @@ -101,11 +105,17 @@ Module instances are classified by *module contexts*, which are regular :ref:`co \qquad (S \vdashglobalinst \globalinst : \globaltype)^\ast \\ + (S \vdasheleminst \eleminst \ok)^\ast + \qquad + (S \vdashdatainst \datainst \ok)^\ast + \\ S = \{ \SFUNCS~\funcinst^\ast, \STABLES~\tableinst^\ast, \SMEMS~\meminst^\ast, - \SGLOBALS~\globalinst^\ast \} + \SGLOBALS~\globalinst^\ast, + \SELEMS~\eleminst^\ast, + \SDATAS~\datainst^\ast \} \end{array} }{ \vdashstore S \ok @@ -203,7 +213,7 @@ Module instances are classified by *module contexts*, which are regular :ref:`co * The length of :math:`\reff^\ast` must equal :math:`\limits.\LMIN`. -* For each :ref:`reference ` :math:`\reff_i` in the table elements :math:`\reff^n`: +* For each :ref:`reference ` :math:`\reff_i` in the table's elements :math:`\reff^n`: * The :ref:`reference ` :math:`\reff_i` must be :ref:`valid ` with some :ref:`reference type ` :math:`t'_i`. @@ -273,6 +283,47 @@ Module instances are classified by *module contexts*, which are regular :ref:`co } +.. index:: element instance, reference +.. _valid-eleminst: + +.. todo:: TODO: adjust elem instances + +:ref:`Element Instances ` :math:`\{ \EIELEM~\X{fa}^\ast \}` +............................................................................ + +* For each :ref:`reference ` :math:`\reff_i` in the elements :math:`\reff^n`: + + * The :ref:`reference ` :math:`\reff_i` must be :ref:`valid ` with some :ref:`reference type ` :math:`t'_i`. + + * The :ref:`reference type ` :math:`t'_i` must :ref:`match ` the :ref:`reference type ` :math:`t`. + +* Then the table instance is valid. + +.. math:: + \frac{ + (S \vdash \reff : t')^\ast + \qquad + (\vdashreftypematch t' \matchesvaltype t)^n + }{ + S \vdasheleminst \{ \EITYPE~t, \EIELEM~\reff^\ast \} \ok + } + + +.. index:: data instance, byte +.. _valid-datainst: + +:ref:`Data Instances ` :math:`\{ \DIDATA~b^\ast \}` +.................................................................... + +* The data instance is valid. + +.. math:: + \frac{ + }{ + S \vdashdatainst \{ \DIDATA~b^\ast \} \ok + } + + .. index:: external type, export instance, name, external value .. _valid-exportinst: @@ -307,6 +358,10 @@ Module instances are classified by *module contexts*, which are regular :ref:`co * For each :ref:`global address ` :math:`\globaladdr_i` in :math:`\moduleinst.\MIGLOBALS`, the :ref:`external value ` :math:`\EVGLOBAL~\globaladdr_i` must be :ref:`valid ` with some :ref:`external type ` :math:`\ETGLOBAL~\globaltype_i`. +* For each :ref:`element address ` :math:`\elemaddr_i` in :math:`\moduleinst.\MIELEMS`, the :ref:`element instance ` :math:`S.\SELEMS[\elemaddr_i]` must be :ref:`valid `. + +* For each :ref:`data address ` :math:`\dataaddr_i` in :math:`\moduleinst.\MIDATAS`, the :ref:`data instance ` :math:`S.\SDATAS[\dataaddr_i]` must be :ref:`valid `. + * Each :ref:`export instance ` :math:`\exportinst_i` in :math:`\moduleinst.\MIEXPORTS` must be :ref:`valid `. * For each :ref:`export instance ` :math:`\exportinst_i` in :math:`\moduleinst.\MIEXPORTS`, the :ref:`name ` :math:`\exportinst_i.\EINAME` must be different from any other name occurring in :math:`\moduleinst.\MIEXPORTS`. @@ -335,6 +390,10 @@ Module instances are classified by *module contexts*, which are regular :ref:`co \qquad (S \vdashexternval \EVGLOBAL~\globaladdr : \ETGLOBAL~\globaltype)^\ast \\ + (S \vdasheleminst S.\SELEMS[\elemaddr] \ok)^\ast + \qquad + (S \vdashdatainst S.\SDATAS[\dataaddr] \ok)^\ast + \\ (S \vdashexportinst \exportinst \ok)^\ast \qquad (\exportinst.\EINAME)^\ast ~\mbox{disjoint} @@ -346,7 +405,9 @@ Module instances are classified by *module contexts*, which are regular :ref:`co \MIFUNCS & \funcaddr^\ast, \\ \MITABLES & \tableaddr^\ast, \\ \MIMEMS & \memaddr^\ast, \\ - \MIGLOBALS & \globaladdr^\ast \\ + \MIGLOBALS & \globaladdr^\ast, \\ + \MIELEMS & \elemaddr^\ast, \\ + \MIDATAS & \dataaddr^\ast, \\ \MIEXPORTS & \exportinst^\ast ~\} : \{ \begin{array}[t]{@{}l@{~}l@{}} \CTYPES & \functype^\ast, \\ @@ -524,54 +585,6 @@ To that end, all previous typing judgements :math:`C \vdash \X{prop}` are genera } -.. index:: element, table, table address, module instance, function index - -:math:`\INITELEM~\tableaddr~o~x^n` -.................................. - -* The :ref:`external table value ` :math:`\EVTABLE~\tableaddr` must be :ref:`valid ` with some :ref:`external table type ` :math:`\ETTABLE~(\limits~\FUNCREF)`. - -* The index :math:`o + n` must be smaller than or equal to :math:`\limits.\LMIN`. - -* The :ref:`module instance ` :math:`\moduleinst` must be :ref:`valid ` with some :ref:`context ` :math:`C`. - -* Each :ref:`function index ` :math:`x_i` in :math:`x^n` must be defined in the context :math:`C`. - -* Then the instruction is valid. - -.. math:: - \frac{ - S \vdashexternval \EVTABLE~\tableaddr : \ETTABLE~\limits~\FUNCREF - \qquad - o + n \leq \limits.\LMIN - \qquad - (C.\CFUNCS[x] = \functype)^n - }{ - S; C \vdashadmininstr \INITELEM~\tableaddr~o~x^n \ok - } - - -.. index:: data, memory, memory address, byte - -:math:`\INITDATA~\memaddr~o~b^n` -................................ - -* The :ref:`external memory value ` :math:`\EVMEM~\memaddr` must be :ref:`valid ` with some :ref:`external memory type ` :math:`\ETMEM~\limits`. - -* The index :math:`o + n` must be smaller than or equal to :math:`\limits.\LMIN` divided by the :ref:`page size ` :math:`64\,\F{Ki}`. - -* Then the instruction is valid. - -.. math:: - \frac{ - S \vdashexternval \EVMEM~\memaddr : \ETMEM~\limits - \qquad - o + n \leq \limits.\LMIN \cdot 64\,\F{Ki} - }{ - S; C \vdashadmininstr \INITDATA~\memaddr~o~b^n \ok - } - - .. index:: label, instruction, result type :math:`\LABEL_n\{\instr_0^\ast\}~\instr^\ast~\END` @@ -647,6 +660,10 @@ a store state :math:`S'` extends state :math:`S`, written :math:`S \extendsto S' * The length of :math:`S.\SGLOBALS` must not shrink. +* The length of :math:`S.\SELEMS` must not shrink. + +* The length of :math:`S.\SDATAS` must not shrink. + * For each :ref:`function instance ` :math:`\funcinst_i` in the original :math:`S.\SFUNCS`, the new function instance must be an :ref:`extension ` of the old. * For each :ref:`table instance ` :math:`\tableinst_i` in the original :math:`S.\STABLES`, the new table instance must be an :ref:`extension ` of the old. @@ -655,21 +672,31 @@ a store state :math:`S'` extends state :math:`S`, written :math:`S \extendsto S' * For each :ref:`global instance ` :math:`\globalinst_i` in the original :math:`S.\SGLOBALS`, the new global instance must be an :ref:`extension ` of the old. +* For each :ref:`element instance ` :math:`\eleminst_i` in the original :math:`S.\SELEMS`, the new global instance must be an :ref:`extension ` of the old. + +* For each :ref:`data instance ` :math:`\datainst_i` in the original :math:`S.\SDATAS`, the new global instance must be an :ref:`extension ` of the old. + .. math:: \frac{ \begin{array}{@{}ccc@{}} S_1.\SFUNCS = \funcinst_1^\ast & S_2.\SFUNCS = {\funcinst'_1}^\ast~\funcinst_2^\ast & - (\funcinst_1 \extendsto \funcinst'_1)^\ast \\ + (\vdashfuncinstextends \funcinst_1 \extendsto \funcinst'_1)^\ast \\ S_1.\STABLES = \tableinst_1^\ast & S_2.\STABLES = {\tableinst'_1}^\ast~\tableinst_2^\ast & - (\tableinst_1 \extendsto \tableinst'_1)^\ast \\ + (\vdashtableinstextends \tableinst_1 \extendsto \tableinst'_1)^\ast \\ S_1.\SMEMS = \meminst_1^\ast & S_2.\SMEMS = {\meminst'_1}^\ast~\meminst_2^\ast & - (\meminst_1 \extendsto \meminst'_1)^\ast \\ + (\vdashmeminstextends \meminst_1 \extendsto \meminst'_1)^\ast \\ S_1.\SGLOBALS = \globalinst_1^\ast & S_2.\SGLOBALS = {\globalinst'_1}^\ast~\globalinst_2^\ast & - (\globalinst_1 \extendsto \globalinst'_1)^\ast \\ + (\vdashglobalinstextends \globalinst_1 \extendsto \globalinst'_1)^\ast \\ + S_1.\SELEMS = \eleminst_1^\ast & + S_2.\SELEMS = {\eleminst'_1}^\ast~\eleminst_2^\ast & + (\vdasheleminstextends \eleminst_1 \extendsto \eleminst'_1)^\ast \\ + S_1.\SDATAS = \datainst_1^\ast & + S_2.\SDATAS = {\datainst'_1}^\ast~\datainst_2^\ast & + (\vdashdatainstextends \datainst_1 \extendsto \datainst'_1)^\ast \\ \end{array} }{ \vdashstoreextends S_1 \extendsto S_2 @@ -747,6 +774,38 @@ a store state :math:`S'` extends state :math:`S`, written :math:`S \extendsto S' } +.. index:: element instance +.. _extend-eleminst: + +:ref:`Element Instance ` :math:`\eleminst` +........................................................... + +* The vector :math:`\eleminst.\EIELEM` must either remain unchanged or shrink to length :math:`0`. + +.. math:: + \frac{ + \X{fa}_1^\ast = \X{fa}_2^\ast \vee \X{fa}_2^\ast = \epsilon + }{ + \vdasheleminstextends \{\EIELEM~\X{fa}_1^\ast\} \extendsto \{\EIELEM~\X{fa}_2^\ast\} + } + + +.. index:: data instance +.. _extend-datainst: + +:ref:`Data Instance ` :math:`\datainst` +........................................................ + +* The vector :math:`\datainst.\DIDATA` must either remain unchanged or shrink to length :math:`0`. + +.. math:: + \frac{ + b_1^\ast = b_2^\ast \vee b_2^\ast = \epsilon + }{ + \vdashdatainstextends \{\DIDATA~b_1^\ast\} \extendsto \{\DIDATA~b_2^\ast\} + } + + .. index:: ! preservation, ! progress, soundness, configuration, thread, terminal configuration, instantiation, invocation, validity, module .. _soundness-statement: diff --git a/document/core/binary/conventions.rst b/document/core/binary/conventions.rst index 8d38399773..cacd25134b 100644 --- a/document/core/binary/conventions.rst +++ b/document/core/binary/conventions.rst @@ -59,6 +59,9 @@ In order to distinguish symbols of the binary syntax from symbols of the abstrac * Some productions are augmented by side conditions in parentheses, which restrict the applicability of the production. They provide a shorthand for a combinatorial expansion of the production into many separate cases. +* If the same meta variable or non-terminal symbol appears multiple times in a production (in the syntax or in an attribute), then all those occurrences must have the same instantiation. + (This is a shorthand for a side condition requiring multiple different variables to be equal.) + .. note:: For example, the :ref:`binary grammar ` for :ref:`value types ` is given as follows: diff --git a/document/core/binary/instructions.rst b/document/core/binary/instructions.rst index 27deed05f5..84b6296bae 100644 --- a/document/core/binary/instructions.rst +++ b/document/core/binary/instructions.rst @@ -135,17 +135,19 @@ Variable Instructions .. index:: table instruction, table index pair: binary format; instruction .. _binary-instr-table: - -Table Instructions -~~~~~~~~~~~~~~~~~~ - -:ref:`Table instructions ` are represented by either single byte or two byte codes. - .. _binary-table.get: .. _binary-table.set: .. _binary-table.size: .. _binary-table.grow: .. _binary-table.fill: +.. _binary-table.copy: +.. _binary-table.init: +.. _binary-elem.drop: + +Table Instructions +~~~~~~~~~~~~~~~~~~ + +:ref:`Table instructions ` are represented by either single byte or two byte codes. .. math:: \begin{array}{llclll} @@ -155,6 +157,9 @@ Table Instructions \hex{FC}~\hex{0F}~~x{:}\Btableidx &\Rightarrow& \TABLEGROW~x \\ &&|& \hex{FC}~\hex{10}~~x{:}\Btableidx &\Rightarrow& \TABLESIZE~x \\ &&|& \hex{FC}~\hex{11}~~x{:}\Btableidx &\Rightarrow& \TABLEFILL~x \\ + \hex{FC}~\hex{0C}~~\hex{00}~x{:}\Belemidx &\Rightarrow& \TABLEINIT~x \\ &&|& + \hex{FC}~\hex{0D}~~x{:}\Belemidx &\Rightarrow& \ELEMDROP~x \\ &&|& + \hex{FC}~\hex{0E}~~\hex{00}~~\hex{00} &\Rightarrow& \TABLECOPY \\ \end{array} @@ -174,6 +179,10 @@ Each variant of :ref:`memory instruction ` is encoded with .. _binary-storen: .. _binary-memory.size: .. _binary-memory.grow: +.. _binary-memory.fill: +.. _binary-memory.copy: +.. _binary-memory.init: +.. _binary-data.drop: .. math:: \begin{array}{llclll} @@ -204,11 +213,15 @@ Each variant of :ref:`memory instruction ` is encoded with \hex{3D}~~m{:}\Bmemarg &\Rightarrow& \I64.\STORE\K{16}~m \\ &&|& \hex{3E}~~m{:}\Bmemarg &\Rightarrow& \I64.\STORE\K{32}~m \\ &&|& \hex{3F}~~\hex{00} &\Rightarrow& \MEMORYSIZE \\ &&|& - \hex{40}~~\hex{00} &\Rightarrow& \MEMORYGROW \\ + \hex{40}~~\hex{00} &\Rightarrow& \MEMORYGROW \\ &&|& + \hex{FC}~\hex{08}~~\hex{00}~x{:}\Bdataidx &\Rightarrow& \MEMORYINIT~x \\ &&|& + \hex{FC}~\hex{09}~~x{:}\Bdataidx &\Rightarrow& \DATADROP~x \\ &&|& + \hex{FC}~\hex{0A}~~\hex{00}~~\hex{00} &\Rightarrow& \MEMORYCOPY \\ &&|& + \hex{FC}~\hex{0B}~~\hex{00} &\Rightarrow& \MEMORYFILL \\ \end{array} .. note:: - In future versions of WebAssembly, the additional zero bytes occurring in the encoding of the |MEMORYSIZE| and |MEMORYGROW| instructions may be used to index additional memories. + In future versions of WebAssembly, the additional zero bytes occurring in the encoding of the |MEMORYSIZE|, |MEMORYGROW|, |MEMORYCOPY|, and |MEMORYFILL| instructions may be used to index additional memories. .. index:: numeric instruction diff --git a/document/core/binary/modules.rst b/document/core/binary/modules.rst index f7c36c9f21..e947fc30d1 100644 --- a/document/core/binary/modules.rst +++ b/document/core/binary/modules.rst @@ -9,12 +9,14 @@ except that :ref:`function definitions ` are split into two section This separation enables *parallel* and *streaming* compilation of the functions in a module. -.. index:: index, type index, function index, table index, memory index, global index, local index, label index +.. index:: index, type index, function index, table index, memory index, global index, element index, data index, local index, label index pair: binary format; type index pair: binary format; function index pair: binary format; table index pair: binary format; memory index pair: binary format; global index + pair: binary format; element index + pair: binary format; data index pair: binary format; local index pair: binary format; label index .. _binary-typeidx: @@ -22,6 +24,8 @@ except that :ref:`function definitions ` are split into two section .. _binary-tableidx: .. _binary-memidx: .. _binary-globalidx: +.. _binary-elemidx: +.. _binary-dataidx: .. _binary-localidx: .. _binary-labelidx: .. _binary-index: @@ -38,6 +42,8 @@ All :ref:`indices ` are encoded with their respective value. \production{table index} & \Btableidx &::=& x{:}\Bu32 &\Rightarrow& x \\ \production{memory index} & \Bmemidx &::=& x{:}\Bu32 &\Rightarrow& x \\ \production{global index} & \Bglobalidx &::=& x{:}\Bu32 &\Rightarrow& x \\ + \production{element index} & \Belemidx &::=& x{:}\Bu32 &\Rightarrow& x \\ + \production{data index} & \Bdataidx &::=& x{:}\Bu32 &\Rightarrow& x \\ \production{local index} & \Blocalidx &::=& x{:}\Bu32 &\Rightarrow& x \\ \production{label index} & \Blabelidx &::=& l{:}\Bu32 &\Rightarrow& l \\ \end{array} @@ -78,22 +84,23 @@ In these cases, the empty result :math:`\epsilon` is interpreted as the empty ve The following section ids are used: -== ======================================== -Id Section -== ======================================== - 0 :ref:`custom section ` - 1 :ref:`type section ` - 2 :ref:`import section ` - 3 :ref:`function section ` - 4 :ref:`table section ` - 5 :ref:`memory section ` - 6 :ref:`global section ` - 7 :ref:`export section ` - 8 :ref:`start section ` - 9 :ref:`element section ` -10 :ref:`code section ` -11 :ref:`data section ` -== ======================================== +== =============================================== +Id Section +== =============================================== + 0 :ref:`custom section ` + 1 :ref:`type section ` + 2 :ref:`import section ` + 3 :ref:`function section ` + 4 :ref:`table section ` + 5 :ref:`memory section ` + 6 :ref:`global section ` + 7 :ref:`export section ` + 8 :ref:`start section ` + 9 :ref:`element section ` +10 :ref:`code section ` +11 :ref:`data section ` +12 :ref:`data count section ` +== =============================================== .. index:: ! custom section @@ -307,12 +314,13 @@ It decodes into an optional :ref:`start function ` that represents single: element; segment .. _binary-elem: .. _binary-elemsec: +.. _binary-elemkind: Element Section ~~~~~~~~~~~~~~~ The *element section* has the id 9. -It decodes into a vector of :ref:`element segments ` that represent the |MELEM| component of a :ref:`module `. +It decodes into a vector of :ref:`element segments ` that represent the |MELEMS| component of a :ref:`module `. .. math:: \begin{array}{llclll} @@ -320,11 +328,29 @@ It decodes into a vector of :ref:`element segments ` that represent \X{seg}^\ast{:}\Bsection_9(\Bvec(\Belem)) &\Rightarrow& \X{seg} \\ \production{element segment} & \Belem &::=& \hex{00}~~e{:}\Bexpr~~y^\ast{:}\Bvec(\Bfuncidx) - &\Rightarrow& \{ \ETABLE~0, \EOFFSET~e, \EINIT~y^\ast \} \\ &&|& - \hex{02}~~x{:}\Btableidx~~e{:}\Bexpr~~\hex{00}~~y^\ast{:}\Bvec(\Bfuncidx) - &\Rightarrow& \{ \ETABLE~x, \EOFFSET~e, \EINIT~y^\ast \} \\ + &\Rightarrow& \{ \ETYPE~\FUNCREF, \EINIT~((\REFFUNC~y)~\END)^\ast, \EMODE~\EACTIVE~\{ \ETABLE~0, \EOFFSET~e \} \} \\ &&|& + \hex{01}~~\X{et}:\Belemkind~~y^\ast{:}\Bvec(\Bfuncidx) + &\Rightarrow& \{ \ETYPE~\X{et}, \EINIT~((\REFFUNC~y)~\END)^\ast, \EMODE~\EPASSIVE \} \\ &&|& + \hex{02}~~x{:}\Btableidx~~e{:}\Bexpr~~\X{et}:\Belemkind~~y^\ast{:}\Bvec(\Bfuncidx) + &\Rightarrow& \{ \ETYPE~\X{et}, \EINIT~((\REFFUNC~y)~\END)^\ast, \EMODE~\EACTIVE~\{ \ETABLE~x, \EOFFSET~e \} \} \\ &&|& + \hex{04}~~e{:}\Bexpr~~\X{el}^\ast{:}\Bvec(\Bexpr) + &\Rightarrow& \{ \ETYPE~\FUNCREF, \EINIT~\X{el}^\ast, \EMODE~\EACTIVE~\{ \ETABLE~0, \EOFFSET~e \} \} \\ &&|& + \hex{05}~~\X{et}:\Breftype~~\X{el}^\ast{:}\Bvec(\Bexpr) + &\Rightarrow& \{ \ETYPE~et, \EINIT~\X{el}^\ast, \EMODE~\EPASSIVE \} \\ &&|& + \hex{06}~~x{:}\Btableidx~~e{:}\Bexpr~~\X{et}:\Breftype~~\X{el}^\ast{:}\Bvec(\Bexpr) + &\Rightarrow& \{ \ETYPE~et, \EINIT~\X{el}^\ast, \EMODE~\EACTIVE~\{ \ETABLE~x, \EOFFSET~e \} \} \\ + \production{element kind} & \Belemkind &::=& + \hex{00} &\Rightarrow& \FUNCREF \\ \end{array} +.. note:: + The initial byte can be interpreted as a bitfield. + Bit 0 indicates a passive segment, + bit 1 indicates the presence of an explicit table index for an active segment, + bit 2 indicates the use of element type and element :ref:`expressions ` instead of element kind and element indices. + + Additional element kinds may be added in future versions of WebAssembly. + .. index:: ! code section, function, local, type index, function type pair: binary format; function @@ -395,17 +421,56 @@ Data Section ~~~~~~~~~~~~ The *data section* has the id 11. -It decodes into a vector of :ref:`data segments ` that represent the |MDATA| component of a :ref:`module `. +It decodes into a vector of :ref:`data segments ` that represent the |MDATAS| component of a :ref:`module `. .. math:: \begin{array}{llclll} \production{data section} & \Bdatasec &::=& \X{seg}^\ast{:}\Bsection_{11}(\Bvec(\Bdata)) &\Rightarrow& \X{seg} \\ \production{data segment} & \Bdata &::=& - x{:}\Bmemidx~~e{:}\Bexpr~~b^\ast{:}\Bvec(\Bbyte) - &\Rightarrow& \{ \DMEM~x, \DOFFSET~e, \DINIT~b^\ast \} \\ + \hex{00}~~e{:}\Bexpr~~b^\ast{:}\Bvec(\Bbyte) + &\Rightarrow& \{ \DINIT~b^\ast, \DMODE~\DACTIVE~\{ \DMEM~0, \DOFFSET~e \} \} \\ &&|& + \hex{01}~~b^\ast{:}\Bvec(\Bbyte) + &\Rightarrow& \{ \DINIT~b^\ast, \DMODE~\DPASSIVE \} \\ &&|& + \hex{02}~~x{:}\Bmemidx~~e{:}\Bexpr~~b^\ast{:}\Bvec(\Bbyte) + &\Rightarrow& \{ \DINIT~b^\ast, \DMODE~\DACTIVE~\{ \DMEM~x, \DOFFSET~e \} \} \\ + \end{array} + +.. note:: + The initial byte can be interpreted as a bitfield. + Bit 0 indicates a passive segment, + bit 1 indicates the presence of an explicit memory index for an active segment. + + In the current version of WebAssembly, at most one memory may be defined or + imported in a single module, so all valid :ref:`active ` data + segments have a |DMEM| value of :math:`0`. + + +.. index:: ! data count section, data count, data segment + pair: binary format; data count + pair: section; data count +.. _binary-datacountsec: + +Data Count Section +~~~~~~~~~~~~~~~~~~ + +The *data count section* has the id 12. +It decodes into an optional :ref:`u32 ` that represents the number of :ref:`data segments ` in the :ref:`data section `. If this count does not match the length of the data segment vector, the module is malformed. + +.. math:: + \begin{array}{llclll} + \production{data count section} & \Bdatacountsec &::=& + \X{n}^?{:}\Bsection_{12}(\Bu32) &\Rightarrow& \X{n}^? \\ \end{array} +.. note:: + The data count section is used to simplify single-pass validation. Since the + data section occurs after the code section, the :math:`\MEMORYINIT` and + :math:`\DATADROP` instructions would not be able to check whether the data + segment index is valid until the data section is read. The data count section + occurs before the code section, so a single-pass validator can use this count + instead of deferring validation. + .. index:: module, section, type definition, function type, function, table, memory, global, element, data, start function, import, export, context, version pair: binary format; module @@ -426,6 +491,9 @@ All sections can be empty. The lengths of vectors produced by the (possibly empty) :ref:`function ` and :ref:`code ` section must match up. +Similarly, the optional data count must match the length of the :ref:`data segment ` vector. +Furthermore, it must be present if any :math:`data index ` occurs in the code section. + .. math:: \begin{array}{llcllll} \production{magic} & \Bmagic &::=& @@ -454,9 +522,11 @@ The lengths of vectors produced by the (possibly empty) :ref:`function ` that is modified by *pushing* or *popping* - :ref:`values `, :ref:`labels `, and :ref:`frames `. + :ref:`values `, :ref:`function elements `, :ref:`labels `, and :ref:`frames `. * Certain rules require the stack to contain at least one frame. The most recent frame is referred to as the *current* frame. diff --git a/document/core/exec/instructions.rst b/document/core/exec/instructions.rst index fb67b8d1d8..ffad9cb326 100644 --- a/document/core/exec/instructions.rst +++ b/document/core/exec/instructions.rst @@ -439,7 +439,7 @@ Variable Instructions :ref:`Validation ` ensures that the global is, in fact, marked as mutable. -.. index:: table instruction, table index, store, frame, address, table address, table instance, value, integer, limits, reference, reference type +.. index:: table instruction, table index, store, frame, address, table address, table instance, element address, element instance, value, integer, limits, reference, reference type pair: execution; instruction single: abstract syntax; instruction .. _exec-instr-table: @@ -470,17 +470,18 @@ Table Instructions a. Trap. -6. Let :math:`\val` be the value :math:`\X{tab}.\TIELEM[i]`. +9. Let :math:`\val` be the value :math:`\X{tab}.\TIELEM[i]`. -7. Push the value :math:`\val` to the stack. +10. Push the value :math:`\val` to the stack. .. math:: + ~\\[-1ex] \begin{array}{l} \begin{array}{lcl@{\qquad}l} S; F; (\I32.\CONST~i)~(\TABLEGET~x) &\stepto& S; F; \val \end{array} \\ \qquad - (\iff S.\STABLES[F.\AMODULE.\MITABLES[x]][i] = \val) \\ + (\iff S.\STABLES[F.\AMODULE.\MITABLES[x]].\TIELEM[i] = \val) \\ \begin{array}{lcl@{\qquad}l} S; F; (\I32.\CONST~i)~(\TABLEGET~x) &\stepto& S; F; \TRAP \end{array} @@ -491,8 +492,8 @@ Table Instructions .. _exec-table.set: -:math:`\TABLESET~x` -................... +:math:`\TABLESET` +................. 1. Let :math:`F` be the :ref:`current ` :ref:`frame `. @@ -519,12 +520,13 @@ Table Instructions 11. Replace the element :math:`\X{tab}.\TIELEM[i]` with :math:`\val`. .. math:: + ~\\[-1ex] \begin{array}{l} \begin{array}{lcl@{\qquad}l} S; F; (\I32.\CONST~i)~\val~(\TABLESET~x) &\stepto& S'; F; \epsilon \end{array} \\ \qquad - (\iff S' = S \with \STABLES[F.\AMODULE.\MITABLES[x]][i] = \val) \\ + (\iff S' = S \with \STABLES[F.\AMODULE.\MITABLES[x]].\TIELEM[i] = \val) \\ \begin{array}{lcl@{\qquad}l} S; F; (\I32.\CONST~i)~\val~(\TABLESET~x) &\stepto& S; F; \TRAP \end{array} @@ -689,6 +691,237 @@ Table Instructions \end{array} +.. _exec-table.copy: + +:math:`\TABLECOPY` +.................. + +.. todo:: TODO: multi tables + +1. Let :math:`F` be the :ref:`current ` :ref:`frame `. + +2. Assert: due to :ref:`validation `, :math:`F.\AMODULE.\MITABLES[0]` exists. + +3. Let :math:`\X{ta}` be the :ref:`table address ` :math:`F.\AMODULE.\MITABLES[0]`. + +4. Assert: due to :ref:`validation `, :math:`S.\STABLES[\X{ta}]` exists. + +5. Let :math:`\X{tab}` be the :ref:`table instance ` :math:`S.\STABLES[\X{ta}]`. + +6. Assert: due to :ref:`validation `, a value of :ref:`value type ` |I32| is on the top of the stack. + +7. Pop the value :math:`\I32.\CONST~n` from the stack. + +8. Assert: due to :ref:`validation `, a value of :ref:`value type ` |I32| is on the top of the stack. + +9. Pop the value :math:`\I32.\CONST~s` from the stack. + +10. Assert: due to :ref:`validation `, a value of :ref:`value type ` |I32| is on the top of the stack. + +11. Pop the value :math:`\I32.\CONST~d` from the stack. + +12. If :math:`s + n` is larger than the length of :math:`\X{tab}.\TIELEM` or :math:`d + n` is larger than the length of :math:`\X{tab}.\TIELEM`, then: + + a. Trap. + +13. If :math:`n = 0`, then: + + a. Return. + +14. If :math:`d \leq s`, then: + + a. Push the value :math:`\I32.\CONST~d` to the stack. + + b. Push the value :math:`\I32.\CONST~s` to the stack. + + c. Execute the instruction :math:`\TABLEGET`. + + d. Execute the instruction :math:`\TABLESET`. + + e. Assert: due to the earlier check against the table size, :math:`d+1 < 2^{32}`. + + f. Push the value :math:`\I32.\CONST~(d+1)` to the stack. + + g. Assert: due to the earlier check against the table size, :math:`s+1 < 2^{32}`. + + h. Push the value :math:`\I32.\CONST~(s+1)` to the stack. + +15. Else: + + a. Assert: due to the earlier check against the table size, :math:`d+n-1 < 2^{32}`. + + b. Push the value :math:`\I32.\CONST~(d+n-1)` to the stack. + + c. Assert: due to the earlier check against the table size, :math:`s+n-1 < 2^{32}`. + + d. Push the value :math:`\I32.\CONST~(s+n-1)` to the stack. + + c. Execute the instruction :math:`\TABLEGET`. + + f. Execute the instruction :math:`\TABLESET`. + + g. Push the value :math:`\I32.\CONST~d` to the stack. + + h. Push the value :math:`\I32.\CONST~s` to the stack. + +16. Push the value :math:`\I32.\CONST~(n-1)` to the stack. + +17. Execute the instruction :math:`\TABLECOPY`. + +.. math:: + ~\\[-1ex] + \begin{array}{l} + S; F; (\I32.\CONST~d)~(\I32.\CONST~s)~(\I32.\CONST~n)~\TABLECOPY + \quad\stepto\quad S; F; \TRAP + \\ \qquad + \begin{array}[t]{@{}r@{~}l@{}} + (\iff & s + n > |S.\STABLES[F.\AMODULE.\MITABLES[0]].\TIELEM| \\ + \vee & d + n > |S.\STABLES[F.\AMODULE.\MITABLES[0]].\TIELEM|) \\ + \end{array} + \\[1ex] + S; F; (\I32.\CONST~d)~(\I32.\CONST~s)~(\I32.\CONST~0)~\TABLECOPY + \quad\stepto\quad S; F; \epsilon + \\ \qquad + (\otherwise) + \\[1ex] + S; F; (\I32.\CONST~d)~(\I32.\CONST~s)~(\I32.\CONST~n+1)~\TABLECOPY + \quad\stepto\quad S; F; + \begin{array}[t]{@{}l@{}} + (\I32.\CONST~d)~(\I32.\CONST~s)~\TABLEGET~\TABLESET \\ + (\I32.\CONST~d+1)~(\I32.\CONST~s+1)~(\I32.\CONST~n)~\TABLECOPY \\ + \end{array} + \\ \qquad + (\otherwise, \iff d \leq s) + \\[1ex] + S; F; (\I32.\CONST~d)~(\I32.\CONST~s)~(\I32.\CONST~n+1)~\TABLECOPY + \quad\stepto\quad S; F; + \begin{array}[t]{@{}l@{}} + (\I32.\CONST~d+n-1)~(\I32.\CONST~s+n-1)~\TABLEGET~\TABLESET \\ + (\I32.\CONST~d)~(\I32.\CONST~s)~(\I32.\CONST~n)~\TABLECOPY \\ + \end{array} + \\ \qquad + (\otherwise, \iff d > s) \\ + \end{array} + + +.. _exec-table.init: + +:math:`\TABLEINIT~x` +.................... + +.. todo:: TODO: multi tables + +1. Let :math:`F` be the :ref:`current ` :ref:`frame `. + +2. Assert: due to :ref:`validation `, :math:`F.\AMODULE.\MITABLES[0]` exists. + +3. Let :math:`\X{ta}` be the :ref:`table address ` :math:`F.\AMODULE.\MITABLES[0]`. + +4. Assert: due to :ref:`validation `, :math:`S.\STABLES[\X{ta}]` exists. + +5. Let :math:`\X{tab}` be the :ref:`table instance ` :math:`S.\STABLES[\X{ta}]`. + +6. Assert: due to :ref:`validation `, :math:`F.\AMODULE.\MIELEMS[x]` exists. + +7. Let :math:`\X{ea}` be the :ref:`element address ` :math:`F.\AMODULE.\MIELEMS[x]`. + +8. Assert: due to :ref:`validation `, :math:`S.\SELEMS[\X{ea}]` exists. + +9. Let :math:`\X{elem}` be the :ref:`element instance ` :math:`S.\SELEMS[\X{ea}]`. + +10. Assert: due to :ref:`validation `, a value of :ref:`value type ` |I32| is on the top of the stack. + +11. Pop the value :math:`\I32.\CONST~n` from the stack. + +12. Assert: due to :ref:`validation `, a value of :ref:`value type ` |I32| is on the top of the stack. + +13. Pop the value :math:`\I32.\CONST~s` from the stack. + +14. Assert: due to :ref:`validation `, a value of :ref:`value type ` |I32| is on the top of the stack. + +15. Pop the value :math:`\I32.\CONST~d` from the stack. + +16. If :math:`s + n` is larger than the length of :math:`\X{elem}.\EIELEM` or :math:`d + n` is larger than the length of :math:`\X{tab}.\TIELEM`, then: + + a. Trap. + +17. If :math:`n = 0`, then: + + a. Return. + +18. Let :math:`\funcelem` be the :ref:`function element ` :math:`\X{elem}.\EIELEM[s]`. + +19. Push the value :math:`\I32.\CONST~d` to the stack. + +20. Push the value :math:`\funcelem` to the stack. + +21. Execute the instruction :math:`\TABLESET`. + +22. Assert: due to the earlier check against the table size, :math:`d+1 < 2^{32}`. + +23. Push the value :math:`\I32.\CONST~(d+1)` to the stack. + +24. Assert: due to the earlier check against the segment size, :math:`s+1 < 2^{32}`. + +25. Push the value :math:`\I32.\CONST~(s+1)` to the stack. + +26. Push the value :math:`\I32.\CONST~(n-1)` to the stack. + +27. Execute the instruction :math:`\TABLEINIT~x`. + +.. math:: + ~\\[-1ex] + \begin{array}{l} + S; F; (\I32.\CONST~d)~(\I32.\CONST~s)~(\I32.\CONST~n)~(\TABLEINIT~x) + \quad\stepto\quad S; F; \TRAP + \\ \qquad + \begin{array}[t]{@{}r@{~}l@{}} + (\iff & s + n > |S.\SELEMS[F.\AMODULE.\MIELEMS[x]].\EIELEM| \\ + \vee & d + n > |S.\STABLES[F.\AMODULE.\MITABLES[x]].\TIELEM|) \\ + \end{array} + \\[1ex] + S; F; (\I32.\CONST~d)~(\I32.\CONST~s)~(\I32.\CONST~0)~(\TABLEINIT~x) + \quad\stepto\quad S; F; \epsilon + \\ \qquad + (\otherwise) + \\[1ex] + S; F; (\I32.\CONST~d)~(\I32.\CONST~s)~(\I32.\CONST~n+1)~(\TABLEINIT~x) + \quad\stepto\quad S; F; + \begin{array}[t]{@{}l@{}} + (\I32.\CONST~d)~\funcelem~(\TABLESET~x) \\ + (\I32.\CONST~d+1)~(\I32.\CONST~s+1)~(\I32.\CONST~n)~(\TABLEINIT~x) \\ + \end{array} + \\ \qquad + (\otherwise, \iff \funcelem = S.\SELEMS[F.\AMODULE.\MIELEMS[x]].\EIELEM[s]) \\ + \end{array} + + +.. _exec-elem.drop: + +:math:`\ELEMDROP~x` +................... + +1. Let :math:`F` be the :ref:`current ` :ref:`frame `. + +2. Assert: due to :ref:`validation `, :math:`F.\AMODULE.\MIELEMS[x]` exists. + +3. Let :math:`a` be the :ref:`element address ` :math:`F.\AMODULE.\MIELEMS[x]`. + +4. Assert: due to :ref:`validation `, :math:`S.\SELEMS[a]` exists. + +5. Replace :math:`S.\SELEMS[a]` with the :ref:`element instance ` :math:`\{\EIELEM~\epsilon\}`. + +.. math:: + ~\\[-1ex] + \begin{array}{l} + \begin{array}{lcl@{\qquad}l} + S; F; (\ELEMDROP~x) &\stepto& S'; F; \epsilon + \end{array} + \\ \qquad + (\iff S' = S \with \SELEMS[F.\AMODULE.\MIELEMS[x]] = \{ \EIELEM~\epsilon \}) \\ + \end{array} + + .. index:: memory instruction, memory index, store, frame, address, memory address, memory instance, value, integer, limits, value type, bit width pair: execution; instruction single: abstract syntax; instruction @@ -944,6 +1177,312 @@ Memory Instructions In practice, the choice depends on the :ref:`resources ` available to the :ref:`embedder `. +.. _exec-memory.fill: + +:math:`\MEMORYFILL` +................... + +1. Let :math:`F` be the :ref:`current ` :ref:`frame `. + +2. Assert: due to :ref:`validation `, :math:`F.\AMODULE.\MIMEMS[0]` exists. + +3. Let :math:`\X{ma}` be the :ref:`memory address ` :math:`F.\AMODULE.\MIMEMS[0]`. + +4. Assert: due to :ref:`validation `, :math:`S.\SMEMS[\X{ma}]` exists. + +5. Let :math:`\X{mem}` be the :ref:`memory instance ` :math:`S.\SMEMS[\X{ma}]`. + +6. Assert: due to :ref:`validation `, a value of :ref:`value type ` |I32| is on the top of the stack. + +7. Pop the value :math:`\I32.\CONST~n` from the stack. + +8. Assert: due to :ref:`validation `, a value of :ref:`value type ` |I32| is on the top of the stack. + +9. Pop the value :math:`\val` from the stack. + +10. Assert: due to :ref:`validation `, a value of :ref:`value type ` |I32| is on the top of the stack. + +11. Pop the value :math:`\I32.\CONST~d` from the stack. + +12. If :math:`d + n` is larger than the length of :math:`\X{mem}.\MIDATA`, then: + + a. Trap. + +13. If :math:`n = 0`, then: + + a. Return. + +14. Push the value :math:`\I32.\CONST~d` to the stack. + +15. Push the value :math:`\val` to the stack. + +16. Execute the instruction :math:`\I32\K{.}\STORE\K{8}~\{ \OFFSET~0, \ALIGN~0 \}`. + +17. Assert: due to the earlier check against the memory size, :math:`d+1 < 2^{32}`. + +18. Push the value :math:`\I32.\CONST~(d+1)` to the stack. + +19. Push the value :math:`\val` to the stack. + +20. Push the value :math:`\I32.\CONST~(n-1)` to the stack. + +21. Execute the instruction :math:`\MEMORYFILL`. + +.. math:: + ~\\[-1ex] + \begin{array}{l} + S; F; (\I32.\CONST~d)~\val~(\I32.\CONST~n)~\MEMORYFILL + \quad\stepto\quad S; F; \TRAP + \\ \qquad + (\iff d + n > |S.\SMEMS[F.\AMODULE.\MIMEMS[x]].\MIDATA|) \\ + \\[1ex] + S; F; (\I32.\CONST~d)~\val~(\I32.\CONST~0)~\MEMORYFILL + \quad\stepto\quad S; F; \epsilon + \\ \qquad + (\otherwise) + \\[1ex] + S; F; (\I32.\CONST~d)~\val~(\I32.\CONST~n+1)~\MEMORYFILL + \quad\stepto\quad S; F; + \begin{array}[t]{@{}l@{}} + (\I32.\CONST~d)~\val~(\I32\K{.}\STORE\K{8}~\{ \OFFSET~0, \ALIGN~0 \}) \\ + (\I32.\CONST~d+1)~\val~(\I32.\CONST~n)~\MEMORYFILL \\ + \end{array} + \\ \qquad + (\otherwise) \\ + \end{array} + + +.. _exec-memory.copy: + +:math:`\MEMORYCOPY` +................... + +1. Let :math:`F` be the :ref:`current ` :ref:`frame `. + +2. Assert: due to :ref:`validation `, :math:`F.\AMODULE.\MIMEMS[0]` exists. + +3. Let :math:`\X{ma}` be the :ref:`memory address ` :math:`F.\AMODULE.\MIMEMS[0]`. + +4. Assert: due to :ref:`validation `, :math:`S.\SMEMS[\X{ma}]` exists. + +5. Let :math:`\X{mem}` be the :ref:`memory instance ` :math:`S.\SMEMS[\X{ma}]`. + +6. Assert: due to :ref:`validation `, a value of :ref:`value type ` |I32| is on the top of the stack. + +7. Pop the value :math:`\I32.\CONST~n` from the stack. + +8. Assert: due to :ref:`validation `, a value of :ref:`value type ` |I32| is on the top of the stack. + +9. Pop the value :math:`\I32.\CONST~s` from the stack. + +10. Assert: due to :ref:`validation `, a value of :ref:`value type ` |I32| is on the top of the stack. + +11. Pop the value :math:`\I32.\CONST~d` from the stack. + +12. If :math:`s + n` is larger than the length of :math:`\X{mem}.\MIDATA` or :math:`d + n` is larger than the length of :math:`\X{mem}.\MIDATA`, then: + + a. Trap. + +13. If :math:`n = 0`, then: + + a. Return. + +14. If :math:`d \leq s`, then: + + a. Push the value :math:`\I32.\CONST~d` to the stack. + + b. Push the value :math:`\I32.\CONST~s` to the stack. + + c. Execute the instruction :math:`\I32\K{.}\LOAD\K{8\_u}~\{ \OFFSET~0, \ALIGN~0 \}`. + + d. Execute the instruction :math:`\I32\K{.}\STORE\K{8}~\{ \OFFSET~0, \ALIGN~0 \}`. + + e. Assert: due to the earlier check against the memory size, :math:`d+1 < 2^{32}`. + + f. Push the value :math:`\I32.\CONST~(d+1)` to the stack. + + g. Assert: due to the earlier check against the memory size, :math:`s+1 < 2^{32}`. + + h. Push the value :math:`\I32.\CONST~(s+1)` to the stack. + +15. Else: + + a. Assert: due to the earlier check against the memory size, :math:`d+n-1 < 2^{32}`. + + b. Push the value :math:`\I32.\CONST~(d+n-1)` to the stack. + + c. Assert: due to the earlier check against the memory size, :math:`s+n-1 < 2^{32}`. + + d. Push the value :math:`\I32.\CONST~(s+n-1)` to the stack. + + e. Execute the instruction :math:`\I32\K{.}\LOAD\K{8\_u}~\{ \OFFSET~0, \ALIGN~0 \}`. + + f. Execute the instruction :math:`\I32\K{.}\STORE\K{8}~\{ \OFFSET~0, \ALIGN~0 \}`. + + g. Push the value :math:`\I32.\CONST~d` to the stack. + + h. Push the value :math:`\I32.\CONST~s` to the stack. + +16. Push the value :math:`\I32.\CONST~(n-1)` to the stack. + +17. Execute the instruction :math:`\MEMORYCOPY`. + +.. math:: + ~\\[-1ex] + \begin{array}{l} + S; F; (\I32.\CONST~d)~(\I32.\CONST~s)~(\I32.\CONST~n)~\MEMORYCOPY + \quad\stepto\quad S; F; \TRAP + \\ \qquad + \begin{array}[t]{@{}r@{~}l@{}} + (\iff & s + n > |S.\SMEMS[F.\AMODULE.\MIMEMS[0]].\MIDATA| \\ + \vee & d + n > |S.\SMEMS[F.\AMODULE.\MIMEMS[0]].\MIDATA|) \\ + \end{array} + \\[1ex] + S; F; (\I32.\CONST~d)~(\I32.\CONST~s)~(\I32.\CONST~0)~\MEMORYCOPY + \quad\stepto\quad S; F; \epsilon + \\ \qquad + (\otherwise) + \\[1ex] + S; F; (\I32.\CONST~d)~(\I32.\CONST~s)~(\I32.\CONST~n+1)~\MEMORYCOPY + \quad\stepto\quad S; F; + \begin{array}[t]{@{}l@{}} + (\I32.\CONST~d) \\ + (\I32.\CONST~s)~(\I32\K{.}\LOAD\K{8\_u}~\{ \OFFSET~0, \ALIGN~0 \}) \\ + (\I32\K{.}\STORE\K{8}~\{ \OFFSET~0, \ALIGN~0 \}) \\ + (\I32.\CONST~d+1)~(\I32.\CONST~s+1)~(\I32.\CONST~n)~\MEMORYCOPY \\ + \end{array} + \\ \qquad + (\otherwise, \iff d \leq s) + \\[1ex] + S; F; (\I32.\CONST~d)~(\I32.\CONST~s)~(\I32.\CONST~n+1)~\MEMORYCOPY + \quad\stepto\quad S; F; + \begin{array}[t]{@{}l@{}} + (\I32.\CONST~d+n-1) \\ + (\I32.\CONST~s+n-1)~(\I32\K{.}\LOAD\K{8\_u}~\{ \OFFSET~0, \ALIGN~0 \}) \\ + (\I32\K{.}\STORE\K{8}~\{ \OFFSET~0, \ALIGN~0 \}) \\ + (\I32.\CONST~d)~(\I32.\CONST~s)~(\I32.\CONST~n)~\MEMORYCOPY \\ + \end{array} + \\ \qquad + (\otherwise, \iff d > s) \\ + \end{array} + + +.. _exec-memory.init: + +:math:`\MEMORYINIT~x` +..................... + +1. Let :math:`F` be the :ref:`current ` :ref:`frame `. + +2. Assert: due to :ref:`validation `, :math:`F.\AMODULE.\MIMEMS[0]` exists. + +3. Let :math:`\X{ma}` be the :ref:`memory address ` :math:`F.\AMODULE.\MIMEMS[0]`. + +4. Assert: due to :ref:`validation `, :math:`S.\SMEMS[\X{ma}]` exists. + +5. Let :math:`\X{mem}` be the :ref:`memory instance ` :math:`S.\SMEMS[\X{ma}]`. + +6. Assert: due to :ref:`validation `, :math:`F.\AMODULE.\MIDATAS[x]` exists. + +7. Let :math:`\X{da}` be the :ref:`data address ` :math:`F.\AMODULE.\MIDATAS[x]`. + +8. Assert: due to :ref:`validation `, :math:`S.\SDATAS[\X{da}]` exists. + +9. Let :math:`\X{data}` be the :ref:`data instance ` :math:`S.\SDATAS[\X{da}]`. + +10. Assert: due to :ref:`validation `, a value of :ref:`value type ` |I32| is on the top of the stack. + +11. Pop the value :math:`\I32.\CONST~cnt` from the stack. + +12. Assert: due to :ref:`validation `, a value of :ref:`value type ` |I32| is on the top of the stack. + +13. Pop the value :math:`\I32.\CONST~src` from the stack. + +14. Assert: due to :ref:`validation `, a value of :ref:`value type ` |I32| is on the top of the stack. + +15. Pop the value :math:`\I32.\CONST~dst` from the stack. + +16. If :math:`s + n` is larger than the length of :math:`\X{data}.\DIDATA` or :math:`d + n` is larger than the length of :math:`\X{mem}.\MIDATA`, then: + + a. Trap. + +17. If :math:`n = 0`, then: + + a. Return. + +18. Let :math:`b` be the byte :math:`\X{data}.\DIDATA[s]`. + +19. Push the value :math:`\I32.\CONST~d` to the stack. + +20. Push the value :math:`\I32.\CONST~b` to the stack. + +21. Execute the instruction :math:`\I32\K{.}\STORE\K{8}~\{ \OFFSET~0, \ALIGN~0 \}`. + +22. Assert: due to the earlier check against the memory size, :math:`d+1 < 2^{32}`. + +23. Push the value :math:`\I32.\CONST~(d+1)` to the stack. + +24. Assert: due to the earlier check against the memory size, :math:`s+1 < 2^{32}`. + +25. Push the value :math:`\I32.\CONST~(s+1)` to the stack. + +26. Push the value :math:`\I32.\CONST~(n-1)` to the stack. + +27. Execute the instruction :math:`\MEMORYINIT~x`. + +.. math:: + ~\\[-1ex] + \begin{array}{l} + S; F; (\I32.\CONST~d)~(\I32.\CONST~s)~(\I32.\CONST~n)~(\MEMORYINIT~x) + \quad\stepto\quad S; F; \TRAP + \\ \qquad + \begin{array}[t]{@{}r@{~}l@{}} + (\iff & s + n > |S.\SDATAS[F.\AMODULE.\MIDATAS[x]].\DIDATA| \\ + \vee & d + n > |S.\SMEMS[F.\AMODULE.\MIMEMS[x]].\MIDATA|) \\ + \end{array} + \\[1ex] + S; F; (\I32.\CONST~d)~(\I32.\CONST~s)~(\I32.\CONST~0)~(\MEMORYINIT~x) + \quad\stepto\quad S; F; \epsilon + \\ \qquad + (\otherwise) + \\[1ex] + S; F; (\I32.\CONST~d)~(\I32.\CONST~s)~(\I32.\CONST~n+1)~(\MEMORYINIT~x) + \quad\stepto\quad S; F; + \begin{array}[t]{@{}l@{}} + (\I32.\CONST~d)~(\I32.\CONST~b)~(\I32\K{.}\STORE\K{8}~\{ \OFFSET~0, \ALIGN~0 \}) \\ + (\I32.\CONST~d+1)~(\I32.\CONST~s+1)~(\I32.\CONST~n)~(\MEMORYINIT~x) \\ + \end{array} + \\ \qquad + (\otherwise, \iff b = S.\SDATAS[F.\AMODULE.\MIDATAS[x]].\DIDATA[s]) \\ + \end{array} + + +.. _exec-data.drop: + +:math:`\DATADROP~x` +................... + +1. Let :math:`F` be the :ref:`current ` :ref:`frame `. + +2. Assert: due to :ref:`validation `, :math:`F.\AMODULE.\MIDATAS[x]` exists. + +3. Let :math:`a` be the :ref:`data address ` :math:`F.\AMODULE.\MIDATAS[x]`. + +4. Assert: due to :ref:`validation `, :math:`S.\SDATAS[a]` exists. + +5. Replace :math:`S.\SDATAS[a]` with the :ref:`data instance ` :math:`\{\DIDATA~\epsilon\}`. + +.. math:: + ~\\[-1ex] + \begin{array}{l} + \begin{array}{lcl@{\qquad}l} + S; F; (\DATADROP~x) &\stepto& S'; F; \epsilon + \end{array} + \\ \qquad + (\iff S' = S \with \SDATAS[F.\AMODULE.\MIDATAS[x]] = \{ \DIDATA~\epsilon \}) \\ + \end{array} + + .. index:: control instructions, structured control, label, block, branch, result type, label index, function index, type index, vector, address, table address, table instance, store, frame pair: execution; instruction single: abstract syntax; instruction diff --git a/document/core/exec/modules.rst b/document/core/exec/modules.rst index b058d0d7d9..1211356d23 100644 --- a/document/core/exec/modules.rst +++ b/document/core/exec/modules.rst @@ -303,6 +303,58 @@ New instances of :ref:`functions `, :ref:`tables ` +......................................... + +1. Let :math:`\reftype` be the elements' type and :math:`\reff^\ast` the vector of :ref:`references ` to allocate. + +2. Let :math:`a` be the first free :ref:`element address ` in :math:`S`. + +3. Let :math:`\eleminst` be the :ref:`element instance ` :math:`\{ \EITYPE~t, \EIELEM~\reff^\ast \}`. + +4. Append :math:`\eleminst` to the |SELEMS| of :math:`S`. + +5. Return :math:`a`. + +.. math:: + \begin{array}{rlll} + \allocelem(S, \reftype, \reff^\ast) &=& S', \elemaddr \\[1ex] + \mbox{where:} \hfill \\ + \elemaddr &=& |S.\SELEMS| \\ + \eleminst &=& \{ \EITYPE~\reftype, \EIELEM~\reff^\ast \} \\ + S' &=& S \compose \{\SELEMS~\eleminst\} \\ + \end{array} + + +.. index:: data, data instance, data address +.. _alloc-data: + +:ref:`Data segments ` +...................................... + +1. Let :math:`\bytes` be the vector of :ref:`bytes ` to allocate. + +2. Let :math:`a` be the first free :ref:`data address ` in :math:`S`. + +3. Let :math:`\datainst` be the :ref:`data instance ` :math:`\{ \DIDATA~\bytes \}`. + +4. Append :math:`\datainst` to the |SDATAS| of :math:`S`. + +5. Return :math:`a`. + +.. math:: + \begin{array}{rlll} + \allocdata(S, \bytes) &=& S', \dataaddr \\[1ex] + \mbox{where:} \hfill \\ + \dataaddr &=& |S.\SDATAS| \\ + \datainst &=& \{ \DIDATA~\bytes \} \\ + S' &=& S \compose \{\SDATAS~\datainst\} \\ + \end{array} + + .. index:: table, table instance, table address, grow, limits .. _grow-table: @@ -384,10 +436,10 @@ Growing :ref:`memories ` .................................. The allocation function for :ref:`modules ` requires a suitable list of :ref:`external values ` that are assumed to :ref:`match ` the :ref:`import ` vector of the module, -and a list of initialization :ref:`values ` for the module's :ref:`globals `. +a list of initialization :ref:`values ` for the module's :ref:`globals `, +and list of :ref:`reference ` vectors for the module's :ref:`element segments `. -1. Let :math:`\module` be the :ref:`module ` to allocate and :math:`\externval_{\F{im}}^\ast` the vector of :ref:`external values ` providing the module's imports, -and :math:`\val^\ast` the initialization :ref:`values ` of the module's :ref:`globals `. +1. Let :math:`\module` be the :ref:`module ` to allocate and :math:`\externval_{\F{im}}^\ast` the vector of :ref:`external values ` providing the module's imports, :math:`\val^\ast` the initialization :ref:`values ` of the module's :ref:`globals `, and :math:`(\reff^\ast)^\ast` the :ref:`reference ` vectors of the module's :ref:`element segments `. 2. For each :ref:`function ` :math:`\func_i` in :math:`\module.\MFUNCS`, do: @@ -405,23 +457,35 @@ and :math:`\val^\ast` the initialization :ref:`values ` of the modul a. Let :math:`\globaladdr_i` be the :ref:`global address ` resulting from :ref:`allocating ` :math:`\global_i.\GTYPE` with initializer value :math:`\val^\ast[i]`. -6. Let :math:`\funcaddr^\ast` be the the concatenation of the :ref:`function addresses ` :math:`\funcaddr_i` in index order. +6. For each :ref:`element segment ` :math:`\elem_i` in :math:`\module.\MELEMS`, do: + + a. Let :math:`\elemaddr_i` be the :ref:`element address ` resulting from :ref:`allocating ` a :ref:`element instance ` of :ref:`reference type ` :math:`\elem_i.\ETYPE` with contents :math:`(\reff^\ast)^\ast[i]`. + +7. For each :ref:`data segment ` :math:`\data_i` in :math:`\module.\MDATAS`, do: + + a. Let :math:`\dataaddr_i` be the :ref:`data address ` resulting from :ref:`allocating ` a :ref:`data instance ` with contents :math:`\data_i.\DINIT`. -7. Let :math:`\tableaddr^\ast` be the the concatenation of the :ref:`table addresses ` :math:`\tableaddr_i` in index order. +8. Let :math:`\funcaddr^\ast` be the the concatenation of the :ref:`function addresses ` :math:`\funcaddr_i` in index order. -8. Let :math:`\memaddr^\ast` be the the concatenation of the :ref:`memory addresses ` :math:`\memaddr_i` in index order. +9. Let :math:`\tableaddr^\ast` be the the concatenation of the :ref:`table addresses ` :math:`\tableaddr_i` in index order. -9. Let :math:`\globaladdr^\ast` be the the concatenation of the :ref:`global addresses ` :math:`\globaladdr_i` in index order. +10. Let :math:`\memaddr^\ast` be the the concatenation of the :ref:`memory addresses ` :math:`\memaddr_i` in index order. -10. Let :math:`\funcaddr_{\F{mod}}^\ast` be the list of :ref:`function addresses ` extracted from :math:`\externval_{\F{im}}^\ast`, concatenated with :math:`\funcaddr^\ast`. +11. Let :math:`\globaladdr^\ast` be the the concatenation of the :ref:`global addresses ` :math:`\globaladdr_i` in index order. -11. Let :math:`\tableaddr_{\F{mod}}^\ast` be the list of :ref:`table addresses ` extracted from :math:`\externval_{\F{im}}^\ast`, concatenated with :math:`\tableaddr^\ast`. +12. Let :math:`\elemaddr^\ast` be the the concatenation of the :ref:`element addresses ` :math:`\elemaddr_i` in index order. -12. Let :math:`\memaddr_{\F{mod}}^\ast` be the list of :ref:`memory addresses ` extracted from :math:`\externval_{\F{im}}^\ast`, concatenated with :math:`\memaddr^\ast`. +13. Let :math:`\dataaddr^\ast` be the the concatenation of the :ref:`data addresses ` :math:`\dataaddr_i` in index order. -13. Let :math:`\globaladdr_{\F{mod}}^\ast` be the list of :ref:`global addresses ` extracted from :math:`\externval_{\F{im}}^\ast`, concatenated with :math:`\globaladdr^\ast`. +14. Let :math:`\funcaddr_{\F{mod}}^\ast` be the list of :ref:`function addresses ` extracted from :math:`\externval_{\F{im}}^\ast`, concatenated with :math:`\funcaddr^\ast`. -14. For each :ref:`export ` :math:`\export_i` in :math:`\module.\MEXPORTS`, do: +15. Let :math:`\tableaddr_{\F{mod}}^\ast` be the list of :ref:`table addresses ` extracted from :math:`\externval_{\F{im}}^\ast`, concatenated with :math:`\tableaddr^\ast`. + +16. Let :math:`\memaddr_{\F{mod}}^\ast` be the list of :ref:`memory addresses ` extracted from :math:`\externval_{\F{im}}^\ast`, concatenated with :math:`\memaddr^\ast`. + +17. Let :math:`\globaladdr_{\F{mod}}^\ast` be the list of :ref:`global addresses ` extracted from :math:`\externval_{\F{im}}^\ast`, concatenated with :math:`\globaladdr^\ast`. + +18. For each :ref:`export ` :math:`\export_i` in :math:`\module.\MEXPORTS`, do: a. If :math:`\export_i` is a function export for :ref:`function index ` :math:`x`, then let :math:`\externval_i` be the :ref:`external value ` :math:`\EVFUNC~(\funcaddr_{\F{mod}}^\ast[x])`. @@ -433,17 +497,18 @@ and :math:`\val^\ast` the initialization :ref:`values ` of the modul e. Let :math:`\exportinst_i` be the :ref:`export instance ` :math:`\{\EINAME~(\export_i.\ENAME), \EIVALUE~\externval_i\}`. -15. Let :math:`\exportinst^\ast` be the the concatenation of the :ref:`export instances ` :math:`\exportinst_i` in index order. +19. Let :math:`\exportinst^\ast` be the the concatenation of the :ref:`export instances ` :math:`\exportinst_i` in index order. -16. Let :math:`\moduleinst` be the :ref:`module instance ` :math:`\{\MITYPES~(\module.\MTYPES),` :math:`\MIFUNCS~\funcaddr_{\F{mod}}^\ast,` :math:`\MITABLES~\tableaddr_{\F{mod}}^\ast,` :math:`\MIMEMS~\memaddr_{\F{mod}}^\ast,` :math:`\MIGLOBALS~\globaladdr_{\F{mod}}^\ast,` :math:`\MIEXPORTS~\exportinst^\ast\}`. +20. Let :math:`\moduleinst` be the :ref:`module instance ` :math:`\{\MITYPES~(\module.\MTYPES),` :math:`\MIFUNCS~\funcaddr_{\F{mod}}^\ast,` :math:`\MITABLES~\tableaddr_{\F{mod}}^\ast,` :math:`\MIMEMS~\memaddr_{\F{mod}}^\ast,` :math:`\MIGLOBALS~\globaladdr_{\F{mod}}^\ast,` :math:`\MIEXPORTS~\exportinst^\ast\}`. -17. Return :math:`\moduleinst`. +21. Return :math:`\moduleinst`. .. math:: ~\\ \begin{array}{rlll} - \allocmodule(S, \module, \externval_{\F{im}}^\ast, \val^\ast) &=& S', \moduleinst \end{array} + \allocmodule(S, \module, \externval_{\F{im}}^\ast, \val^\ast, (\reff^\ast)^\ast) &=& S', \moduleinst + \end{array} where: @@ -456,6 +521,8 @@ where: \MITABLES~\evtables(\externval_{\F{im}}^\ast)~\tableaddr^\ast, \\ \MIMEMS~\evmems(\externval_{\F{im}}^\ast)~\memaddr^\ast, \\ \MIGLOBALS~\evglobals(\externval_{\F{im}}^\ast)~\globaladdr^\ast, \\ + \MIELEMS~\elemaddr^\ast, \\ + \MIDATAS~\dataaddr^\ast, \\ \MIEXPORTS~\exportinst^\ast ~\} \end{array} \\[1ex] S_1, \funcaddr^\ast &=& \allocfunc^\ast(S, \module.\MFUNCS, \moduleinst) \\ @@ -463,8 +530,12 @@ where: \qquad\qquad\qquad~ (\where \table^\ast = \module.\MTABLES) \\ S_3, \memaddr^\ast &=& \allocmem^\ast(S_2, (\mem.\MTYPE)^\ast) \qquad\qquad\qquad~ (\where \mem^\ast = \module.\MMEMS) \\ - S', \globaladdr^\ast &=& \allocglobal^\ast(S_3, (\global.\GTYPE)^\ast, \val^\ast) + S_4, \globaladdr^\ast &=& \allocglobal^\ast(S_3, (\global.\GTYPE)^\ast, \val^\ast) \qquad\quad~ (\where \global^\ast = \module.\MGLOBALS) \\ + S_5, \elemaddr^\ast &=& \allocelem^\ast(S_4, (\elem.\ETYPE)^\ast, (\reff^\ast)^\ast) \\ + \qquad\quad~ (\where \elem^\ast = \module.\MELEMS) \\ + S', \dataaddr^\ast &=& \allocdata^\ast(S_5, (\data.\DINIT)^\ast) + \qquad\qquad\qquad~ (\where \data^\ast = \module.\MDATAS) \\ \exportinst^\ast &=& \{ \EINAME~(\export.\ENAME), \EIVALUE~\externval_{\F{ex}} \}^\ast \quad (\where \export^\ast = \module.\MEXPORTS) \\[1ex] \evfuncs(\externval_{\F{ex}}^\ast) &=& (\moduleinst.\MIFUNCS[x])^\ast @@ -555,125 +626,110 @@ It is up to the :ref:`embedder ` to define how such conditions are rep f. Pop the frame :math:`F_{\F{im}}` from the stack. -6. Let :math:`\moduleinst` be a new module instance :ref:`allocated ` from :math:`\module` in store :math:`S` with imports :math:`\externval^n` and global initializer values :math:`\val^\ast`, and let :math:`S'` be the extended store produced by module allocation. - -7. Let :math:`F` be the :ref:`frame ` :math:`\{ \AMODULE~\moduleinst, \ALOCALS~\epsilon \}`. + g. Let :math:`\val^\ast` be the conatenation of :math:`\val_i` in index order. -8. Push the frame :math:`F` to the stack. +6. Let :math:`(\reff^\ast)^\ast` be the list of :ref:`reference ` vectors determined by the :ref:`element segments ` in :math:`\module`. These may be calculated as follows. -9. For each :ref:`element segment ` :math:`\elem_i` in :math:`\module.\MELEM`, do: + .. todo:: TODO desugar funcelem - a. Let :math:`\X{eoval}_i` be the result of :ref:`evaluating ` the expression :math:`\elem_i.\EOFFSET`. + a. For each :ref:`element segment ` :math:`\elem_i` in :math:`\module.\MELEMS`, and for each element :ref:`expression ` :math:`\expr_{ij}` in :math:`\elem_i.\EINIT`, do: - b. Assert: due to :ref:`validation `, :math:`\X{eoval}_i` is of the form :math:`\I32.\CONST~\X{eo}_i`. + i. If :math:`\expr_{ij}` is of the form :math:`\REFNULL`, then let the :ref:`function element ` :math:`\funcelem_{ij}` be :math:`\epsilon`. - c. Let :math:`\tableidx_i` be the :ref:`table index ` :math:`\elem_i.\ETABLE`. + ii. Else, :math:`\expr_{ij}` is of the form is :math:`\REFFUNC~\funcidx_{ij}`. - d. Assert: due to :ref:`validation `, :math:`\moduleinst.\MITABLES[\tableidx_i]` exists. + iii. Assert: due to :ref:`validation `, :math:`\moduleinst.\MIFUNCS[\funcidx_{ij}]` exists. - e. Let :math:`\tableaddr_i` be the :ref:`table address ` :math:`\moduleinst.\MITABLES[\tableidx_i]`. + iv. Let the :ref:`function element ` :math:`\funcelem_{ij}` be the :ref:`function address ` :math:`\moduleinst.\MIFUNCS[\funcidx_{ij}]`. - f. Assert: due to :ref:`validation `, :math:`S'.\STABLES[\tableaddr_i]` exists. + b. Let :math:`\funcelem^\ast_i` be the concatenation of function elements :math:`\funcelem_{ij}` in order of index :math:`j`. - g. Let :math:`\tableinst_i` be the :ref:`table instance ` :math:`S'.\STABLES[\tableaddr_i]`. + c. Let :math:`(\funcelem^\ast)^\ast` be the concatenation of function element vectors :math:`\funcelem^\ast_i` in order of index :math:`i`. - h. Let :math:`\X{eend}_i` be :math:`\X{eo}_i` plus the length of :math:`\elem_i.\EINIT`. +7. Let :math:`\moduleinst` be a new module instance :ref:`allocated ` from :math:`\module` in store :math:`S` with imports :math:`\externval^n`, global initializer values :math:`\val^\ast`, and element segment contents :math:`(\reff^\ast)^\ast`, and let :math:`S'` be the extended store produced by module allocation. - i. If :math:`\X{eend}_i` is larger than the length of :math:`\tableinst_i.\TIELEM`, then: +8. Let :math:`F` be the auxiliary :ref:`frame ` :math:`\{ \AMODULE~\moduleinst, \ALOCALS~\epsilon \}`. - i. Fail. +9. Push the frame :math:`F` to the stack. -10. For each :ref:`data segment ` :math:`\data_i` in :math:`\module.\MDATA`, do: +10. For each :ref:`element segment ` :math:`\elem_i` in :math:`\module.\MELEMS` whose :ref:`mode ` is of the form :math:`\EACTIVE~\{ \ETABLE~\tableidx_i, \EOFFSET~\X{einstr}^\ast_i~\END \}`, do: - a. Let :math:`\X{doval}_i` be the result of :ref:`evaluating ` the expression :math:`\data_i.\DOFFSET`. + a. Assert: :math:`\tableidx_i` is :math:`0`. - b. Assert: due to :ref:`validation `, :math:`\X{doval}_i` is of the form :math:`\I32.\CONST~\X{do}_i`. + b. Let :math:`n` be the length of the vector :math:`\elem_i.\EINIT`. - c. Let :math:`\memidx_i` be the :ref:`memory index ` :math:`\data_i.\DMEM`. + c. :ref:`Execute ` the instruction sequence :math:`\X{einstr}^\ast_i`. - d. Assert: due to :ref:`validation `, :math:`\moduleinst.\MIMEMS[\memidx_i]` exists. + d. :ref:`Execute ` the instruction :math:`\I32.\CONST~0`. - e. Let :math:`\memaddr_i` be the :ref:`memory address ` :math:`\moduleinst.\MIMEMS[\memidx_i]`. + e. :ref:`Execute ` the instruction :math:`\I32.\CONST~n`. - f. Assert: due to :ref:`validation `, :math:`S'.\SMEMS[\memaddr_i]` exists. + f. :ref:`Execute ` the instruction :math:`\TABLEINIT~i`. - g. Let :math:`\meminst_i` be the :ref:`memory instance ` :math:`S'.\SMEMS[\memaddr_i]`. + g. :ref:`Execute ` the instruction :math:`\ELEMDROP~i`. - h. Let :math:`\X{dend}_i` be :math:`\X{do}_i` plus the length of :math:`\data_i.\DINIT`. +11. For each :ref:`data segment ` :math:`\data_i` in :math:`\module.\MDATAS` whose :ref:`mode ` is of the form :math:`\DACTIVE~\{ \DMEM~\memidx_i, \DOFFSET~\X{dinstr}^\ast_i~\END \}`, do: - i. If :math:`\X{dend}_i` is larger than the length of :math:`\meminst_i.\MIDATA`, then: + a. Assert: :math:`\memidx_i` is :math:`0`. - i. Fail. + b. Let :math:`n` be the length of the vector :math:`\data_i.\DINIT`. -11. Assert: due to :ref:`validation `, the frame :math:`F` is now on the top of the stack. + c. :ref:`Execute ` the instruction sequence :math:`\X{dinstr}^\ast_i`. -12. Pop the frame from the stack. + d. :ref:`Execute ` the instruction :math:`\I32.\CONST~0`. -13. For each :ref:`element segment ` :math:`\elem_i` in :math:`\module.\MELEM`, do: + e. :ref:`Execute ` the instruction :math:`\I32.\CONST~n`. - a. For each :ref:`function index ` :math:`\funcidx_{ij}` in :math:`\elem_i.\EINIT` (starting with :math:`j = 0`), do: + f. :ref:`Execute ` the instruction :math:`\MEMORYINIT~i`. - i. Assert: due to :ref:`validation `, :math:`\moduleinst.\MIFUNCS[\funcidx_{ij}]` exists. + g. :ref:`Execute ` the instruction :math:`\DATADROP~i`. - ii. Let :math:`\funcaddr_{ij}` be the :ref:`function address ` :math:`\moduleinst.\MIFUNCS[\funcidx_{ij}]`. +12. If the :ref:`start function ` :math:`\module.\MSTART` is not empty, then: - iii. Replace :math:`\tableinst_i.\TIELEM[\X{eo}_i + j]` with :math:`\REFFUNCADDR~\funcaddr_{ij}`. + a. Let :math:`\start` be the :ref:`start function ` :math:`\module.\MSTART`. -14. For each :ref:`data segment ` :math:`\data_i` in :math:`\module.\MDATA`, do: + b. :ref:`Execute ` the instruction :math:`\CALL~\start.\SFUNC`. - a. For each :ref:`byte ` :math:`b_{ij}` in :math:`\data_i.\DINIT` (starting with :math:`j = 0`), do: +13. Assert: due to :ref:`validation `, the frame :math:`F` is now on the top of the stack. - i. Replace :math:`\meminst_i.\MIDATA[\X{do}_i + j]` with :math:`b_{ij}`. - -15. If the :ref:`start function ` :math:`\module.\MSTART` is not empty, then: - - a. Assert: due to :ref:`validation `, :math:`\moduleinst.\MIFUNCS[\module.\MSTART.\SFUNC]` exists. - - b. Let :math:`\funcaddr` be the :ref:`function address ` :math:`\moduleinst.\MIFUNCS[\module.\MSTART.\SFUNC]`. - - c. :ref:`Invoke ` the function instance at :math:`\funcaddr`. +14. Pop the frame :math:`F` from the stack. .. math:: ~\\ \begin{array}{@{}rcll} - \instantiate(S, \module, \externval^n) &=& S'; F; + \instantiate(S, \module, \externval^k) &=& S'; F; \begin{array}[t]{@{}l@{}} - (\INITELEM~\tableaddr~\X{eo}~\elem.\EINIT)^\ast \\ - (\INITDATA~\memaddr~\X{do}~\data.\DINIT)^\ast \\ - (\INVOKE~\funcaddr)^? \\ + \F{runelem}_0(\elem^n[0])~\dots~\F{runelem}_{n-1}(\elem^n[n-1]) \\ + \F{rundata}_0(\data^m[0])~\dots~\F{rundata}_{m-1}(\data^m[m-1]) \\ + (\CALL~\start.\SFUNC)^? \\ \end{array} \\ &(\iff - & \vdashmodule \module : \externtype_{\F{im}}^n \to \externtype_{\F{ex}}^\ast \\ - &\wedge& (S \vdashexternval \externval : \externtype)^n \\ - &\wedge& (\vdashexterntypematch \externtype \matchesexterntype \externtype_{\F{im}})^n \\[1ex] + & \vdashmodule \module : \externtype_{\F{im}}^k \to \externtype_{\F{ex}}^\ast \\ + &\wedge& (S \vdashexternval \externval : \externtype)^k \\ + &\wedge& (\vdashexterntypematch \externtype \matchesexterntype \externtype_{\F{im}})^k \\[1ex] &\wedge& \module.\MGLOBALS = \global^\ast \\ - &\wedge& \module.\MELEM = \elem^\ast \\ - &\wedge& \module.\MDATA = \data^\ast \\ + &\wedge& \module.\MELEMS = \elem^n \\ + &\wedge& \module.\MDATAS = \data^m \\ &\wedge& \module.\MSTART = \start^? \\[1ex] - &\wedge& S', \moduleinst = \allocmodule(S, \module, \externval^n, \val^\ast) \\ + &\wedge& S', \moduleinst = \allocmodule(S, \module, \externval^k, \val^\ast) \\ &\wedge& F = \{ \AMODULE~\moduleinst, \ALOCALS~\epsilon \} \\[1ex] &\wedge& (S'; F; \global.\GINIT \stepto^\ast S'; F; \val~\END)^\ast \\ - &\wedge& (S'; F; \elem.\EOFFSET \stepto^\ast S'; F; \I32.\CONST~\X{eo}~\END)^\ast \\ - &\wedge& (S'; F; \data.\DOFFSET \stepto^\ast S'; F; \I32.\CONST~\X{do}~\END)^\ast \\[1ex] - &\wedge& (\X{eo} + |\elem.\EINIT| \leq |S'.\STABLES[\tableaddr].\TIELEM|)^\ast \\ - &\wedge& (\X{do} + |\data.\DINIT| \leq |S'.\SMEMS[\memaddr].\MIDATA|)^\ast - \\[1ex] &\wedge& (\tableaddr = \moduleinst.\MITABLES[\elem.\ETABLE])^\ast \\ &\wedge& (\memaddr = \moduleinst.\MIMEMS[\data.\DMEM])^\ast \\ &\wedge& (\funcaddr = \moduleinst.\MIFUNCS[\start.\SFUNC])^?) - \\[2ex] - S; F; \INITELEM~a~i~\epsilon &\stepto& - S; F; \epsilon \\ - S; F; \INITELEM~a~i~(x_0~x^\ast) &\stepto& - S'; F; \INITELEM~a~(i+1)~x^\ast \\ && - (\iff S' = S \with \STABLES[a].\TIELEM[i] = \REFFUNCADDR~F.\AMODULE.\MIFUNCS[x_0]) - \\[1ex] - S; F; \INITDATA~a~i~\epsilon &\stepto& - S; F; \epsilon \\ - S; F; \INITDATA~a~i~(b_0~b^\ast) &\stepto& - S'; F; \INITDATA~a~(i+1)~b^\ast \\ && - (\iff S' = S \with \SMEMS[a].\MIDATA[i] = b_0) + \end{array} + +where: + +.. math:: + \begin{array}{@{}l} + \F{runelem}_i(\{\ETYPE~\X{et}, \EINIT~\reff^n, \EMODE~\EPASSIVE\}) \quad=\quad \epsilon \\ + \F{runelem}_i(\{\ETYPE~\X{et}, \EINIT~\reff^n, \EMODE~\EACTIVE \{\ETABLE~0, \EOFFSET~\instr^\ast~\END\}\}) \quad=\\ \qquad + \instr^\ast~(\I32.\CONST~0)~(\I32.\CONST~n)~(\TABLEINIT~i)~(\ELEMDROP~i) \\[1ex] + \F{rundata}_i(\{\DINIT~b^n, DMODE~\DPASSIVE\}) \quad=\quad \epsilon \\ + \F{rundata}_i(\{\DINIT~b^n, DMODE~\DACTIVE \{\DMEM~0, \DOFFSET~\instr^\ast~\END\}\}) \quad=\\ \qquad + \instr^\ast~(\I32.\CONST~0)~(\I32.\CONST~n)~(\MEMORYINIT~i)~(\DATADROP~i) \\ \end{array} .. note:: diff --git a/document/core/exec/runtime.rst b/document/core/exec/runtime.rst index b599e81079..594255be7e 100644 --- a/document/core/exec/runtime.rst +++ b/document/core/exec/runtime.rst @@ -93,7 +93,9 @@ Store ~~~~~ The *store* represents all global state that can be manipulated by WebAssembly programs. -It consists of the runtime representation of all *instances* of :ref:`functions `, :ref:`tables `, :ref:`memories `, and :ref:`globals ` that have been :ref:`allocated ` during the life time of the abstract machine. [#gc]_ +It consists of the runtime representation of all *instances* of :ref:`functions `, :ref:`tables `, :ref:`memories `, and :ref:`globals `, :ref:`element segments `, and :ref:`data segments ` that have been :ref:`allocated ` during the life time of the abstract machine. [#gc]_ + +It is an invariant of the semantics that no element or data instance is :ref:`addressed ` from anywhere else but the owning module instances. Syntactically, the store is defined as a :ref:`record ` listing the existing instances of each category: @@ -104,7 +106,9 @@ Syntactically, the store is defined as a :ref:`record ` listing \SFUNCS & \funcinst^\ast, \\ \STABLES & \tableinst^\ast, \\ \SMEMS & \meminst^\ast, \\ - \SGLOBALS & \globalinst^\ast ~\} \\ + \SGLOBALS & \globalinst^\ast, \\ + \SELEMS & \eleminst^\ast, \\ + \SDATAS & \datainst^\ast ~\} \\ \end{array} \end{array} @@ -120,28 +124,34 @@ Convention * The meta variable :math:`S` ranges over stores where clear from context. -.. index:: ! address, store, function instance, table instance, memory instance, global instance, embedder +.. index:: ! address, store, function instance, table instance, memory instance, global instance, element instance, data instance, embedder pair: abstract syntax; function address pair: abstract syntax; table address pair: abstract syntax; memory address pair: abstract syntax; global address + pair: abstract syntax; element address + pair: abstract syntax; data address pair: abstract syntax; host address pair: function; address pair: table; address pair: memory; address pair: global; address + pair: element; address + pair: data; address pair: host; address .. _syntax-funcaddr: .. _syntax-tableaddr: .. _syntax-memaddr: .. _syntax-globaladdr: +.. _syntax-elemaddr: +.. _syntax-dataaddr: .. _syntax-hostaddr: .. _syntax-addr: Addresses ~~~~~~~~~ -:ref:`Function instances `, :ref:`table instances `, :ref:`memory instances `, and :ref:`global instances ` in the :ref:`store ` are referenced with abstract *addresses*. +:ref:`Function instances `, :ref:`table instances `, :ref:`memory instances `, and :ref:`global instances `, :ref:`element instances `, and :ref:`data instances ` in the :ref:`store ` are referenced with abstract *addresses*. These are simply indices into the respective store component. In addition, an :ref:`embedder ` may supply an uninterpreted set of *host addresses*. @@ -157,6 +167,10 @@ In addition, an :ref:`embedder ` may supply an uninterpreted set of *h \addr \\ \production{(global address)} & \globaladdr &::=& \addr \\ + \production{(element address)} & \elemaddr &::=& + \addr \\ + \production{(data address)} & \dataaddr &::=& + \addr \\ \production{(host address)} & \hostaddr &::=& \addr \\ \end{array} @@ -176,7 +190,7 @@ even where this identity is not observable from within WebAssembly code itself hence logical addresses can be arbitrarily large natural numbers. -.. index:: ! instance, function type, function instance, table instance, memory instance, global instance, export instance, table address, memory address, global address, index, name +.. index:: ! instance, function type, function instance, table instance, memory instance, global instance, element instance, data instance, export instance, table address, memory address, global address, element address, data address, index, name pair: abstract syntax; module instance pair: module; instance .. _syntax-moduleinst: @@ -197,6 +211,8 @@ and collects runtime representations of all entities that are imported, defined, \MITABLES & \tableaddr^\ast, \\ \MIMEMS & \memaddr^\ast, \\ \MIGLOBALS & \globaladdr^\ast, \\ + \MIELEMS & \elemaddr^\ast, \\ + \MIDATAS & \dataaddr^\ast, \\ \MIEXPORTS & \exportinst^\ast ~\} \\ \end{array} \end{array} @@ -310,6 +326,42 @@ The value of mutable globals can be mutated through :ref:`variable instructions It is an invariant of the semantics that the value has a type :ref:`matching ` the :ref:`value type ` of :math:`\globaltype`. +.. index:: ! element instance, element segment, embedder, element expression + pair: abstract syntax; element instance + pair: element; instance +.. _syntax-eleminst: + +Element Instances +~~~~~~~~~~~~~~~~~ + +An *element instance* is the runtime representation of an :ref:`element segment `. +It holds a vector of references and their common :ref:`type `. + +.. math:: + \begin{array}{llll} + \production{(element instance)} & \eleminst &::=& + \{ \EITYPE~\reftype, \EIELEM~\vec(\funcelem) \} \\ + \end{array} + + +.. index:: ! data instance, data segment, embedder, byte + pair: abstract syntax; data instance + pair: data; instance +.. _syntax-datainst: + +Data Instances +~~~~~~~~~~~~~~ + +An *data instance* is the runtime representation of a :ref:`data segment `. +It holds a vector of :ref:`bytes `. + +.. math:: + \begin{array}{llll} + \production{(data instance)} & \datainst &::=& + \{ \DIDATA~\vec(\byte) \} \\ + \end{array} + + .. index:: ! export instance, export, name, external value pair: abstract syntax; export instance pair: export; instance @@ -363,8 +415,6 @@ It filters out entries of a specific kind in an order-preserving fashion: * :math:`\evglobals(\externval^\ast) = [\globaladdr ~|~ (\EVGLOBAL~\globaladdr) \in \externval^\ast]` - - .. index:: ! stack, ! frame, ! label, instruction, store, activation, function, call, local, module instance pair: abstract syntax; frame pair: abstract syntax; label @@ -461,8 +511,6 @@ Conventions .. _syntax-trap: .. _syntax-reffuncaddr: .. _syntax-invoke: -.. _syntax-init_elem: -.. _syntax-init_data: .. _syntax-instr-admin: Administrative Instructions @@ -481,8 +529,6 @@ In order to express the reduction of :ref:`traps `, :ref:`calls `, identified by its :ref:`address `. It unifies the handling of different forms of calls. -The |INITELEM| and |INITDATA| instructions perform initialization of :ref:`element ` and :ref:`data ` segments during module :ref:`instantiation `. - -.. note:: - The reason for splitting instantiation into individual reduction steps is to provide a semantics that is compatible with future extensions like threads. - The |LABEL| and |FRAME| instructions model :ref:`labels ` and :ref:`frames ` :ref:`"on the stack" `. Moreover, the administrative syntax maintains the nesting structure of the original :ref:`structured control instruction ` or :ref:`function body ` and their :ref:`instruction sequences ` with an |END| marker. That way, the end of the inner instruction sequence is known when part of an outer sequence. diff --git a/document/core/index.rst b/document/core/index.rst index fac7e53567..139a05b04e 100644 --- a/document/core/index.rst +++ b/document/core/index.rst @@ -3,7 +3,7 @@ WebAssembly Specification .. only:: html - | Release |release| + reference types (Draft, |today|) + | Release |release| + bulk instructions + reference types (Draft, |today|) | Editor: Andreas Rossberg diff --git a/document/core/syntax/conventions.rst b/document/core/syntax/conventions.rst index c0890ba98f..979d6bc4e3 100644 --- a/document/core/syntax/conventions.rst +++ b/document/core/syntax/conventions.rst @@ -41,6 +41,9 @@ The following conventions are adopted in defining grammar rules for abstract syn * Some productions are augmented with side conditions in parentheses, ":math:`(\iff \X{condition})`", that provide a shorthand for a combinatorial expansion of the production into many separate cases. +* If the same meta variable or non-terminal symbol appears multiple times in a production, then all those occurrences must have the same instantiation. + (This is a shorthand for a side condition requiring multiple different variables to be equal.) + .. _notation-epsilon: .. _notation-length: @@ -82,6 +85,7 @@ Moreover, the following conventions are employed: (similarly for :math:`x^\ast`, :math:`x^+`, :math:`x^?`). This implicitly expresses a form of mapping syntactic constructions over a sequence. + Productions of the following form are interpreted as *records* that map a fixed set of fields :math:`\K{field}_i` to "values" :math:`A_i`, respectively: .. math:: diff --git a/document/core/syntax/instructions.rst b/document/core/syntax/instructions.rst index cddf8ab21f..87a11b17cd 100644 --- a/document/core/syntax/instructions.rst +++ b/document/core/syntax/instructions.rst @@ -243,17 +243,17 @@ The |LOCALTEE| instruction is like |LOCALSET| but also returns its argument. .. index:: ! table instruction, table, table index, trap pair: abstract syntax; instruction +.. _syntax-instr-table: .. _syntax-table.get: .. _syntax-table.set: .. _syntax-table.size: .. _syntax-table.grow: .. _syntax-table.fill: -.. _syntax-instr-table: Table Instructions ~~~~~~~~~~~~~~~~~~ -Instructions in this group are concerned with accessing :ref:`tables `. +Instructions in this group are concerned with tables :ref:`table `. .. math:: \begin{array}{llcl} @@ -264,6 +264,9 @@ Instructions in this group are concerned with accessing :ref:`tables ` into a table. +The |ELEMDROP| instruction prevents further use of a passive element segment. This instruction is intended to be used as an optimization hint. After an element segment is dropped its elements can no longer be retrieved, so the memory used by this segment may be freed. + An additional instruction that accesses a table is the :ref:`control instruction ` |CALLINDIRECT|. @@ -306,7 +313,11 @@ Instructions in this group are concerned with linear :ref:`memory `. \K{i}\X{nn}\K{.}\STORE\K{16}~\memarg ~|~ \K{i64.}\STORE\K{32}~\memarg \\&&|& \MEMORYSIZE \\&&|& - \MEMORYGROW \\ + \MEMORYGROW \\&&|& + \MEMORYFILL \\&&|& + \MEMORYCOPY \\&&|& + \MEMORYINIT~\dataidx \\&&|& + \DATADROP~\dataidx \\ \end{array} Memory is accessed with |LOAD| and |STORE| instructions for the different :ref:`value types `. @@ -325,6 +336,11 @@ The |MEMORYSIZE| instruction returns the current size of a memory. The |MEMORYGROW| instruction grows memory by a given delta and returns the previous size, or :math:`-1` if enough memory cannot be allocated. Both instructions operate in units of :ref:`page size `. +The |MEMORYFILL| instruction sets all values in a region to a given byte. +The |MEMORYCOPY| instruction copies data from a source memory region to a possibly overlapping destination region. +The |MEMORYINIT| instruction copies data from a :ref:`passive data segment ` into a memory. +The |DATADROP| instruction prevents further use of a passive data segment. This instruction is intended to be used as an optimization hint. After a data segment is dropped its data can no longer be retrieved, so the memory used by this segment may be freed. + .. note:: In the current version of WebAssembly, all memory instructions implicitly operate on :ref:`memory ` :ref:`index ` :math:`0`. diff --git a/document/core/syntax/modules.rst b/document/core/syntax/modules.rst index 7913138986..91562bce6f 100644 --- a/document/core/syntax/modules.rst +++ b/document/core/syntax/modules.rst @@ -9,7 +9,7 @@ WebAssembly programs are organized into *modules*, which are the unit of deployment, loading, and compilation. A module collects definitions for :ref:`types `, :ref:`functions `, :ref:`tables `, :ref:`memories `, and :ref:`globals `. In addition, it can declare :ref:`imports ` and :ref:`exports ` -and provide initialization logic in the form of :ref:`data ` and :ref:`element ` segments or a :ref:`start function `. +and provide initialization in the form of :ref:`data ` and :ref:`element ` segments, or a :ref:`start function `. .. math:: \begin{array}{lllll} @@ -19,8 +19,8 @@ and provide initialization logic in the form of :ref:`data ` and :r \MTABLES~\vec(\table), \\&&&& \MMEMS~\vec(\mem), \\&&&& \MGLOBALS~\vec(\global), \\&&&& - \MELEM~\vec(\elem), \\&&&& - \MDATA~\vec(\data), \\&&&& + \MELEMS~\vec(\elem), \\&&&& + \MDATAS~\vec(\data), \\&&&& \MSTART~\start^?, \\&&&& \MIMPORTS~\vec(\import), \\&&&& \MEXPORTS~\vec(\export) \quad\} \\ @@ -29,12 +29,14 @@ and provide initialization logic in the form of :ref:`data ` and :r Each of the vectors -- and thus the entire module -- may be empty. -.. index:: ! index, ! index space, ! type index, ! function index, ! table index, ! memory index, ! global index, ! local index, ! label index, function, global, table, memory, local, parameter, import +.. index:: ! index, ! index space, ! type index, ! function index, ! table index, ! memory index, ! global index, ! local index, ! label index, ! element index, ! data index, function, global, table, memory, element, data, local, parameter, import pair: abstract syntax; type index pair: abstract syntax; function index pair: abstract syntax; table index pair: abstract syntax; memory index pair: abstract syntax; global index + pair: abstract syntax; element index + pair: abstract syntax; data index pair: abstract syntax; local index pair: abstract syntax; label index pair: type; index @@ -42,6 +44,8 @@ Each of the vectors -- and thus the entire module -- may be empty. pair: table; index pair: memory; index pair: global; index + pair: element; index + pair: data; index pair: local; index pair: label; index .. _syntax-typeidx: @@ -49,6 +53,8 @@ Each of the vectors -- and thus the entire module -- may be empty. .. _syntax-tableidx: .. _syntax-memidx: .. _syntax-globalidx: +.. _syntax-elemidx: +.. _syntax-dataidx: .. _syntax-localidx: .. _syntax-labelidx: .. _syntax-index: @@ -66,6 +72,8 @@ Each class of definition has its own *index space*, as distinguished by the foll \production{table index} & \tableidx &::=& \u32 \\ \production{memory index} & \memidx &::=& \u32 \\ \production{global index} & \globalidx &::=& \u32 \\ + \production{element index} & \elemidx &::=& \u32 \\ + \production{data index} & \dataidx &::=& \u32 \\ \production{local index} & \localidx &::=& \u32 \\ \production{label index} & \labelidx &::=& \u32 \\ \end{array} @@ -73,11 +81,24 @@ Each class of definition has its own *index space*, as distinguished by the foll The index space for :ref:`functions `, :ref:`tables `, :ref:`memories ` and :ref:`globals ` includes respective :ref:`imports ` declared in the same module. The indices of these imports precede the indices of other definitions in the same index space. +Element indices reference :ref:`element segments ` and data indices reference :ref:`data segments `. + The index space for :ref:`locals ` is only accessible inside a :ref:`function ` and includes the parameters of that function, which precede the local variables. Label indices reference :ref:`structured control instructions ` inside an instruction sequence. +.. _free-typeidx: +.. _free-funcidx: +.. _free-tableidx: +.. _free-memidx: +.. _free-globalidx: +.. _free-elemidx: +.. _free-dataidx: +.. _free-localidx: +.. _free-labelidx: +.. _free-index: + Conventions ........... @@ -85,6 +106,11 @@ Conventions * The meta variables :math:`x, y` range over indices in any of the other index spaces. +* The notation :math:`\F{idx}(A)` denotes the set of indices from index space :math:`\X{idx}` occurring free in :math:`A`. + +.. note:: + For example, if :math:`\instr^\ast` is :math:`(\DATADROP~x) (\MEMORYINIT~y)`, then :math:`\freedataidx(\instr^\ast) = \{x, y\}`. + .. index:: ! type definition, type index, function type pair: abstract syntax; type definition @@ -216,50 +242,71 @@ Globals are referenced through :ref:`global indices `, starting with the smallest index not referencing a global :ref:`import `. -.. index:: ! element, table, table index, expression, constant, function index, vector +.. index:: ! element, active, passive, element index, table, table index, expression, constant, function index, vector pair: abstract syntax; element single: table; element single: element; segment .. _syntax-elem: +.. _syntax-elemmode: Element Segments ~~~~~~~~~~~~~~~~ -The initial contents of a table is uninitialized. -The |MELEM| component of a module defines a vector of *element segments* that initialize a subrange of a table, at a given offset, from a static :ref:`vector ` of elements. +The initial contents of a table is uninitialized. *Element segments* can be used to initialize a subrange of a table from a static :ref:`vector ` of elements. + +The |MELEMS| component of a module defines a vector of element segments. +Each element segment defines an :ref:`reference type ` and a corresponding list of :ref:`constant ` element :ref:`expressions `. + +Element segments have a mode that identifies them as either *passive* or *active*. +A passive element segment's elements can be copied to a table using the |TABLEINIT| instruction. +An active element segment copies its elements into a table during :ref:`instantiation `, as specified by a :ref:`table index ` and a :ref:`constant ` :ref:`expression ` defining an offset into that table. .. math:: \begin{array}{llll} \production{element segment} & \elem &::=& - \{ \ETABLE~\tableidx, \EOFFSET~\expr, \EINIT~\vec(\funcidx) \} \\ + \{ \ETYPE~\reftype, \EINIT~\vec(\expr), \EMODE~\elemmode \} \\ + \production{element segment mode} & \elemmode &::=& + \EPASSIVE \\&&|& + \EACTIVE~\{ \ETABLE~\tableidx, \EOFFSET~\expr \} \\ \end{array} The |EOFFSET| is given by a :ref:`constant ` :ref:`expression `. +Element segments are referenced through :ref:`element indices `. + .. note:: In the current version of WebAssembly, only tables of element type |FUNCREF| can be initialized with an element segment. This limitation may be lifted in the future. -.. index:: ! data, memory, memory index, expression, constant, byte, vector +.. index:: ! data, active, passive, data index, memory, memory index, expression, constant, byte, vector pair: abstract syntax; data single: memory; data single: data; segment .. _syntax-data: +.. _syntax-datamode: Data Segments ~~~~~~~~~~~~~ -The initial contents of a :ref:`memory ` are zero-valued bytes. -The |MDATA| component of a module defines a vector of *data segments* that initialize a range of memory, at a given offset, with a static :ref:`vector ` of :ref:`bytes `. +The initial contents of a :ref:`memory ` are zero bytes. *Data segments* can be used to initialize a range of memory from a static :ref:`vector ` of :ref:`bytes `. + +The |MDATAS| component of a module defines a vector of data segments. + +Like element segments, data segments have a mode that identifies them as either *passive* or *active*. +A passive data segment's contents can be copied into a memory using the |MEMORYINIT| instruction. +An active data segment copies its contents into a memory during :ref:`instantiation `, as specified by a :ref:`memory index ` and a :ref:`constant ` :ref:`expression ` defining an offset into that memory. .. math:: \begin{array}{llll} \production{data segment} & \data &::=& - \{ \DMEM~\memidx, \DOFFSET~\expr, \DINIT~\vec(\byte) \} \\ + \{ \DINIT~\vec(\byte), \DMODE~\datamode \} \\ + \production{data segment mode} & \datamode &::=& + \DPASSIVE \\&&|& + \DACTIVE~\{ \DMEM~\memidx, \DOFFSET~\expr \} \\ \end{array} -The |DOFFSET| is given by a :ref:`constant ` :ref:`expression `. +Data segments are referenced through :ref:`data indices `. .. note:: In the current version of WebAssembly, at most one memory is allowed in a module. diff --git a/document/core/text/conventions.rst b/document/core/text/conventions.rst index c73e9c000a..ea62cc4b77 100644 --- a/document/core/text/conventions.rst +++ b/document/core/text/conventions.rst @@ -54,6 +54,8 @@ In order to distinguish symbols of the textual syntax from symbols of the abstra * Some productions are augmented by side conditions in parentheses, which restrict the applicability of the production. They provide a shorthand for a combinatorial expansion of the production into many separate cases. +* If the same meta variable or non-terminal symbol appears multiple times in a production (in the syntax or in an attribute), then all those occurrences must have the same instantiation. + .. _text-syntactic: * A distinction is made between *lexical* and *syntactic* productions. For the latter, arbitrary :ref:`white space ` is allowed in any place where the grammar contains spaces. The productions defining :ref:`lexical syntax ` and the syntax of :Ref:`values ` are considered lexical, all others are syntactic. @@ -122,6 +124,8 @@ It is convenient to define identifier contexts as :ref:`records ` can be given inline with a table definitio .. math:: \begin{array}{llclll} \production{module field} & - \text{(}~\text{table}~~\Tid^?~~\Treftype~~\text{(}~\text{elem}~~x^n{:}\Tvec(\Tfuncidx)~\text{)}~~\text{)} \quad\equiv \\ & \qquad + \text{(}~\text{table}~~\Tid^?~~\Treftype~~\text{(}~\text{elem}~~\Telemlist~\text{)} \quad\equiv \\ & \qquad + \text{(}~\text{table}~~\Tid'~~n~~n~~\Treftype~\text{)}~~ + \text{(}~\text{elem}~~\text{(}~\text{table}~~\Tid'~\text{)}~~\text{(}~\text{i32.const}~~\text{0}~\text{)}~~\Telemlist~\text{)} + \\ & \qquad\qquad + (\iff \Tid' = \Tid^? \neq \epsilon \vee \Tid' \idfresh) \\ + \end{array} + +.. math:: + \begin{array}{llclll} + \production{module field} & + \text{(}~\text{table}~~\Tid^?~~\Treftype~~\text{(}~\text{elem}~~x^n{:}\Tvec(\Texpr)~\text{)}~~\text{)} \quad\equiv \\ & \qquad \text{(}~\text{table}~~\Tid'~~n~~n~~\Treftype~\text{)}~~ - \text{(}~\text{elem}~~\Tid'~~\text{(}~\text{i32.const}~~\text{0}~\text{)}~~\Tvec(\Tfuncidx)~\text{)} + \text{(}~\text{elem}~~\Tid'~~\text{(}~\text{i32.const}~~\text{0}~\text{)}~~\Tvec(\Texpr)~\text{)} \\ & \qquad\qquad (\iff \Tid' = \Tid^? \neq \epsilon \vee \Tid' \idfresh) \\ \end{array} @@ -339,7 +357,7 @@ A :ref:`data segment ` can be given inline with a memory definition, \production{module field} & \text{(}~\text{memory}~~\Tid^?~~\text{(}~\text{data}~~b^n{:}\Tdatastring~\text{)}~~\text{)} \quad\equiv \\ & \qquad \text{(}~\text{memory}~~\Tid'~~m~~m~\text{)}~~ - \text{(}~\text{data}~~\Tid'~~\text{(}~\text{i32.const}~~\text{0}~\text{)}~~\Tdatastring~\text{)} + \text{(}~\text{data}~~\text{(}~\text{memory}~~\Tid'~\text{)}~~\text{(}~\text{i32.const}~~\text{0}~\text{)}~~\Tdatastring~\text{)} \\ & \qquad\qquad (\iff \Tid' = \Tid^? \neq \epsilon \vee \Tid' \idfresh, m = \F{ceil}(n / 64\F{Ki})) \\ \end{array} @@ -466,28 +484,39 @@ A :ref:`start function ` is defined in terms of its index. single: table; element single: element; segment .. _text-elem: +.. _text-elemlist: +.. _text-elemexpr: +.. _text-tableuse: Element Segments ~~~~~~~~~~~~~~~~ Element segments allow for an optional :ref:`table index ` to identify the table to initialize. +.. todo:: TODO: multi-instr elemexpr + .. math:: \begin{array}{llclll} \production{element segment} & \Telem_I &::=& - \text{(}~\text{elem}~~x{:}\Ttableidx_I~~\text{(}~\text{offset}~~e{:}\Texpr_I~\text{)}~~y^\ast{:}\Tvec(\Tfuncidx_I)~\text{)} \\ &&& \qquad - \Rightarrow\quad \{ \ETABLE~x, \EOFFSET~e, \EINIT~y^\ast \} \\ + \text{(}~\text{elem}~~\Tid^?~~(et, y^\ast){:}\Telemlist~\text{)} \\ &&& \qquad + \Rightarrow\quad \{ \ETYPE~et, \EINIT~y^\ast, \EMODE~\EPASSIVE \} \\ &&|& + \text{(}~\text{elem}~~\Tid^?~~x{:}\Ttableuse_I~~\text{(}~\text{offset}~~e{:}\Texpr_I~\text{)}~~(et, y^\ast){:}\Telemlist~\text{)} \\ &&& \qquad + \Rightarrow\quad \{ \ETYPE~et, \EINIT~y^\ast, \EMODE~\EACTIVE~\{ \ETABLE~x, \EOFFSET~e \} \} \\ + \production{element list} & \Telemlist &::=& + t{:}\Treftype~~y^\ast{:}\Tvec(\Telemexpr_I) \qquad\Rightarrow\quad ( \ETYPE~t, \EINIT~y^\ast ) \\ + \production{element expression} & \Telemexpr &::=& + \text{(}~e{:}\Tinstr~\text{)} + \quad\Rightarrow\quad e \\ + \production{table use} & \Ttableuse_I &::=& + \text{(}~\text{table}~~x{:}\Ttableidx_I ~\text{)} + \quad\Rightarrow\quad x \\ \end{array} -.. note:: - In the current version of WebAssembly, the only valid table index is 0 - or a symbolic :ref:`table identifier ` resolving to the same value. - Abbreviations ............. -As an abbreviation, a single instruction may occur in place of the offset: +As an abbreviation, a single instruction may occur in place of the offset of an active element segment: .. math:: \begin{array}{llcll} @@ -496,14 +525,26 @@ As an abbreviation, a single instruction may occur in place of the offset: \text{(}~\text{offset}~~\Tinstr~\text{)} \end{array} -Also, the table index can be omitted, defaulting to :math:`\T{0}`. +Also, the element list may be written as just a sequence of :ref:`function indices `: + +.. math:: + \begin{array}{llcll} + \production{element list} & + \text{func}~~\Tvec(\Tfuncidx_I) &\equiv& + \text{funcref}~~\Tvec(\text{(}~\text{ref.func}~~\Tfuncidx_I~\text{)}) + \end{array} + +Also, a table use can be omitted, defaulting to :math:`\T{0}`. +Furthermore, for backwards compatibility with earlier versions of WebAssembly, if the table use is omitted, the :math:`\text{func}` keyword can be omitted as well. .. math:: \begin{array}{llclll} + \production{table use} & + \epsilon &\equiv& \text{(}~\text{table}~~\text{0}~\text{)} \\ \production{element segment} & - \text{(}~\text{elem}~~\text{(}~\text{offset}~~\Texpr_I~\text{)}~~\dots~\text{)} + \text{(}~\text{elem}~~\Tid^?~~\text{(}~\text{offset}~~\Texpr_I~\text{)}~~\Tvec(\Tfuncidx_I)~\text{)} &\equiv& - \text{(}~\text{elem}~~0~~\text{(}~\text{offset}~~\Texpr_I~\text{)}~~\dots~\text{)} + \text{(}~\text{elem}~~\Tid^?~~\text{(}~\text{table}~~\text{0}~\text{)}~~\text{(}~\text{offset}~~\Texpr_I~\text{)}~~\text{func}~~\Tvec(\Tfuncidx_I)~\text{)} \end{array} As another abbreviation, element segments may also be specified inline with :ref:`table ` definitions; see the respective section. @@ -515,6 +556,7 @@ As another abbreviation, element segments may also be specified inline with :ref single: data; segment .. _text-datastring: .. _text-data: +.. _test-memuse: Data Segments ~~~~~~~~~~~~~ @@ -525,10 +567,15 @@ The data is written as a :ref:`string `, which may be split up into .. math:: \begin{array}{llclll} \production{data segment} & \Tdata_I &::=& - \text{(}~\text{data}~~x{:}\Tmemidx_I~~\text{(}~\text{offset}~~e{:}\Texpr_I~\text{)}~~b^\ast{:}\Tdatastring~\text{)} \\ &&& \qquad - \Rightarrow\quad \{ \DMEM~x', \DOFFSET~e, \DINIT~b^\ast \} \\[1ex] + \text{(}~\text{data}~~\Tid^?~~b^\ast{:}\Tdatastring~\text{)} \\ &&& \qquad + \Rightarrow\quad \{ \DINIT~b^\ast, \DMODE~\DPASSIVE \} \\ &&|& + \text{(}~\text{data}~~\Tid^?~~x{:}\Tmemuse_I~~\text{(}~\text{offset}~~e{:}\Texpr_I~\text{)}~~b^\ast{:}\Tdatastring~\text{)} \\ &&& \qquad + \Rightarrow\quad \{ \DINIT~b^\ast, \DMODE~\DACTIVE~\{ \DMEM~x', \DOFFSET~e \} \} \\ \production{data string} & \Tdatastring &::=& (b^\ast{:}\Tstring)^\ast \quad\Rightarrow\quad \concat((b^\ast)^\ast) \\ + \production{memory use} & \Tmemuse_I &::=& + \text{(}~\text{memory}~~x{:}\Tmemidx_I ~\text{)} + \quad\Rightarrow\quad x \\ \end{array} .. note:: @@ -539,7 +586,7 @@ The data is written as a :ref:`string `, which may be split up into Abbreviations ............. -As an abbreviation, a single instruction may occur in place of the offset: +As an abbreviation, a single instruction may occur in place of the offset of an active data segment: .. math:: \begin{array}{llcll} @@ -548,14 +595,12 @@ As an abbreviation, a single instruction may occur in place of the offset: \text{(}~\text{offset}~~\Tinstr~\text{)} \end{array} -Also, the memory index can be omitted, defaulting to :math:`\T{0}`. +Also, a memory use can be omitted, defaulting to :math:`\T{0}`. .. math:: \begin{array}{llclll} - \production{data segment} & - \text{(}~\text{data}~~\text{(}~\text{offset}~~\Texpr_I~\text{)}~~\dots~\text{)} - &\equiv& - \text{(}~\text{data}~~0~~\text{(}~\text{offset}~~\Texpr_I~\text{)}~~\dots~\text{)} + \production{memory use} & + \epsilon &\equiv& \text{(}~\text{memory}~~\text{0}~\text{)} \\ \end{array} As another abbreviation, data segments may also be specified inline with :ref:`memory ` definitions; see the respective section. @@ -599,8 +644,8 @@ The name serves a documentary role only. \X{gl}{:}\Tglobal_I &\Rightarrow& \{\MGLOBALS~\X{gl}\} \\ |& \X{ex}{:}\Texport_I &\Rightarrow& \{\MEXPORTS~\X{ex}\} \\ |& \X{st}{:}\Tstart_I &\Rightarrow& \{\MSTART~\X{st}\} \\ |& - \X{el}{:}\Telem_I &\Rightarrow& \{\MELEM~\X{el}\} \\ |& - \X{da}{:}\Tdata_I &\Rightarrow& \{\MDATA~\X{da}\} \\ + \X{el}{:}\Telem_I &\Rightarrow& \{\MELEMS~\X{el}\} \\ |& + \X{da}{:}\Tdata_I &\Rightarrow& \{\MDATAS~\X{da}\} \\ \end{array} \end{array} @@ -631,6 +676,10 @@ The definition of the initial :ref:`identifier context ` :math:`I` \{\IMEMS~(\Tid^?)\} \\ \F{idc}(\text{(}~\text{global}~\Tid^?~\dots~\text{)}) &=& \{\IGLOBALS~(\Tid^?)\} \\ + \F{idc}(\text{(}~\text{elem}~\Tid^?~\dots~\text{)}) &=& + \{\IELEM~(\Tid^?)\} \\ + \F{idc}(\text{(}~\text{data}~\Tid^?~\dots~\text{)}) &=& + \{\IDATA~(\Tid^?)\} \\ \F{idc}(\text{(}~\text{import}~\dots~\text{(}~\text{func}~\Tid^?~\dots~\text{)}~\text{)}) &=& \{\IFUNCS~(\Tid^?)\} \\ \F{idc}(\text{(}~\text{import}~\dots~\text{(}~\text{table}~\Tid^?~\dots~\text{)}~\text{)}) &=& diff --git a/document/core/util/macros.def b/document/core/util/macros.def index c1553b50b3..87b5ca2804 100644 --- a/document/core/util/macros.def +++ b/document/core/util/macros.def @@ -227,10 +227,25 @@ .. |tableidx| mathdef:: \xref{syntax/modules}{syntax-tableidx}{\X{tableidx}} .. |memidx| mathdef:: \xref{syntax/modules}{syntax-memidx}{\X{memidx}} .. |globalidx| mathdef:: \xref{syntax/modules}{syntax-globalidx}{\X{globalidx}} +.. |elemidx| mathdef:: \xref{syntax/modules}{syntax-elemidx}{\X{elemidx}} +.. |dataidx| mathdef:: \xref{syntax/modules}{syntax-dataidx}{\X{dataidx}} .. |localidx| mathdef:: \xref{syntax/modules}{syntax-localidx}{\X{localidx}} .. |labelidx| mathdef:: \xref{syntax/modules}{syntax-labelidx}{\X{labelidx}} +.. Indices, meta functions + +.. |freetypeidx| mathdef:: \xref{syntax/modules}{syntax-typeidx}{\F{typeidx}} +.. |freefuncidx| mathdef:: \xref{syntax/modules}{syntax-funcidx}{\F{funcidx}} +.. |freetableidx| mathdef:: \xref{syntax/modules}{syntax-tableidx}{\F{tableidx}} +.. |freememidx| mathdef:: \xref{syntax/modules}{syntax-memidx}{\F{memidx}} +.. |freeglobalidx| mathdef:: \xref{syntax/modules}{syntax-globalidx}{\F{globalidx}} +.. |freeelemidx| mathdef:: \xref{syntax/modules}{syntax-elemidx}{\F{elemidx}} +.. |freedataidx| mathdef:: \xref{syntax/modules}{syntax-dataidx}{\F{dataidx}} +.. |freelocalidx| mathdef:: \xref{syntax/modules}{syntax-localidx}{\F{localidx}} +.. |freelabelidx| mathdef:: \xref{syntax/modules}{syntax-labelidx}{\F{labelidx}} + + .. Modules, terminals .. |MTYPES| mathdef:: \xref{syntax/modules}{syntax-module}{\K{types}} @@ -240,8 +255,8 @@ .. |MGLOBALS| mathdef:: \xref{syntax/modules}{syntax-module}{\K{globals}} .. |MIMPORTS| mathdef:: \xref{syntax/modules}{syntax-module}{\K{imports}} .. |MEXPORTS| mathdef:: \xref{syntax/modules}{syntax-module}{\K{exports}} -.. |MDATA| mathdef:: \xref{syntax/modules}{syntax-module}{\K{data}} -.. |MELEM| mathdef:: \xref{syntax/modules}{syntax-module}{\K{elem}} +.. |MDATAS| mathdef:: \xref{syntax/modules}{syntax-module}{\K{datas}} +.. |MELEMS| mathdef:: \xref{syntax/modules}{syntax-module}{\K{elems}} .. |MSTART| mathdef:: \xref{syntax/modules}{syntax-module}{\K{start}} .. |FTYPE| mathdef:: \xref{syntax/modules}{syntax-func}{\K{type}} @@ -255,13 +270,20 @@ .. |GTYPE| mathdef:: \xref{syntax/modules}{syntax-global}{\K{type}} .. |GINIT| mathdef:: \xref{syntax/modules}{syntax-global}{\K{init}} +.. |ETYPE| mathdef:: \xref{syntax/modules}{syntax-elem}{\K{type}} +.. |EINIT| mathdef:: \xref{syntax/modules}{syntax-elem}{\K{init}} +.. |EMODE| mathdef:: \xref{syntax/modules}{syntax-elem}{\K{mode}} +.. |EPASSIVE| mathdef:: \xref{syntax/modules}{syntax-elem}{\K{passive}} +.. |EACTIVE| mathdef:: \xref{syntax/modules}{syntax-elem}{\K{active}} .. |ETABLE| mathdef:: \xref{syntax/modules}{syntax-elem}{\K{table}} .. |EOFFSET| mathdef:: \xref{syntax/modules}{syntax-elem}{\K{offset}} -.. |EINIT| mathdef:: \xref{syntax/modules}{syntax-elem}{\K{init}} -.. |DMEM| mathdef:: \xref{syntax/modules}{syntax-data}{\K{data}} -.. |DOFFSET| mathdef:: \xref{syntax/modules}{syntax-data}{\K{offset}} .. |DINIT| mathdef:: \xref{syntax/modules}{syntax-data}{\K{init}} +.. |DMODE| mathdef:: \xref{syntax/modules}{syntax-data}{\K{mode}} +.. |DPASSIVE| mathdef:: \xref{syntax/modules}{syntax-data}{\K{passive}} +.. |DACTIVE| mathdef:: \xref{syntax/modules}{syntax-data}{\K{active}} +.. |DMEM| mathdef:: \xref{syntax/modules}{syntax-data}{\K{memory}} +.. |DOFFSET| mathdef:: \xref{syntax/modules}{syntax-data}{\K{offset}} .. |SFUNC| mathdef:: \xref{syntax/modules}{syntax-start}{\K{func}} @@ -294,7 +316,9 @@ .. |importdesc| mathdef:: \xref{syntax/modules}{syntax-importdesc}{\X{importdesc}} .. |exportdesc| mathdef:: \xref{syntax/modules}{syntax-exportdesc}{\X{exportdesc}} .. |elem| mathdef:: \xref{syntax/modules}{syntax-elem}{\X{elem}} +.. |elemmode| mathdef:: \xref{syntax/modules}{syntax-elemmode}{\X{elemmode}} .. |data| mathdef:: \xref{syntax/modules}{syntax-data}{\X{data}} +.. |datamode| mathdef:: \xref{syntax/modules}{syntax-datamode}{\X{datamode}} .. |start| mathdef:: \xref{syntax/modules}{syntax-start}{\X{start}} @@ -339,11 +363,18 @@ .. |TABLESIZE| mathdef:: \xref{syntax/instructions}{syntax-instr-table}{\K{table.size}} .. |TABLEGROW| mathdef:: \xref{syntax/instructions}{syntax-instr-table}{\K{table.grow}} .. |TABLEFILL| mathdef:: \xref{syntax/instructions}{syntax-instr-table}{\K{table.fill}} +.. |TABLECOPY| mathdef:: \xref{syntax/instructions}{syntax-instr-table}{\K{table.copy}} +.. |TABLEINIT| mathdef:: \xref{syntax/instructions}{syntax-instr-table}{\K{table.init}} +.. |ELEMDROP| mathdef:: \xref{syntax/instructions}{syntax-instr-table}{\K{elem.drop}} .. |LOAD| mathdef:: \xref{syntax/instructions}{syntax-instr-memory}{\K{load}} .. |STORE| mathdef:: \xref{syntax/instructions}{syntax-instr-memory}{\K{store}} .. |MEMORYSIZE| mathdef:: \xref{syntax/instructions}{syntax-instr-memory}{\K{memory.size}} .. |MEMORYGROW| mathdef:: \xref{syntax/instructions}{syntax-instr-memory}{\K{memory.grow}} +.. |MEMORYFILL| mathdef:: \xref{syntax/instructions}{syntax-instr-memory}{\K{memory.fill}} +.. |MEMORYCOPY| mathdef:: \xref{syntax/instructions}{syntax-instr-memory}{\K{memory.copy}} +.. |MEMORYINIT| mathdef:: \xref{syntax/instructions}{syntax-instr-memory}{\K{memory.init}} +.. |DATADROP| mathdef:: \xref{syntax/instructions}{syntax-instr-memory}{\K{data.drop}} .. |REFNULL| mathdef:: \xref{syntax/instructions}{syntax-instr-ref}{\K{ref{.}null}} .. |REFISNULL| mathdef:: \xref{syntax/instructions}{syntax-instr-ref}{\K{ref{.}is\_null}} @@ -485,6 +516,8 @@ .. |Btableidx| mathdef:: \xref{binary/modules}{binary-tableidx}{\B{tableidx}} .. |Bmemidx| mathdef:: \xref{binary/modules}{binary-memidx}{\B{memidx}} .. |Bglobalidx| mathdef:: \xref{binary/modules}{binary-globalidx}{\B{globalidx}} +.. |Belemidx| mathdef:: \xref{binary/modules}{binary-elemidx}{\B{elemidx}} +.. |Bdataidx| mathdef:: \xref{binary/modules}{binary-dataidx}{\B{dataidx}} .. |Blocalidx| mathdef:: \xref{binary/modules}{binary-localidx}{\B{localidx}} .. |Blabelidx| mathdef:: \xref{binary/modules}{binary-labelidx}{\B{labelidx}} @@ -508,6 +541,7 @@ .. |Belemsec| mathdef:: \xref{binary/modules}{binary-elemsec}{\B{elemsec}} .. |Bdatasec| mathdef:: \xref{binary/modules}{binary-datasec}{\B{datasec}} .. |Bstartsec| mathdef:: \xref{binary/modules}{binary-startsec}{\B{startsec}} +.. |Bdatacountsec| mathdef:: \xref{binary/modules}{binary-datacountsec}{\B{datacountsec}} .. |Bcustom| mathdef:: \xref{binary/modules}{binary-customsec}{\B{custom}} .. |Btype| mathdef:: \xref{binary/modules}{binary-typedef}{\B{type}} @@ -520,6 +554,7 @@ .. |Bimportdesc| mathdef:: \xref{binary/modules}{binary-importdesc}{\B{importdesc}} .. |Bexportdesc| mathdef:: \xref{binary/modules}{binary-exportdesc}{\B{exportdesc}} .. |Belem| mathdef:: \xref{binary/modules}{binary-elem}{\B{elem}} +.. |Belemkind| mathdef:: \xref{binary/modules}{binary-elemkind}{\B{elemkind}} .. |Bcode| mathdef:: \xref{binary/modules}{binary-code}{\B{code}} .. |Blocal| mathdef:: \xref{binary/modules}{binary-local}{\B{local}} .. |Blocals| mathdef:: \xref{binary/modules}{binary-local}{\B{locals}} @@ -642,6 +677,8 @@ .. |Ttableidx| mathdef:: \xref{text/modules}{text-tableidx}{\T{tableidx}} .. |Tmemidx| mathdef:: \xref{text/modules}{text-memidx}{\T{memidx}} .. |Tglobalidx| mathdef:: \xref{text/modules}{text-globalidx}{\T{globalidx}} +.. |Telemidx| mathdef:: \xref{text/modules}{text-elemidx}{\T{elemidx}} +.. |Tdataidx| mathdef:: \xref{text/modules}{text-dataidx}{\T{dataidx}} .. |Tlocalidx| mathdef:: \xref{text/modules}{text-localidx}{\T{localidx}} .. |Tlabelidx| mathdef:: \xref{text/modules}{text-labelidx}{\T{labelidx}} @@ -670,11 +707,15 @@ .. |Timportdesc| mathdef:: \xref{text/modules}{text-importdesc}{\T{importdesc}} .. |Texportdesc| mathdef:: \xref{text/modules}{text-exportdesc}{\T{exportdesc}} .. |Telem| mathdef:: \xref{text/modules}{text-elem}{\T{elem}} +.. |Telemlist| mathdef:: \xref{text/modules}{text-elemlist}{\T{elemlist}} +.. |Telemexpr| mathdef:: \xref{text/modules}{text-elemexpr}{\X{elemexpr}} +.. |Ttableuse| mathdef:: \xref{text/modules}{text-tableuse}{\T{tableuse}} .. |Tcode| mathdef:: \xref{text/modules}{text-code}{\T{code}} .. |Tlocal| mathdef:: \xref{text/modules}{text-local}{\T{local}} .. |Tlocals| mathdef:: \xref{text/modules}{text-local}{\T{locals}} .. |Tdata| mathdef:: \xref{text/modules}{text-data}{\T{data}} .. |Tdatastring| mathdef:: \xref{text/modules}{text-datastring}{\T{datastring}} +.. |Tmemuse| mathdef:: \xref{text/modules}{text-memuse}{\T{memuse}} .. |Tstart| mathdef:: \xref{text/modules}{text-start}{\T{start}} @@ -704,6 +745,8 @@ .. |ITABLES| mathdef:: \xref{text/conventions}{text-context}{\K{tables}} .. |IMEMS| mathdef:: \xref{text/conventions}{text-context}{\K{mems}} .. |IGLOBALS| mathdef:: \xref{text/conventions}{text-context}{\K{globals}} +.. |IELEM| mathdef:: \xref{text/conventions}{text-context}{\K{elem}} +.. |IDATA| mathdef:: \xref{text/conventions}{text-context}{\K{data}} .. |ILOCALS| mathdef:: \xref{text/conventions}{text-context}{\K{locals}} .. |ILABELS| mathdef:: \xref{text/conventions}{text-context}{\K{labels}} @@ -734,6 +777,8 @@ .. |CTABLES| mathdef:: \xref{valid/conventions}{context}{\K{tables}} .. |CMEMS| mathdef:: \xref{valid/conventions}{context}{\K{mems}} .. |CGLOBALS| mathdef:: \xref{valid/conventions}{context}{\K{globals}} +.. |CELEMS| mathdef:: \xref{valid/conventions}{context}{\K{elems}} +.. |CDATAS| mathdef:: \xref{valid/conventions}{context}{\K{datas}} .. |CLOCALS| mathdef:: \xref{valid/conventions}{context}{\K{locals}} .. |CLABELS| mathdef:: \xref{valid/conventions}{context}{\K{labels}} .. |CRETURN| mathdef:: \xref{valid/conventions}{context}{\K{return}} @@ -764,7 +809,9 @@ .. |vdashmem| mathdef:: \xref{valid/modules}{valid-mem}{\vdash} .. |vdashglobal| mathdef:: \xref{valid/modules}{valid-global}{\vdash} .. |vdashelem| mathdef:: \xref{valid/modules}{valid-elem}{\vdash} +.. |vdashelemmode| mathdef:: \xref{valid/modules}{valid-elemmode}{\vdash} .. |vdashdata| mathdef:: \xref{valid/modules}{valid-data}{\vdash} +.. |vdashdatamode| mathdef:: \xref{valid/modules}{valid-datamode}{\vdash} .. |vdashstart| mathdef:: \xref{valid/modules}{valid-start}{\vdash} .. |vdashexport| mathdef:: \xref{valid/modules}{valid-export}{\vdash} .. |vdashexportdesc| mathdef:: \xref{valid/modules}{valid-exportdesc}{\vdash} @@ -791,6 +838,8 @@ .. |alloctable| mathdef:: \xref{exec/modules}{alloc-table}{\F{alloctable}} .. |allocmem| mathdef:: \xref{exec/modules}{alloc-mem}{\F{allocmem}} .. |allocglobal| mathdef:: \xref{exec/modules}{alloc-global}{\F{allocglobal}} +.. |allocelem| mathdef:: \xref{exec/modules}{alloc-elem}{\F{allocelem}} +.. |allocdata| mathdef:: \xref{exec/modules}{alloc-data}{\F{allocdata}} .. |allocmodule| mathdef:: \xref{exec/modules}{alloc-module}{\F{allocmodule}} .. |growtable| mathdef:: \xref{exec/modules}{grow-table}{\F{growtable}} @@ -804,9 +853,10 @@ .. |tableaddr| mathdef:: \xref{exec/runtime}{syntax-tableaddr}{\X{tableaddr}} .. |memaddr| mathdef:: \xref{exec/runtime}{syntax-memaddr}{\X{memaddr}} .. |globaladdr| mathdef:: \xref{exec/runtime}{syntax-globaladdr}{\X{globaladdr}} +.. |elemaddr| mathdef:: \xref{exec/runtime}{syntax-elemaddr}{\X{elemaddr}} +.. |dataaddr| mathdef:: \xref{exec/runtime}{syntax-dataaddr}{\X{dataaddr}} .. |hostaddr| mathdef:: \xref{exec/runtime}{syntax-hostaddr}{\X{hostaddr}} - .. Instances, terminals .. |FITYPE| mathdef:: \xref{exec/runtime}{syntax-funcinst}{\K{type}} @@ -823,6 +873,11 @@ .. |GITYPE| mathdef:: \xref{exec/runtime}{syntax-globalinst}{\K{type}} .. |GIVALUE| mathdef:: \xref{exec/runtime}{syntax-globalinst}{\K{value}} +.. |EITYPE| mathdef:: \xref{exec/runtime}{syntax-eleminst}{\K{type}} +.. |EIELEM| mathdef:: \xref{exec/runtime}{syntax-eleminst}{\K{elem}} + +.. |DIDATA| mathdef:: \xref{exec/runtime}{syntax-datainst}{\K{data}} + .. |EINAME| mathdef:: \xref{exec/runtime}{syntax-exportinst}{\K{name}} .. |EIVALUE| mathdef:: \xref{exec/runtime}{syntax-exportinst}{\K{value}} @@ -836,6 +891,8 @@ .. |MITABLES| mathdef:: \xref{exec/runtime}{syntax-moduleinst}{\K{tableaddrs}} .. |MIMEMS| mathdef:: \xref{exec/runtime}{syntax-moduleinst}{\K{memaddrs}} .. |MIGLOBALS| mathdef:: \xref{exec/runtime}{syntax-moduleinst}{\K{globaladdrs}} +.. |MIELEMS| mathdef:: \xref{exec/runtime}{syntax-moduleinst}{\K{elemaddrs}} +.. |MIDATAS| mathdef:: \xref{exec/runtime}{syntax-moduleinst}{\K{dataaddrs}} .. |MIEXPORTS| mathdef:: \xref{exec/runtime}{syntax-moduleinst}{\K{exports}} @@ -849,6 +906,8 @@ .. |funcelem| mathdef:: \xref{exec/runtime}{syntax-funcelem}{\X{funcelem}} .. |meminst| mathdef:: \xref{exec/runtime}{syntax-meminst}{\X{meminst}} .. |globalinst| mathdef:: \xref{exec/runtime}{syntax-globalinst}{\X{globalinst}} +.. |eleminst| mathdef:: \xref{exec/runtime}{syntax-eleminst}{\X{eleminst}} +.. |datainst| mathdef:: \xref{exec/runtime}{syntax-datainst}{\X{datainst}} .. |exportinst| mathdef:: \xref{exec/runtime}{syntax-exportinst}{\X{exportinst}} .. |hostfunc| mathdef:: \xref{exec/runtime}{syntax-hostfunc}{\X{hostfunc}} @@ -868,7 +927,8 @@ .. |STABLES| mathdef:: \xref{exec/runtime}{syntax-store}{\K{tables}} .. |SMEMS| mathdef:: \xref{exec/runtime}{syntax-store}{\K{mems}} .. |SGLOBALS| mathdef:: \xref{exec/runtime}{syntax-store}{\K{globals}} - +.. |SELEMS| mathdef:: \xref{exec/runtime}{syntax-store}{\K{elems}} +.. |SDATAS| mathdef:: \xref{exec/runtime}{syntax-store}{\K{datas}} .. Store, non-terminals @@ -896,8 +956,6 @@ .. |REFHOST| mathdef:: \xref{exec/runtime}{syntax-ref.host}{\K{ref{.}host}} .. |TRAP| mathdef:: \xref{exec/runtime}{syntax-trap}{\K{trap}} .. |INVOKE| mathdef:: \xref{exec/runtime}{syntax-invoke}{\K{invoke}} -.. |INITELEM| mathdef:: \xref{exec/runtime}{syntax-init_elem}{\K{init\_elem}} -.. |INITDATA| mathdef:: \xref{exec/runtime}{syntax-init_data}{\K{init\_data}} .. Values & Results, non-terminals @@ -1035,6 +1093,8 @@ .. |vdashtableinst| mathdef:: \xref{appendix/properties}{valid-tableinst}{\vdash} .. |vdashmeminst| mathdef:: \xref{appendix/properties}{valid-meminst}{\vdash} .. |vdashglobalinst| mathdef:: \xref{appendix/properties}{valid-globalinst}{\vdash} +.. |vdasheleminst| mathdef:: \xref{appendix/properties}{valid-eleminst}{\vdash} +.. |vdashdatainst| mathdef:: \xref{appendix/properties}{valid-datainst}{\vdash} .. |vdashexportinst| mathdef:: \xref{appendix/properties}{valid-exportinst}{\vdash} .. |vdashmoduleinst| mathdef:: \xref{appendix/properties}{valid-moduleinst}{\vdash} @@ -1047,6 +1107,8 @@ .. |vdashtableinstextends| mathdef:: \xref{appendix/properties}{extend-tableinst}{\vdash} .. |vdashmeminstextends| mathdef:: \xref{appendix/properties}{extend-meminst}{\vdash} .. |vdashglobalinstextends| mathdef:: \xref{appendix/properties}{extend-globalinst}{\vdash} +.. |vdasheleminstextends| mathdef:: \xref{appendix/properties}{extend-eleminst}{\vdash} +.. |vdashdatainstextends| mathdef:: \xref{appendix/properties}{extend-datainst}{\vdash} .. |vdashstoreextends| mathdef:: \xref{appendix/properties}{extend-store}{\vdash} diff --git a/document/core/valid/conventions.rst b/document/core/valid/conventions.rst index e316ff6876..7f132d7ea3 100644 --- a/document/core/valid/conventions.rst +++ b/document/core/valid/conventions.rst @@ -38,6 +38,8 @@ which collects relevant information about the surrounding :ref:`module ` :math: & \CTABLES & \tabletype^\ast, \\ & \CMEMS & \memtype^\ast, \\ & \CGLOBALS & \globaltype^\ast, \\ + & \CELEMS & {\ok}^\ast, \\ + & \CDATAS & {\ok}^\ast, \\ & \CLOCALS & \valtype^\ast, \\ & \CLABELS & \resulttype^\ast, \\ & \CRETURN & \resulttype^? ~\} \\ diff --git a/document/core/valid/instructions.rst b/document/core/valid/instructions.rst index 82f4fd8e15..9a27e94441 100644 --- a/document/core/valid/instructions.rst +++ b/document/core/valid/instructions.rst @@ -370,9 +370,7 @@ Variable Instructions } - - -.. index:: table instructions, table index, context +.. index:: table instruction, table index, context pair: validation; instruction single: abstract syntax; instruction .. _valid-instr-table: @@ -473,6 +471,61 @@ Table Instructions } +.. _valid-table.copy: + +:math:`\TABLECOPY` +..................... + +* The table :math:`C.\CTABLES[0]` must be defined in the context. + +* Then the instruction is valid with type :math:`[\I32~\I32~\I32] \to []`. + +.. math:: + \frac{ + C.\CTABLES[0] = \tabletype + }{ + C \vdashinstr \TABLECOPY : [\I32~\I32~\I32] \to [] + } + + +.. _valid-table.init: + +:math:`\TABLEINIT~x` +..................... + +* The table :math:`C.\CTABLES[0]` must be defined in the context. + +* The element segment :math:`C.\CELEMS[x]` must be defined in the context. + +* Then the instruction is valid with type :math:`[\I32~\I32~\I32] \to []`. + +.. math:: + \frac{ + C.\CTABLES[0] = \tabletype + \qquad + C.\CELEMS[x] = {\ok} + }{ + C \vdashinstr \TABLEINIT~x : [\I32~\I32~\I32] \to [] + } + + +.. _valid-elem.drop: + +:math:`\ELEMDROP~x` +................... + +* The element segment :math:`C.\CELEMS[x]` must be defined in the context. + +* Then the instruction is valid with type :math:`[] \to []`. + +.. math:: + \frac{ + C.\CELEMS[x] = {\ok} + }{ + C \vdashinstr \ELEMDROP~x : [] \to [] + } + + .. index:: memory instruction, memory index, context pair: validation; instruction single: abstract syntax; instruction @@ -598,6 +651,78 @@ Memory Instructions } +.. _valid-memory.fill: + +:math:`\MEMORYFILL` +................... + +* The memory :math:`C.\CMEMS[0]` must be defined in the context. + +* Then the instruction is valid with type :math:`[\I32~\I32~\I32] \to []`. + +.. math:: + \frac{ + C.\CMEMS[0] = \memtype + }{ + C \vdashinstr \MEMORYFILL : [\I32~\I32~\I32] \to [] + } + + +.. _valid-memory.copy: + +:math:`\MEMORYCOPY` +................... + +* The memory :math:`C.\CMEMS[0]` must be defined in the context. + +* Then the instruction is valid with type :math:`[\I32~\I32~\I32] \to []`. + +.. math:: + \frac{ + C.\CMEMS[0] = \memtype + }{ + C \vdashinstr \MEMORYCOPY : [\I32~\I32~\I32] \to [] + } + + +.. _valid-memory.init: + +:math:`\MEMORYINIT~x` +..................... + +* The memory :math:`C.\CMEMS[0]` must be defined in the context. + +* The data segment :math:`C.\CDATAS[x]` must be defined in the context. + +* Then the instruction is valid with type :math:`[\I32~\I32~\I32] \to []`. + +.. math:: + \frac{ + C.\CMEMS[0] = \memtype + \qquad + C.\CDATAS[x] = {\ok} + }{ + C \vdashinstr \MEMORYINIT~x : [\I32~\I32~\I32] \to [] + } + + +.. _valid-data.drop: + +:math:`\DATADROP~x` +................... + +* The data segment :math:`C.\CDATAS[x]` must be defined in the context. + +* Then the instruction is valid with type :math:`[] \to []`. + +.. math:: + \frac{ + C.\CDATAS[x] = {\ok} + }{ + C \vdashinstr \DATADROP~x : [] \to [] + } + + .. index:: control instructions, structured control, label, block, branch, result type, label index, function index, type index, vector, polymorphism, context pair: validation; instruction single: abstract syntax; instruction diff --git a/document/core/valid/modules.rst b/document/core/valid/modules.rst index 1a6f056505..461b9a5563 100644 --- a/document/core/valid/modules.rst +++ b/document/core/valid/modules.rst @@ -145,42 +145,76 @@ Globals :math:`\global` are classified by :ref:`global types Element Segments ~~~~~~~~~~~~~~~~ -Element segments :math:`\elem` are not classified by a type. +Element segments :math:`\elem` are not classified by any type but merely checked for well-formedness. -:math:`\{ \ETABLE~x, \EOFFSET~\expr, \EINIT~y^\ast \}` -...................................................... +:math:`\{ \ETYPE~et, \EINIT~e^\ast, \EMODE~\elemmode \}` +........................................................ + +* For each :math:`e_i` in :math:`e^\ast`, + + * The expression :math:`e_i` must be :ref:`valid `. + + * The expression :math:`e_i` must be :ref:`constant `. + +* The element mode :math:`\elemmode` must be valid for :ref:`reference type ` :math:`\X{et}`. + +* Then the element segment is valid. + + +.. math:: + \frac{ + (C \vdashexpr e \ok)^\ast + \qquad + (C \vdashexprconst e \const)^\ast + \qquad + C; \X{et} \vdashelemmode \elemmode \ok + }{ + C \vdashelem \{ \ETYPE~et, \EINIT~e^\ast, \EMODE~\elemmode \} \ok + } + + +.. _valid-elemmode: + +:math:`\EPASSIVE` +................. + +* The element mode is valid for any :ref:`reference type ` :math:`\X{et}`. + +.. math:: + \frac{ + }{ + C; \X{et} \vdashelemmode \EPASSIVE \ok + } + + +:math:`\EACTIVE~\{ \ETABLE~x, \EOFFSET~\expr \}` +................................................ * The table :math:`C.\CTABLES[x]` must be defined in the context. * Let :math:`\limits~t` be the :ref:`table type ` :math:`C.\CTABLES[x]`. -* The :ref:`reference type ` |FUNCREF| must :ref:`match ` the reference type :math:`t`. +* The :ref:`reference type ` :math:`\X{et}` must :ref:`match ` the reference type :math:`t`. * The expression :math:`\expr` must be :ref:`valid ` with :ref:`result type ` :math:`[\I32]`. * The expression :math:`\expr` must be :ref:`constant `. -* For each :math:`y_i` in :math:`y^\ast`, - the function :math:`C.\CFUNCS[y]` must be defined in the context. - -* Then the element segment is valid. - +* Then the element mode is valid for :ref:`reference type ` :math:`\X{et}`. .. math:: \frac{ \begin{array}{@{}c@{}} C.\CTABLES[x] = \limits~t \qquad - \vdashreftypematch \FUNCREF \matchesvaltype t + \vdashreftypematch \X{et} \matchesvaltype t \\ C \vdashexpr \expr : [\I32] \qquad C \vdashexprconst \expr \const - \qquad - (C.\CFUNCS[y] = \functype)^\ast \end{array} }{ - C \vdashelem \{ \ETABLE~x, \EOFFSET~\expr, \EINIT~y^\ast \} \ok + C; \X{et} \vdashelemmode \EACTIVE~\{ \ETABLE~x, \EOFFSET~\expr \} \ok } @@ -194,19 +228,47 @@ Element segments :math:`\elem` are not classified by a type. Data Segments ~~~~~~~~~~~~~ -Data segments :math:`\data` are not classified by any type. +Data segments :math:`\data` are not classified by any type but merely checked for well-formedness. -:math:`\{ \DMEM~x, \DOFFSET~\expr, \DINIT~b^\ast \}` +:math:`\{ \DINIT~b^\ast, \DMODE~\datamode \}` .................................................... +* The data mode :math:`\datamode` must be valid. + +* Then the data segment is valid. + +.. math:: + \frac{ + C \vdashdatamode \datamode \ok + }{ + C \vdashdata \{ \DINIT~b^\ast, \DMODE~\datamode \} \ok + } + + +.. _valid-datamode: + +:math:`\DPASSIVE` +................. + +* The data mode is valid. + +.. math:: + \frac{ + }{ + C \vdashdatamode \DPASSIVE \ok + } + + +:math:`\DACTIVE~\{ \DMEM~x, \DOFFSET~\expr \}` +.............................................. + * The memory :math:`C.\CMEMS[x]` must be defined in the context. * The expression :math:`\expr` must be :ref:`valid ` with :ref:`result type ` :math:`[\I32]`. * The expression :math:`\expr` must be :ref:`constant `. -* Then the data segment is valid. - +* Then the data mode is valid. .. math:: \frac{ @@ -216,7 +278,7 @@ Data segments :math:`\data` are not classified by any type. \qquad C \vdashexprconst \expr \const }{ - C \vdashdata \{ \DMEM~x, \DOFFSET~\expr, \DINIT~b^\ast \} \ok + C \vdashelemmode \EACTIVE~\{ \DMEM~x, \DOFFSET~\expr \} \ok } @@ -457,6 +519,10 @@ Instead, the context :math:`C` for validation of the module's content is constru * :math:`C.\CGLOBALS` is :math:`\etglobals(\X{it}^\ast)` concatenated with :math:`\X{gt}^\ast`, with the import's :ref:`external types ` :math:`\X{it}^\ast` and the internal :ref:`global types ` :math:`\X{gt}^\ast` as determined below, + * :math:`C.\CELEMS` is :math:`{\ok}^{N_e}`, where :math:`N_e` is the length of the vector :math:`\module.\MELEMS`, + + * :math:`C.\CDATAS` is :math:`{\ok}^{N_d}`, where :math:`N_d` is the length of the vector :math:`\module.\MDATAS`, + * :math:`C.\CLOCALS` is empty, * :math:`C.\CLABELS` is empty, @@ -484,10 +550,10 @@ Instead, the context :math:`C` for validation of the module's content is constru * Under the context :math:`C'`, the definition :math:`\global_i` must be :ref:`valid ` with a :ref:`global type ` :math:`\X{gt}_i`. - * For each :math:`\elem_i` in :math:`\module.\MELEM`, + * For each :math:`\elem_i` in :math:`\module.\MELEMS`, the segment :math:`\elem_i` must be :ref:`valid `. - * For each :math:`\data_i` in :math:`\module.\MDATA`, + * For each :math:`\data_i` in :math:`\module.\MDATAS`, the segment :math:`\data_i` must be :ref:`valid `. * If :math:`\module.\MSTART` is non-empty, @@ -530,9 +596,9 @@ Instead, the context :math:`C` for validation of the module's content is constru \quad (C' \vdashglobal \global : \X{gt})^\ast \\ - (C \vdashelem \elem \ok)^\ast + (C \vdashelem \elem \ok)^{N_e} \quad - (C \vdashdata \data \ok)^\ast + (C \vdashdata \data \ok)^{N_d} \quad (C \vdashstart \start \ok)^? \quad @@ -548,7 +614,7 @@ Instead, the context :math:`C` for validation of the module's content is constru \qquad \X{igt}^\ast = \etglobals(\X{it}^\ast) \\ - C = \{ \CTYPES~\functype^\ast, \CFUNCS~\X{ift}^\ast~\X{ft}^\ast, \CTABLES~\X{itt}^\ast~\X{tt}^\ast, \CMEMS~\X{imt}^\ast~\X{mt}^\ast, \CGLOBALS~\X{igt}^\ast~\X{gt}^\ast \} + C = \{ \CTYPES~\functype^\ast, \CFUNCS~\X{ift}^\ast~\X{ft}^\ast, \CTABLES~\X{itt}^\ast~\X{tt}^\ast, \CMEMS~\X{imt}^\ast~\X{mt}^\ast, \CGLOBALS~\X{igt}^\ast~\X{gt}^\ast, \CELEMS~{\ok}^{N_e}, \CDATAS~{\ok}^{N_d} \} \\ C' = \{ \CGLOBALS~\X{igt}^\ast \} \qquad @@ -564,8 +630,8 @@ Instead, the context :math:`C` for validation of the module's content is constru \MTABLES~\table^\ast, \MMEMS~\mem^\ast, \MGLOBALS~\global^\ast, \\ - \MELEM~\elem^\ast, - \MDATA~\data^\ast, + \MELEMS~\elem^\ast, + \MDATAS~\data^\ast, \MSTART~\start^?, \MIMPORTS~\import^\ast, \MEXPORTS~\export^\ast \} : \X{it}^\ast \to \X{et}^\ast \\ diff --git a/interpreter/README.md b/interpreter/README.md index 77c6a54319..546a1c4c50 100644 --- a/interpreter/README.md +++ b/interpreter/README.md @@ -229,10 +229,17 @@ op: table.size table.grow table.fill + table.copy + table.init + elem.drop .load((8|16|32)_)? ? ? .store(8|16|32)? ? ? memory.size memory.grow + memory.fill + memory.copy + memory.init + data.drop ref.null ref.isnull ref.func diff --git a/interpreter/binary/decode.ml b/interpreter/binary/decode.ml index 674240bb07..c97026215b 100644 --- a/interpreter/binary/decode.ml +++ b/interpreter/binary/decode.ml @@ -202,6 +202,7 @@ let var s = vu32 s let op s = u8 s let end_ s = expect 0x0b s "END opcode expected" +let zero_flag s = expect 0x00 s "zero flag expected" let memop s = let align = vu32 s in @@ -299,12 +300,8 @@ let rec instr s = | 0x3d -> let a, o = memop s in i64_store16 a o | 0x3e -> let a, o = memop s in i64_store32 a o - | 0x3f -> - expect 0x00 s "zero flag expected"; - memory_size - | 0x40 -> - expect 0x00 s "zero flag expected"; - memory_grow + | 0x3f -> zero_flag s; memory_size + | 0x40 -> zero_flag s; memory_grow | 0x41 -> i32_const (at vs32 s) | 0x42 -> i64_const (at vs64 s) @@ -447,13 +444,31 @@ let rec instr s = | 0xc0 | 0xc1 | 0xc2 | 0xc3 | 0xc4 | 0xc5 | 0xc6 | 0xc7 | 0xc8 | 0xc9 | 0xca | 0xcb | 0xcc | 0xcd | 0xce | 0xcf as b -> illegal s pos b - (* TODO: Allocate more adequate opcodes *) | 0xd0 -> ref_null | 0xd1 -> ref_is_null | 0xd2 -> ref_func (at var s) | 0xfc as b1 -> (match op s with + | 0x00 | 0x01 | 0x02 | 0x03 | 0x04 | 0x05 | 0x06 | 0x07 as b2 -> + illegal2 s pos b1 b2 + + | 0x08 -> + let x = at var s in + zero_flag s; memory_init x + | 0x09 -> data_drop (at var s) + | 0x0a -> zero_flag s; zero_flag s; memory_copy + | 0x0b -> zero_flag s; memory_fill + + | 0x0c -> + let y = at var s in + let x = at var s in + table_init x y + | 0x0d -> elem_drop (at var s) + | 0x0e -> + let x = at var s in + let y = at var s in + table_copy x y | 0x0f -> table_grow (at var s) | 0x10 -> table_size (at var s) | 0x11 -> table_fill (at var s) @@ -496,6 +511,7 @@ let id s = | 9 -> `ElemSection | 10 -> `CodeSection | 11 -> `DataSection + | 12 -> `DataCountSection | _ -> error s (pos s) "invalid section id" ) bo @@ -551,10 +567,6 @@ let table s = let table_section s = section `TableSection (vec (at table)) [] s -let elem_kind s = - match vs7 s with - | 0x00 -> FuncRefType - | _ -> error s (pos s - 1) "invalid elem kind" (* Memory section *) @@ -570,8 +582,8 @@ let memory_section s = let global s = let gtype = global_type s in - let value = const s in - {gtype; value} + let ginit = const s in + {gtype; ginit} let global_section s = section `GlobalSection (vec (at global)) [] s @@ -626,36 +638,93 @@ let code_section s = (* Element section *) -let segment dat kind s = - let pos = pos s in +let passive s = + Passive + +let active s = + let index = at var s in + let offset = const s in + Active {index; offset} + +let active_zero s = + let index = Source.(0l @@ Source.no_region) in + let offset = const s in + Active {index; offset} + +let elem_index s = + let x = at var s in + [Source.(ref_func x @@ x.at)] + +let elem_kind s = + match u8 s with + | 0x00 -> FuncRefType + | _ -> error s (pos s - 1) "invalid element kind" + +let elem s = match vu32 s with - | 0l -> - let index = Source.(0l @@ Source.no_region) in - let offset = const s in - let init = dat s in - {index; offset; init} - | 2l -> - let index = at var s in - let offset = const s in - let _ = kind s in - let init = dat s in - {index; offset; init} - | _ -> error s pos "invalid segment kind" - -let table_segment s = - segment (vec (at var)) elem_kind s + | 0x00l -> + let emode = at active_zero s in + let einit = vec (at elem_index) s in + {etype = FuncRefType; einit; emode} + | 0x01l -> + let emode = at passive s in + let etype = elem_kind s in + let einit = vec (at elem_index) s in + {etype; einit; emode} + | 0x02l -> + let emode = at active s in + let etype = elem_kind s in + let einit = vec (at elem_index) s in + {etype; einit; emode} + | 0x04l -> + let emode = at active_zero s in + let einit = vec const s in + {etype = FuncRefType; einit; emode} + | 0x05l -> + let emode = at passive s in + let etype = ref_type s in + let einit = vec const s in + {etype; einit; emode} + | 0x06l -> + let emode = at active s in + let etype = ref_type s in + let einit = vec const s in + {etype; einit; emode} + | _ -> error s (pos s - 1) "invalid elements segment kind" let elem_section s = - section `ElemSection (vec (at table_segment)) [] s + section `ElemSection (vec (at elem)) [] s (* Data section *) -let memory_segment s = - segment string (fun s -> ()) s +let data s = + match vu32 s with + | 0x00l -> + let dmode = at active_zero s in + let dinit = string s in + {dinit; dmode} + | 0x01l -> + let dmode = at passive s in + let dinit = string s in + {dinit; dmode} + | 0x02l -> + let dmode = at active s in + let dinit = string s in + {dinit; dmode} + | _ -> error s (pos s - 1) "invalid data segment kind" let data_section s = - section `DataSection (vec (at memory_segment)) [] s + section `DataSection (vec (at data)) [] s + + +(* DataCount section *) + +let data_count s = + Some (vu32 s) + +let data_count_section s = + section `DataCountSection data_count None s (* Custom section *) @@ -698,17 +767,24 @@ let module_ s = iterate custom_section s; let elems = elem_section s in iterate custom_section s; + let data_count = data_count_section s in + iterate custom_section s; let func_bodies = code_section s in iterate custom_section s; - let data = data_section s in + let datas = data_section s in iterate custom_section s; require (pos s = len s) s (len s) "junk after last section"; require (List.length func_types = List.length func_bodies) s (len s) "function and code section have inconsistent lengths"; + require (data_count = None || data_count = Some (Lib.List32.length datas)) + s (len s) "data count and data section have inconsistent lengths"; + require (data_count <> None || + List.for_all Free.(fun f -> (func f).datas = Set.empty) func_bodies) + s (len s) "data count section required"; let funcs = List.map2 Source.(fun t f -> {f.it with ftype = t} @@ f.at) func_types func_bodies - in {types; tables; memories; globals; funcs; imports; exports; elems; data; start} + in {types; tables; memories; globals; funcs; imports; exports; elems; datas; start} let decode name bs = at module_ (stream name bs) diff --git a/interpreter/binary/encode.ml b/interpreter/binary/encode.ml index f44df2158d..690697c79f 100644 --- a/interpreter/binary/encode.ml +++ b/interpreter/binary/encode.ml @@ -181,6 +181,9 @@ let encode m = | TableSize x -> op 0xfc; op 0x10; var x | TableGrow x -> op 0xfc; op 0x0f; var x | TableFill x -> op 0xfc; op 0x11; var x + | TableCopy (x, y) -> op 0xfc; op 0x0e; var x; var y + | TableInit (x, y) -> op 0xfc; op 0x0c; var y; var x + | ElemDrop x -> op 0xfc; op 0x0d; var x | Load ({ty = I32Type; sz = None; _} as mo) -> op 0x28; memop mo | Load ({ty = I64Type; sz = None; _} as mo) -> op 0x29; memop mo @@ -225,6 +228,14 @@ let encode m = | MemorySize -> op 0x3f; u8 0x00 | MemoryGrow -> op 0x40; u8 0x00 + | MemoryFill -> op 0xfc; op 0x0b; u8 0x00 + | MemoryCopy -> op 0xfc; op 0x0a; u8 0x00; u8 0x00 + | MemoryInit x -> op 0xfc; op 0x08; var x; u8 0x00 + | DataDrop x -> op 0xfc; op 0x09; var x + + | RefNull -> op 0xd0 + | RefIsNull -> op 0xd1 + | RefFunc x -> op 0xd2; var x | Const {it = I32 c; _} -> op 0x41; vs32 c | Const {it = I64 c; _} -> op 0x42; vs64 c @@ -378,11 +389,6 @@ let encode m = | Convert (F64 F64Op.DemoteF64) -> assert false | Convert (F64 F64Op.ReinterpretInt) -> op 0xbf - (* TODO: Allocate more adequate opcodes *) - | RefNull -> op 0xd0 - | RefIsNull -> op 0xd1 - | RefFunc x -> op 0xd2; var x - let const c = list instr c.it; end_ () @@ -442,8 +448,8 @@ let encode m = (* Global section *) let global g = - let {gtype; value} = g.it in - global_type gtype; const value + let {gtype; ginit} = g.it in + global_type gtype; const ginit let global_section gs = section 6 (vec global) gs (gs <> []) @@ -489,28 +495,66 @@ let encode m = section 10 (vec code) fs (fs <> []) (* Element section *) - let segment dat seg = - match seg.it with - | {index; offset; init} when index.it = 0l -> - u8 0x00; const offset; dat init - | {index; offset; init} -> - u8 0x02; var index; const offset; u8 0x00; dat init + let is_elem_kind = function + | FuncRefType -> true + | _ -> false + + let elem_kind = function + | FuncRefType -> u8 0x00 + | _ -> assert false - let table_segment seg = - segment (vec var) seg + let is_elem_index e = + match e.it with + | [{it = RefFunc _; _}] -> true + | _ -> false + + let elem_index e = + match e.it with + | [{it = RefFunc x; _}] -> var x + | _ -> assert false + + let elem seg = + let {etype; einit; emode} = seg.it in + if is_elem_kind etype && List.for_all is_elem_index einit then + match emode.it with + | Passive -> + vu32 0x01l; elem_kind etype; vec elem_index einit + | Active {index; offset} when index.it = 0l && etype = FuncRefType -> + vu32 0x00l; const offset; vec elem_index einit + | Active {index; offset} -> + vu32 0x02l; + var index; const offset; elem_kind etype; vec elem_index einit + else + match emode.it with + | Passive -> + vu32 0x05l; ref_type etype; vec const einit + | Active {index; offset} when index.it = 0l && etype = FuncRefType -> + vu32 0x04l; const offset; vec const einit + | Active {index; offset} -> + vu32 0x06l; var index; const offset; ref_type etype; vec const einit let elem_section elems = - section 9 (vec table_segment) elems (elems <> []) + section 9 (vec elem) elems (elems <> []) (* Data section *) - let memory_segment seg = - segment string seg - - let data_section data = - section 11 (vec memory_segment) data (data <> []) + let data seg = + let {dinit; dmode} = seg.it in + match dmode.it with + | Passive -> + vu32 0x01l; string dinit + | Active {index; offset} when index.it = 0l -> + vu32 0x00l; const offset; string dinit + | Active {index; offset} -> + vu32 0x02l; var index; const offset; string dinit + + let data_section datas = + section 11 (vec data) datas (datas <> []) + + (* Data count section *) + let data_count_section datas m = + section 12 len (List.length datas) Free.((module_ m).datas <> Set.empty) (* Module *) - let module_ m = u32 0x6d736100l; u32 version; @@ -523,7 +567,8 @@ let encode m = export_section m.it.exports; start_section m.it.start; elem_section m.it.elems; + data_count_section m.it.datas m; code_section m.it.funcs; - data_section m.it.data + data_section m.it.datas end in E.module_ m; to_string s diff --git a/interpreter/exec/eval.ml b/interpreter/exec/eval.ml index f690761bcd..7a9039fe07 100644 --- a/interpreter/exec/eval.ml +++ b/interpreter/exec/eval.ml @@ -85,6 +85,8 @@ let func (inst : module_inst) x = lookup "function" inst.funcs x let table (inst : module_inst) x = lookup "table" inst.tables x let memory (inst : module_inst) x = lookup "memory" inst.memories x let global (inst : module_inst) x = lookup "global" inst.globals x +let elem (inst : module_inst) x = lookup "element segment" inst.elems x +let data (inst : module_inst) x = lookup "data segment" inst.datas x let local (frame : frame) x = lookup "local" frame.locals x let any_ref inst x i at = @@ -115,6 +117,22 @@ let drop n (vs : 'a stack) at = * c : config *) +let mem_oob frame x i n = + I64.gt_u (I64.add (I64_convert.extend_i32_u i) (I64_convert.extend_i32_u n)) + (Memory.bound (memory frame.inst x)) + +let data_oob frame x i n = + I64.gt_u (I64.add (I64_convert.extend_i32_u i) (I64_convert.extend_i32_u n)) + (I64.of_int_u (String.length !(data frame.inst x))) + +let table_oob frame x i n = + I64.gt_u (I64.add (I64_convert.extend_i32_u i) (I64_convert.extend_i32_u n)) + (I64_convert.extend_i32_u (Table.size (table frame.inst x))) + +let elem_oob frame x i n = + I64.gt_u (I64.add (I64_convert.extend_i32_u i) (I64_convert.extend_i32_u n)) + (I64.of_int_u (List.length !(elem frame.inst x))) + let rec step (c : config) : config = let {frame; code = vs, es; _} = c in let e = List.hd es in @@ -134,27 +152,26 @@ let rec step (c : config) : config = | Loop (ts, es'), vs -> vs, [Label (0, [e' @@ e.at], ([], List.map plain es')) @@ e.at] - | If (ts, es1, es2), Num (I32 0l) :: vs' -> - vs', [Plain (Block (ts, es2)) @@ e.at] - | If (ts, es1, es2), Num (I32 i) :: vs' -> - vs', [Plain (Block (ts, es1)) @@ e.at] + if i = 0l then + vs', [Plain (Block (ts, es2)) @@ e.at] + else + vs', [Plain (Block (ts, es1)) @@ e.at] | Br x, vs -> [], [Breaking (x.it, vs) @@ e.at] - | BrIf x, Num (I32 0l) :: vs' -> - vs', [] - | BrIf x, Num (I32 i) :: vs' -> - vs', [Plain (Br x) @@ e.at] - - | BrTable (xs, x), Num (I32 i) :: vs' - when I32.ge_u i (Lib.List32.length xs) -> - vs', [Plain (Br x) @@ e.at] + if i = 0l then + vs', [] + else + vs', [Plain (Br x) @@ e.at] | BrTable (xs, x), Num (I32 i) :: vs' -> - vs', [Plain (Br (Lib.List32.nth xs i)) @@ e.at] + if I32.ge_u i (Lib.List32.length xs) then + vs', [Plain (Br x) @@ e.at] + else + vs', [Plain (Br (Lib.List32.nth xs i)) @@ e.at] | Return, vs -> [], [Returning vs @@ e.at] @@ -172,11 +189,11 @@ let rec step (c : config) : config = | Drop, v :: vs' -> vs', [] - | Select _, Num (I32 0l) :: v2 :: v1 :: vs' -> - v2 :: vs', [] - | Select _, Num (I32 i) :: v2 :: v1 :: vs' -> - v1 :: vs', [] + if i = 0l then + v2 :: vs', [] + else + v1 :: vs', [] | LocalGet x, vs -> !(local frame x) :: vs, [] @@ -216,40 +233,66 @@ let rec step (c : config) : config = with Table.SizeOverflow | Table.SizeLimit | Table.OutOfMemory -> -1l in Num (I32 result) :: vs', [] - | TableFill x, Num (I32 0l) :: Ref r :: Num (I32 i) :: vs' -> - if I32.gt_u i (Table.size (table frame.inst x)) then + | TableFill x, Num (I32 n) :: Ref r :: Num (I32 i) :: vs' -> + if table_oob frame x i n then vs', [Trapping (table_error e.at Table.Bounds) @@ e.at] + else if n = 0l then + vs', [] else + let _ = assert (I32.lt_u i 0xffff_ffffl) in + Ref r :: Num (I32 i) :: Num (I32 (I32.sub n 1l)) :: + Ref r :: Num (I32 (I32.add i 1l)) :: vs', + [Plain (TableSet x) @@ e.at; Plain (TableFill x) @@ e.at] + + | TableCopy (x, y), Num (I32 n) :: Num (I32 s) :: Num (I32 d) :: vs' -> + if table_oob frame x d n || table_oob frame y s n then + vs', [Trapping (table_error e.at Table.Bounds) @@ e.at] + else if n = 0l then vs', [] + else + (* TODO: turn into small-step, but needs reference values *) + let tab = table frame.inst x in (*TODO*) + (try Table.copy tab d s n; vs', [] + with exn -> vs', [Trapping (table_error e.at exn) @@ e.at]) - | TableFill x, Num (I32 n) :: Ref r :: Num (I32 i) :: vs' -> - assert (I32.lt_u i 0xffff_ffffl); - Ref r :: Num (I32 i) :: - Num (I32 (I32.sub n 1l)) :: Ref r :: Num (I32 (I32.add i 1l)) :: vs', - [Plain (TableSet x) @@ e.at; Plain (TableFill x) @@ e.at] + | TableInit (x, y), Num (I32 n) :: Num (I32 s) :: Num (I32 d) :: vs' -> + if table_oob frame x d n || elem_oob frame y s n then + vs', [Trapping (table_error e.at Table.Bounds) @@ e.at] + else if n = 0l then + vs', [] + else + (* TODO: turn into small-step, but needs reference values *) + let tab = table frame.inst x in + let seg = !(elem frame.inst y) in + (try Table.init tab seg d s n; vs', [] + with exn -> vs', [Trapping (table_error e.at exn) @@ e.at]) + + | ElemDrop x, vs -> + let seg = elem frame.inst x in + seg := []; + vs, [] | Load {offset; ty; sz; _}, Num (I32 i) :: vs' -> let mem = memory frame.inst (0l @@ e.at) in - let addr = I64_convert.extend_i32_u i in + let a = I64_convert.extend_i32_u i in (try let n = match sz with - | None -> Memory.load_num mem addr offset ty - | Some (sz, ext) -> Memory.load_packed sz ext mem addr offset ty + | None -> Memory.load_num mem a offset ty + | Some (sz, ext) -> Memory.load_packed sz ext mem a offset ty in Num n :: vs', [] with exn -> vs', [Trapping (memory_error e.at exn) @@ e.at]) | Store {offset; sz; _}, Num n :: Num (I32 i) :: vs' -> let mem = memory frame.inst (0l @@ e.at) in - let addr = I64_convert.extend_i32_u i in + let a = I64_convert.extend_i32_u i in (try (match sz with - | None -> Memory.store_num mem addr offset n - | Some sz -> Memory.store_packed sz mem addr offset n + | None -> Memory.store_num mem a offset n + | Some sz -> Memory.store_packed sz mem a offset n ); vs', [] with exn -> vs', [Trapping (memory_error e.at exn) @@ e.at]); - | MemorySize, vs -> let mem = memory frame.inst (0l @@ e.at) in Num (I32 (Memory.size mem)) :: vs, [] @@ -262,14 +305,87 @@ let rec step (c : config) : config = with Memory.SizeOverflow | Memory.SizeLimit | Memory.OutOfMemory -> -1l in Num (I32 result) :: vs', [] + | MemoryFill, Num (I32 n) :: Num k :: Num (I32 i) :: vs' -> + if mem_oob frame (0l @@ e.at) i n then + vs', [Trapping (memory_error e.at Memory.Bounds) @@ e.at] + else if n = 0l then + vs', [] + else + vs', List.map (at e.at) [ + Plain (Const (I32 i @@ e.at)); + Plain (Const (k @@ e.at)); + Plain (Store + {ty = I32Type; align = 0; offset = 0l; sz = Some Memory.Pack8}); + Plain (Const (I32 (I32.add i 1l) @@ e.at)); + Plain (Const (k @@ e.at)); + Plain (Const (I32 (I32.sub n 1l) @@ e.at)); + Plain (MemoryFill); + ] + + | MemoryCopy, Num (I32 n) :: Num (I32 s) :: Num (I32 d) :: vs' -> + if mem_oob frame (0l @@ e.at) s n || mem_oob frame (0l @@ e.at) d n then + vs', [Trapping (memory_error e.at Memory.Bounds) @@ e.at] + else if n = 0l then + vs', [] + else if d <= s then + vs', List.map (at e.at) [ + Plain (Const (I32 d @@ e.at)); + Plain (Const (I32 s @@ e.at)); + Plain (Load + {ty = I32Type; align = 0; offset = 0l; sz = Some Memory.(Pack8, ZX)}); + Plain (Store + {ty = I32Type; align = 0; offset = 0l; sz = Some Memory.Pack8}); + Plain (Const (I32 (I32.add d 1l) @@ e.at)); + Plain (Const (I32 (I32.add s 1l) @@ e.at)); + Plain (Const (I32 (I32.sub n 1l) @@ e.at)); + Plain (MemoryCopy); + ] + else (* d > s *) + vs', List.map (at e.at) [ + Plain (Const (I32 (I32.add d 1l) @@ e.at)); + Plain (Const (I32 (I32.add s 1l) @@ e.at)); + Plain (Const (I32 (I32.sub n 1l) @@ e.at)); + Plain (MemoryCopy); + Plain (Const (I32 d @@ e.at)); + Plain (Const (I32 s @@ e.at)); + Plain (Load + {ty = I32Type; align = 0; offset = 0l; sz = Some Memory.(Pack8, ZX)}); + Plain (Store + {ty = I32Type; align = 0; offset = 0l; sz = Some Memory.Pack8}); + ] + + | MemoryInit x, Num (I32 n) :: Num (I32 s) :: Num (I32 d) :: vs' -> + if mem_oob frame (0l @@ e.at) d n || data_oob frame x s n then + vs', [Trapping (memory_error e.at Memory.Bounds) @@ e.at] + else if n = 0l then + vs', [] + else + let seg = !(data frame.inst x) in + let b = Int32.of_int (Char.code seg.[Int32.to_int s]) in + vs', List.map (at e.at) [ + Plain (Const (I32 d @@ e.at)); + Plain (Const (I32 b @@ e.at)); + Plain (Store + {ty = I32Type; align = 0; offset = 0l; sz = Some Memory.Pack8}); + Plain (Const (I32 (I32.add d 1l) @@ e.at)); + Plain (Const (I32 (I32.add s 1l) @@ e.at)); + Plain (Const (I32 (I32.sub n 1l) @@ e.at)); + Plain (MemoryInit x); + ] + + | DataDrop x, vs -> + let seg = data frame.inst x in + seg := ""; + vs, [] + | RefNull, vs' -> Ref NullRef :: vs', [] - | RefIsNull, Ref NullRef :: vs' -> - Num (I32 1l) :: vs', [] - - | RefIsNull, v :: vs' -> - Num (I32 0l) :: vs', [] + | RefIsNull, Ref r :: vs' -> + if r = NullRef then + Num (I32 1l) :: vs', [] + else + Num (I32 0l) :: vs', [] | RefFunc x, vs' -> let f = func frame.inst x in @@ -398,11 +514,6 @@ let eval_const (inst : module_inst) (const : const) : value = | [v] -> v | vs -> Crash.error const.at "wrong number of results on stack" -let i32 (v : value) at = - match v with - | Num (I32 i) -> i - | _ -> Crash.error at "type error: i32 value expected" - (* Modules *) @@ -418,8 +529,8 @@ let create_memory (inst : module_inst) (mem : memory) : memory_inst = Memory.alloc mtype let create_global (inst : module_inst) (glob : global) : global_inst = - let {gtype; value} = glob.it in - let v = eval_const inst value in + let {gtype; ginit} = glob.it in + let v = eval_const inst ginit in Global.alloc gtype v let create_export (inst : module_inst) (ex : export) : export_inst = @@ -432,33 +543,13 @@ let create_export (inst : module_inst) (ex : export) : export_inst = | GlobalExport x -> ExternGlobal (global inst x) in name, ext +let create_elem (inst : module_inst) (seg : elem_segment) : elem_inst = + let {etype; einit; _} = seg.it in + ref (List.map (fun c -> as_ref (eval_const inst c)) einit) -let init_func (inst : module_inst) (func : func_inst) = - match func with - | Func.AstFunc (_, inst_ref, _) -> inst_ref := inst - | _ -> assert false - -let init_table (inst : module_inst) (seg : table_segment) = - let {index; offset = const; init} = seg.it in - let tab = table inst index in - let offset = i32 (eval_const inst const) const.at in - let end_ = Int32.(add offset (of_int (List.length init))) in - let bound = Table.size tab in - if I32.lt_u bound end_ || I32.lt_u end_ offset then - Link.error seg.at "elements segment does not fit table"; - fun () -> - Table.blit tab offset (List.map (fun x -> FuncRef (func inst x)) init) - -let init_memory (inst : module_inst) (seg : memory_segment) = - let {index; offset = const; init} = seg.it in - let mem = memory inst index in - let offset' = i32 (eval_const inst const) const.at in - let offset = I64_convert.extend_i32_u offset' in - let end_ = Int64.(add offset (of_int (String.length init))) in - let bound = Memory.bound mem in - if I64.lt_u bound end_ || I64.lt_u end_ offset then - Link.error seg.at "data segment does not fit memory"; - fun () -> Memory.store_bytes mem offset init +let create_data (inst : module_inst) (seg : data_segment) : data_inst = + let {dinit; _} = seg.it in + ref dinit let add_import (m : module_) (ext : extern) (im : import) (inst : module_inst) @@ -471,10 +562,45 @@ let add_import (m : module_) (ext : extern) (im : import) (inst : module_inst) | ExternMemory mem -> {inst with memories = mem :: inst.memories} | ExternGlobal glob -> {inst with globals = glob :: inst.globals} +let init_func (inst : module_inst) (func : func_inst) = + match func with + | Func.AstFunc (_, inst_ref, _) -> inst_ref := inst + | _ -> assert false + +let run_elem i elem = + match elem.it.emode.it with + | Passive -> [] + | Active {index; offset} -> + let at = elem.it.emode.at in + let x = i @@ at in + offset.it @ [ + Const (I32 0l @@ at) @@ at; + Const (I32 (Lib.List32.length elem.it.einit) @@ at) @@ at; + TableInit (index, x) @@ at; + ElemDrop x @@ at + ] + +let run_data i data = + match data.it.dmode.it with + | Passive -> [] + | Active {index; offset} -> + assert (index.it = 0l); + let at = data.it.dmode.at in + let x = i @@ at in + offset.it @ [ + Const (I32 0l @@ at) @@ at; + Const (I32 (Int32.of_int (String.length data.it.dinit)) @@ at) @@ at; + MemoryInit x @@ at; + DataDrop x @@ at + ] + +let run_start start = + [Call start @@ start.at] + let init (m : module_) (exts : extern list) : module_inst = let { imports; tables; memories; globals; funcs; types; - exports; elems; data; start + exports; elems; datas; start } = m.it in if List.length exts <> List.length imports then @@ -492,11 +618,16 @@ let init (m : module_) (exts : extern list) : module_inst = globals = inst1.globals @ List.map (create_global inst1) globals; } in - let inst = {inst2 with exports = List.map (create_export inst2) exports} in + let inst = + { inst2 with + exports = List.map (create_export inst2) exports; + elems = List.map (create_elem inst2) elems; + datas = List.map (create_data inst2) datas; + } + in List.iter (init_func inst) fs; - let init_elems = List.map (init_table inst) elems in - let init_datas = List.map (init_memory inst) data in - List.iter (fun f -> f ()) init_elems; - List.iter (fun f -> f ()) init_datas; - Lib.Option.app (fun x -> ignore (invoke (func inst x) [])) start; + let es_elem = List.concat (Lib.List32.mapi run_elem elems) in + let es_data = List.concat (Lib.List32.mapi run_data datas) in + let es_start = Lib.Option.get (Lib.Option.map run_start start) [] in + ignore (eval (config inst [] (List.map plain (es_elem @ es_data @ es_start)))); inst diff --git a/interpreter/runtime/instance.ml b/interpreter/runtime/instance.ml index 6288d11126..efc230e0f9 100644 --- a/interpreter/runtime/instance.ml +++ b/interpreter/runtime/instance.ml @@ -8,6 +8,8 @@ type module_inst = memories : memory_inst list; globals : global_inst list; exports : export_inst list; + elems : elem_inst list; + datas : data_inst list; } and func_inst = module_inst ref Func.t @@ -15,6 +17,8 @@ and table_inst = Table.t and memory_inst = Memory.t and global_inst = Global.t and export_inst = Ast.name * extern +and elem_inst = Values.ref_ list ref +and data_inst = string ref and extern = | ExternFunc of func_inst @@ -23,7 +27,7 @@ and extern = | ExternGlobal of global_inst -(* Reference type extensions *) +(* Reference types *) type Values.ref_ += FuncRef of func_inst @@ -44,7 +48,7 @@ let () = let empty_module_inst = { types = []; funcs = []; tables = []; memories = []; globals = []; - exports = [] } + exports = []; elems = []; datas = [] } let extern_type_of = function | ExternFunc func -> ExternFuncType (Func.type_of func) diff --git a/interpreter/runtime/memory.ml b/interpreter/runtime/memory.ml index c72ef0c3ac..fc3562d907 100644 --- a/interpreter/runtime/memory.ml +++ b/interpreter/runtime/memory.ml @@ -6,6 +6,7 @@ open Values type size = int32 (* number of pages *) type address = int64 type offset = int32 +type count = int32 type pack_size = Pack8 | Pack16 | Pack32 type extension = SX | ZX diff --git a/interpreter/runtime/memory.mli b/interpreter/runtime/memory.mli index 6fe9d32f43..c8e55df3d3 100644 --- a/interpreter/runtime/memory.mli +++ b/interpreter/runtime/memory.mli @@ -7,6 +7,7 @@ type t = memory type size = int32 (* number of pages *) type address = int64 type offset = int32 +type count = int32 type pack_size = Pack8 | Pack16 | Pack32 type extension = SX | ZX diff --git a/interpreter/runtime/table.ml b/interpreter/runtime/table.ml index db7dacee67..811edcff72 100644 --- a/interpreter/runtime/table.ml +++ b/interpreter/runtime/table.ml @@ -3,6 +3,7 @@ open Values type size = int32 type index = int32 +type count = int32 type table = {mutable ty : table_type; mutable content : ref_ array} type t = table @@ -57,3 +58,26 @@ let blit tab offset rs = let data = Array.of_list rs in try Lib.Array32.blit data 0l tab.content offset (Lib.Array32.length data) with Invalid_argument _ -> raise Bounds + +(*TODO: remove*) +let init tab es d s n = + let rec loop es d s n = + match s, n, es with + | s, 0l, _ -> () + | 0l, n, e::es' -> + store tab d e; + loop es' (Int32.add d 1l) 0l (Int32.sub n 1l) + | s, n, _::es' -> loop es' d (Int32.sub s 1l) n + | _ -> raise Bounds + in loop es d s n + +let copy tab d s n = + let rec loop d s n dx = + if I32.gt_u n 0l then begin + store tab d (load tab s); + loop (Int32.add d dx) (Int32.add s dx) (Int32.sub n 1l) dx + end + in (if s < d then + loop Int32.(add d (sub n 1l)) Int32.(add s (sub n 1l)) n (-1l) + else + loop d s n 1l) diff --git a/interpreter/runtime/table.mli b/interpreter/runtime/table.mli index b452afcbcb..dcc28f686f 100644 --- a/interpreter/runtime/table.mli +++ b/interpreter/runtime/table.mli @@ -6,6 +6,7 @@ type t = table type size = int32 type index = int32 +type count = int32 exception Type exception Bounds @@ -22,3 +23,8 @@ val grow : table -> size -> ref_ -> unit val load : table -> index -> ref_ (* raises Bounds *) val store : table -> index -> ref_ -> unit (* raises Type, Bounds *) val blit : table -> index -> ref_ list -> unit (* raises Bounds *) + +(*TODO: remove*) +val init : + table -> ref_ list -> index -> index -> count -> unit (* raises Bounds *) +val copy : table -> index -> index -> count -> unit (* raises Bounds *) diff --git a/interpreter/syntax/ast.ml b/interpreter/syntax/ast.ml index 06e75c396c..5926bffd79 100644 --- a/interpreter/syntax/ast.ml +++ b/interpreter/syntax/ast.ml @@ -90,11 +90,18 @@ and instr' = | TableSet of var (* write table element *) | TableSize of var (* size of table *) | TableGrow of var (* grow table *) - | TableFill of var (* fill table with unique value *) + | TableFill of var (* fill table range with value *) + | TableCopy of var * var (* copy table range *) + | TableInit of var * var (* initialize table range from segment *) + | ElemDrop of var (* drop passive element segment *) | Load of loadop (* read memory at address *) | Store of storeop (* write memory at address *) - | MemorySize (* size of linear memory *) - | MemoryGrow (* grow linear memory *) + | MemorySize (* size of memory *) + | MemoryGrow (* grow memory *) + | MemoryFill (* fill memory range with value *) + | MemoryCopy (* copy memory ranges *) + | MemoryInit of var (* initialize memory range from segment *) + | DataDrop of var (* drop passive data segment *) | RefNull (* null reference *) | RefIsNull (* null test *) | RefFunc of var (* function reference *) @@ -114,7 +121,7 @@ type global = global' Source.phrase and global' = { gtype : global_type; - value : const; + ginit : const; } type func = func' Source.phrase @@ -140,16 +147,25 @@ and memory' = mtype : memory_type; } -type 'data segment = 'data segment' Source.phrase -and 'data segment' = +type segment_mode = segment_mode' Source.phrase +and segment_mode' = + | Passive + | Active of {index : var; offset : const} + +type elem_segment = elem_segment' Source.phrase +and elem_segment' = { - index : var; - offset : const; - init : 'data; + etype : ref_type; + einit : const list; + emode : segment_mode; } -type table_segment = var list segment -type memory_segment = string segment +type data_segment = data_segment' Source.phrase +and data_segment' = +{ + dinit : string; + dmode : segment_mode; +} (* Modules *) @@ -194,8 +210,8 @@ and module_' = memories : memory list; funcs : func list; start : var option; - elems : var list segment list; - data : string segment list; + elems : elem_segment list; + datas : data_segment list; imports : import list; exports : export list; } @@ -211,8 +227,8 @@ let empty_module = memories = []; funcs = []; start = None; - elems = []; - data = []; + elems = []; + datas = []; imports = []; exports = []; } @@ -262,3 +278,4 @@ let string_of_name n = in List.iter escape n; Buffer.contents b + diff --git a/interpreter/syntax/free.ml b/interpreter/syntax/free.ml new file mode 100644 index 0000000000..39e1474ce5 --- /dev/null +++ b/interpreter/syntax/free.ml @@ -0,0 +1,140 @@ +open Source +open Ast + +module Set = Set.Make(Int32) + +type t = +{ + types : Set.t; + globals : Set.t; + tables : Set.t; + memories : Set.t; + funcs : Set.t; + elems : Set.t; + datas : Set.t; + locals : Set.t; + labels : Set.t; +} + +let empty : t = +{ + types = Set.empty; + globals = Set.empty; + tables = Set.empty; + memories = Set.empty; + funcs = Set.empty; + elems = Set.empty; + datas = Set.empty; + locals = Set.empty; + labels = Set.empty; +} + +let union (s1 : t) (s2 : t) : t = +{ + types = Set.union s1.types s2.types; + globals = Set.union s1.globals s2.globals; + tables = Set.union s1.tables s2.tables; + memories = Set.union s1.memories s2.memories; + funcs = Set.union s1.funcs s2.funcs; + elems = Set.union s1.elems s2.elems; + datas = Set.union s1.datas s2.datas; + locals = Set.union s1.locals s2.locals; + labels = Set.union s1.labels s2.labels; +} + +let types s = {empty with types = s} +let globals s = {empty with globals = s} +let tables s = {empty with tables = s} +let memories s = {empty with memories = s} +let funcs s = {empty with funcs = s} +let elems s = {empty with elems = s} +let datas s = {empty with datas = s} +let locals s = {empty with locals = s} +let labels s = {empty with labels = s} + +let var x = Set.singleton x.it +let zero = Set.singleton 0l +let shift s = Set.map (Int32.add (-1l)) (Set.remove 0l s) + +let (++) = union +let list free xs = List.fold_left union empty (List.map free xs) + +let rec instr (e : instr) = + match e.it with + | Unreachable | Nop | Drop | Select _ -> empty + | Const _ | Test _ | Compare _ | Unary _ | Binary _ | Convert _ -> empty + | RefNull | RefIsNull -> empty + | RefFunc x -> funcs (var x) + | Block (_, es) | Loop (_, es) -> block es + | If (_, es1, es2) -> block es1 ++ block es2 + | Br x | BrIf x -> labels (var x) + | BrTable (xs, x) -> list (fun x -> labels (var x)) (x::xs) + | Return -> empty + | Call x -> funcs (var x) + | CallIndirect (x, y) -> tables (var x) ++ types (var y) + | LocalGet x | LocalSet x | LocalTee x -> locals (var x) + | GlobalGet x | GlobalSet x -> globals (var x) + | Load _ | Store _ | MemorySize | MemoryGrow | MemoryCopy | MemoryFill -> + memories zero + | MemoryInit x -> memories zero ++ datas (var x) + | TableGet x | TableSet x | TableSize x | TableGrow x | TableFill x -> + tables (var x) + | TableCopy (x, y) -> tables (var x) ++ tables (var y) + | TableInit (x, y) -> tables (var x) ++ elems (var y) + | DataDrop x -> datas (var x) + | ElemDrop x -> elems (var x) + +and block (es : instr list) = + let free = list instr es in {free with labels = shift free.labels} + +let const (c : const) = block c.it + +let global (g : global) = const g.it.ginit +let func (f : func) = {(block f.it.body) with locals = Set.empty} +let table (t : table) = empty +let memory (m : memory) = empty + +let segment_mode f (m : segment_mode) = + match m.it with + | Passive -> empty + | Active {index; offset} -> f (var index) ++ const offset + +let elem (s : elem_segment) = + list const s.it.einit ++ segment_mode tables s.it.emode + +let data (s : data_segment) = + segment_mode memories s.it.dmode + +let type_ (t : type_) = empty + +let export_desc (d : export_desc) = + match d.it with + | FuncExport x -> funcs (var x) + | TableExport x -> tables (var x) + | MemoryExport x -> memories (var x) + | GlobalExport x -> globals (var x) + +let import_desc (d : import_desc) = + match d.it with + | FuncImport x -> types (var x) + | TableImport tt -> empty + | MemoryImport mt -> empty + | GlobalImport gt -> empty + +let export (e : export) = export_desc e.it.edesc +let import (i : import) = import_desc i.it.idesc + +let start (s : var option) = + funcs (Lib.Option.get (Lib.Option.map var s) Set.empty) + +let module_ (m : module_) = + list type_ m.it.types ++ + list global m.it.globals ++ + list table m.it.tables ++ + list memory m.it.memories ++ + list func m.it.funcs ++ + start m.it.start ++ + list elem m.it.elems ++ + list data m.it.datas ++ + list import m.it.imports ++ + list export m.it.exports diff --git a/interpreter/syntax/free.mli b/interpreter/syntax/free.mli new file mode 100644 index 0000000000..288a27b679 --- /dev/null +++ b/interpreter/syntax/free.mli @@ -0,0 +1,34 @@ +module Set : Set.S with type elt = int32 + +type t = +{ + types : Set.t; + globals : Set.t; + tables : Set.t; + memories : Set.t; + funcs : Set.t; + elems : Set.t; + datas : Set.t; + locals : Set.t; + labels : Set.t; +} + +val empty : t +val union : t -> t -> t + +val instr : Ast.instr -> t +val block : Ast.instr list -> t +val const : Ast.const -> t + +val type_ : Ast.type_ -> t +val global : Ast.global -> t +val func : Ast.func -> t +val table : Ast.table -> t +val memory : Ast.memory -> t +val elem : Ast.elem_segment -> t +val data : Ast.data_segment -> t +val export : Ast.export -> t +val import : Ast.import -> t +val start : Ast.var option -> t + +val module_ : Ast.module_ -> t diff --git a/interpreter/syntax/operators.ml b/interpreter/syntax/operators.ml index 2ff649b67d..e804a41395 100644 --- a/interpreter/syntax/operators.ml +++ b/interpreter/syntax/operators.ml @@ -39,6 +39,9 @@ let table_set x = TableSet x let table_size x = TableSize x let table_grow x = TableGrow x let table_fill x = TableFill x +let table_copy x y = TableCopy (x, y) +let table_init x y = TableInit (x, y) +let elem_drop x = ElemDrop x let i32_load align offset = Load {ty = I32Type; align; offset; sz = None} let i64_load align offset = Load {ty = I64Type; align; offset; sz = None} @@ -80,6 +83,13 @@ let i64_store16 align offset = let i64_store32 align offset = Store {ty = I64Type; align; offset; sz = Some Pack32} +let memory_size = MemorySize +let memory_grow = MemoryGrow +let memory_fill = MemoryFill +let memory_copy = MemoryCopy +let memory_init x = MemoryInit x +let data_drop x = DataDrop x + let i32_clz = Unary (I32 I32Op.Clz) let i32_ctz = Unary (I32 I32Op.Ctz) let i32_popcnt = Unary (I32 I32Op.Popcnt) @@ -207,7 +217,3 @@ let i32_reinterpret_f32 = Convert (I32 I32Op.ReinterpretFloat) let i64_reinterpret_f64 = Convert (I64 I64Op.ReinterpretFloat) let f32_reinterpret_i32 = Convert (F32 F32Op.ReinterpretInt) let f64_reinterpret_i64 = Convert (F64 F64Op.ReinterpretInt) - -let memory_size = MemorySize -let memory_grow = MemoryGrow - diff --git a/interpreter/syntax/values.ml b/interpreter/syntax/values.ml index cf5c6cb88c..6907ae75b9 100644 --- a/interpreter/syntax/values.ml +++ b/interpreter/syntax/values.ml @@ -30,6 +30,17 @@ let type_of_value = function | Ref r -> RefType (type_of_ref r) +(* Projections *) + +let as_num = function + | Num n -> n + | Ref _ -> failwith "as_num" + +let as_ref = function + | Num _ -> failwith "as_ref" + | Ref r -> r + + (* Defaults *) let default_num = function diff --git a/interpreter/text/arrange.ml b/interpreter/text/arrange.ml index 8bc9b6324c..d0433a0843 100644 --- a/interpreter/text/arrange.ml +++ b/interpreter/text/arrange.ml @@ -251,10 +251,17 @@ let rec instr e = | TableSize x -> "table.size " ^ var x, [] | TableGrow x -> "table.grow " ^ var x, [] | TableFill x -> "table.fill " ^ var x, [] + | TableCopy (x, y) -> "table.copy", [] (*TODO*) + | TableInit (x, y) -> "table.init " ^ var y, [] (*TODO*) + | ElemDrop x -> "elem.drop " ^ var x, [] | Load op -> loadop op, [] | Store op -> storeop op, [] | MemorySize -> "memory.size", [] | MemoryGrow -> "memory.grow", [] + | MemoryFill -> "memory.fill", [] + | MemoryCopy -> "memory.copy", [] + | MemoryInit x -> "memory.init " ^ var x, [] + | DataDrop x -> "data.drop " ^ var x, [] | RefNull -> "ref.null", [] | RefIsNull -> "ref.is_null", [] | RefFunc x -> "ref.func " ^ var x, [] @@ -266,8 +273,10 @@ let rec instr e = | Convert op -> cvtop op, [] in Node (head, inner) -let const c = - list instr c.it +let const head c = + match c.it with + | [e] -> instr e + | es -> Node (head, list instr c.it) (* Functions *) @@ -301,15 +310,44 @@ let memory off i mem = let {mtype = MemoryType lim} = mem.it in Node ("memory $" ^ nat (off + i) ^ " " ^ limits nat32 lim, []) -let segment head dat seg = - let {index; offset; init} = seg.it in - Node (head, atom var index :: Node ("offset", const offset) :: dat init) +let is_elem_kind = function + | FuncRefType -> true + | _ -> false -let elems seg = - segment "elem" (list (atom var)) seg +let elem_kind = function + | FuncRefType -> "func" + | _ -> assert false + +let is_elem_index e = + match e.it with + | [{it = RefFunc _; _}] -> true + | _ -> false + +let elem_index e = + match e.it with + | [{it = RefFunc x; _}] -> atom var x + | _ -> assert false + +let segment_mode category mode = + match mode.it with + | Passive -> [] + | Active {index; offset} -> + (if index.it = 0l then [] else [Node (category, [atom var index])]) @ + [const "offset" offset] + +let elem seg = + let {etype; einit; emode} = seg.it in + Node ("elem", + segment_mode "table" emode @ + if is_elem_kind etype && List.for_all is_elem_index einit then + atom elem_kind etype :: list elem_index einit + else + atom ref_type etype :: list (const "item") einit + ) let data seg = - segment "data" break_bytes seg + let {dinit; dmode} = seg.it in + Node ("data", segment_mode "memory" dmode @ break_bytes dinit) (* Modules *) @@ -346,8 +384,8 @@ let export ex = Node ("export", [atom name n; export_desc edesc]) let global off i g = - let {gtype; value} = g.it in - Node ("global $" ^ nat (off + i), global_type gtype :: const value) + let {gtype; ginit} = g.it in + Node ("global $" ^ nat (off + i), global_type gtype :: list instr ginit.it) (* Modules *) @@ -371,8 +409,8 @@ let module_with_var_opt x_opt m = listi (func_with_index !fx) m.it.funcs @ list export m.it.exports @ opt start m.it.start @ - list elems m.it.elems @ - list data m.it.data + list elem m.it.elems @ + list data m.it.datas ) let binary_module_with_var_opt x_opt bs = diff --git a/interpreter/text/lexer.mll b/interpreter/text/lexer.mll index 9a5cf16630..02c80b06df 100644 --- a/interpreter/text/lexer.mll +++ b/interpreter/text/lexer.mll @@ -211,6 +211,16 @@ rule token = parse | "table.size" { TABLE_SIZE } | "table.grow" { TABLE_GROW } | "table.fill" { TABLE_FILL } + | "table.copy" { TABLE_COPY } + | "table.init" { TABLE_INIT } + | "elem.drop" { ELEM_DROP } + + | "memory.size" { MEMORY_SIZE } + | "memory.grow" { MEMORY_GROW } + | "memory.fill" { MEMORY_FILL } + | "memory.copy" { MEMORY_COPY } + | "memory.init" { MEMORY_INIT } + | "data.drop" { DATA_DROP } | (nxx as t)".load" { LOAD (fun a o -> @@ -327,9 +337,6 @@ rule token = parse | "i32.reinterpret_f32" { CONVERT i32_reinterpret_f32 } | "i64.reinterpret_f64" { CONVERT i64_reinterpret_f64 } - | "memory.size" { MEMORY_SIZE } - | "memory.grow" { MEMORY_GROW } - | "type" { TYPE } | "func" { FUNC } | "start" { START } diff --git a/interpreter/text/parser.mly b/interpreter/text/parser.mly index c42b3cd326..5b26e68ed7 100644 --- a/interpreter/text/parser.mly +++ b/interpreter/text/parser.mly @@ -64,11 +64,14 @@ let empty_types () = {space = empty (); list = []} type context = { types : types; tables : space; memories : space; - funcs : space; locals : space; globals : space; labels : int32 VarMap.t } + funcs : space; locals : space; globals : space; + data : space; elems : space; + labels : int32 VarMap.t } let empty_context () = { types = empty_types (); tables = empty (); memories = empty (); funcs = empty (); locals = empty (); globals = empty (); + data = empty (); elems = empty (); labels = VarMap.empty } let enter_func (c : context) = @@ -84,6 +87,8 @@ let local (c : context) x = lookup "local" c.locals x let global (c : context) x = lookup "global" c.globals x let table (c : context) x = lookup "table" c.tables x let memory (c : context) x = lookup "memory" c.memories x +let elem (c : context) x = lookup "elem segment" c.elems x +let data (c : context) x = lookup "data segment" c.data x let label (c : context) x = try VarMap.find x.it c.labels with Not_found -> error x.at ("unknown label " ^ x.it) @@ -111,6 +116,8 @@ let bind_local (c : context) x = bind "local" c.locals x let bind_global (c : context) x = bind "global" c.globals x let bind_table (c : context) x = bind "table" c.tables x let bind_memory (c : context) x = bind "memory" c.memories x +let bind_elem (c : context) x = bind "elem segment" c.elems x +let bind_data (c : context) x = bind "data segment" c.data x let bind_label (c : context) x = {c with labels = VarMap.add x.it 0l (VarMap.map (Int32.add 1l) c.labels)} @@ -130,6 +137,8 @@ let anon_locals (c : context) ts = let anon_global (c : context) = anon "global" c.globals 1l let anon_table (c : context) = anon "table" c.tables 1l let anon_memory (c : context) = anon "memory" c.memories 1l +let anon_elem (c : context) = anon "elem segment" c.elems 1l +let anon_data (c : context) = anon "data segment" c.data 1l let anon_label (c : context) = {c with labels = VarMap.map (Int32.add 1l) c.labels} @@ -152,13 +161,14 @@ let inline_type_explicit (c : context) x ft at = %token BLOCK END IF THEN ELSE LOOP BR BR_IF BR_TABLE %token CALL CALL_INDIRECT RETURN %token LOCAL_GET LOCAL_SET LOCAL_TEE GLOBAL_GET GLOBAL_SET -%token TABLE_GET TABLE_SET TABLE_SIZE TABLE_GROW TABLE_FILL -%token MEMORY_SIZE MEMORY_GROW +%token TABLE_GET TABLE_SET +%token TABLE_SIZE TABLE_GROW TABLE_FILL TABLE_COPY TABLE_INIT ELEM_DROP +%token MEMORY_SIZE MEMORY_GROW MEMORY_FILL MEMORY_COPY MEMORY_INIT DATA_DROP %token LOAD STORE OFFSET_EQ_NAT ALIGN_EQ_NAT %token CONST UNARY BINARY TEST COMPARE CONVERT %token REF_NULL REF_FUNC REF_HOST REF_IS_NULL %token FUNC START TYPE PARAM RESULT LOCAL GLOBAL -%token TABLE ELEM MEMORY DATA OFFSET IMPORT EXPORT TABLE +%token TABLE ELEM MEMORY DATA OFFSET IMPORT EXPORT %token MODULE BIN QUOTE %token SCRIPT REGISTER INVOKE GET %token ASSERT_MALFORMED ASSERT_INVALID ASSERT_SOFT_INVALID ASSERT_UNLINKABLE @@ -332,10 +342,18 @@ plain_instr : | TABLE_SIZE var { fun c -> table_size ($2 c table) } | TABLE_GROW var { fun c -> table_grow ($2 c table) } | TABLE_FILL var { fun c -> table_fill ($2 c table) } + | TABLE_COPY { let at = ati 1 in fun c -> table_copy (0l @@ at) (0l @@ at) } + | TABLE_INIT var /*TODO*/ + { let at = ati 1 in fun c -> table_init (0l @@ at) ($2 c elem) } + | ELEM_DROP var { fun c -> elem_drop ($2 c elem) } | LOAD offset_opt align_opt { fun c -> $1 $3 $2 } | STORE offset_opt align_opt { fun c -> $1 $3 $2 } | MEMORY_SIZE { fun c -> memory_size } | MEMORY_GROW { fun c -> memory_grow } + | MEMORY_FILL { fun c -> memory_fill } + | MEMORY_COPY { fun c -> memory_copy } + | MEMORY_INIT var { fun c -> memory_init ($2 c data) } + | DATA_DROP var { fun c -> data_drop ($2 c data) } | REF_NULL { fun c -> ref_null } | REF_IS_NULL { fun c -> ref_is_null } | REF_FUNC var { fun c -> ref_func ($2 c func) } @@ -606,17 +624,63 @@ func_body : /* Tables, Memories & Globals */ +table_use : + | LPAR TABLE var RPAR { fun c -> $3 c } + +memory_use : + | LPAR MEMORY var RPAR { fun c -> $3 c } + offset : | LPAR OFFSET const_expr RPAR { $3 } | expr { let at = at () in fun c -> $1 c @@ at } /* Sugar */ +elem_kind : + | FUNC { FuncRefType } + +elem_expr : + /* TODO: | LPAR ITEM const_expr RPAR { $3 } */ + | expr { let at = at () in fun c -> $1 c @@ at } /* Sugar */ + +elem_expr_list : + | /* empty */ { fun c -> [] } + | elem_expr elem_expr_list { fun c -> $1 c :: $2 c } + +elem_var_list : + | var_list + { let f = function {at; _} as x -> [ref_func x @@ at] @@ at in + fun c lookup -> List.map f ($1 c lookup) } + +elem_list : + | elem_kind elem_var_list + { ($1, fun c -> $2 c func) } + | ref_type elem_expr_list + { ($1, fun c -> $2 c) } + + elem : - | LPAR ELEM var offset var_list RPAR + | LPAR ELEM bind_var_opt elem_list RPAR { let at = at () in - fun c -> {index = $3 c table; offset = $4 c; init = $5 c func} @@ at } - | LPAR ELEM offset var_list RPAR /* Sugar */ + fun c -> ignore ($3 c anon_elem bind_elem); + fun () -> + { etype = (fst $4); einit = (snd $4) c; emode = Passive @@ at } @@ at } + | LPAR ELEM bind_var_opt table_use offset elem_list RPAR { let at = at () in - fun c -> {index = 0l @@ at; offset = $3 c; init = $4 c func} @@ at } + fun c -> ignore ($3 c anon_elem bind_elem); + fun () -> + { etype = (fst $6); einit = (snd $6) c; + emode = Active {index = $4 c table; offset = $5 c} @@ at } @@ at } + | LPAR ELEM bind_var_opt offset elem_list RPAR /* Sugar */ + { let at = at () in + fun c -> ignore ($3 c anon_elem bind_elem); + fun () -> + { etype = (fst $5); einit = (snd $5) c; + emode = Active {index = 0l @@ at; offset = $4 c} @@ at } @@ at } + | LPAR ELEM bind_var_opt offset elem_var_list RPAR /* Sugar */ + { let at = at () in + fun c -> ignore ($3 c anon_elem bind_elem); + fun () -> + { etype = FuncRefType; einit = $5 c func; + emode = Active {index = 0l @@ at; offset = $4 c} @@ at } @@ at } table : | LPAR TABLE bind_var_opt table_fields RPAR @@ -635,20 +699,40 @@ table_fields : | inline_export table_fields /* Sugar */ { fun c x at -> let tabs, elems, ims, exs = $2 c x at in tabs, elems, ims, $1 (TableExport x) c :: exs } - | ref_type LPAR ELEM var_list RPAR /* Sugar */ + | ref_type LPAR ELEM elem_var_list RPAR /* Sugar */ + { fun c x at -> + let offset = [i32_const (0l @@ at) @@ at] @@ at in + let einit = $4 c func in + let size = Lib.List32.length einit in + let emode = Active {index = x; offset} @@ at in + [{ttype = TableType ({min = size; max = Some size}, $1)} @@ at], + [{etype = FuncRefType; einit; emode} @@ at], + [], [] } + | ref_type LPAR ELEM elem_expr elem_expr_list RPAR /* Sugar */ { fun c x at -> - let init = $4 c func in let size = Int32.of_int (List.length init) in + let offset = [i32_const (0l @@ at) @@ at] @@ at in + let einit = (fun c -> $4 c :: $5 c) c in + let size = Lib.List32.length einit in + let emode = Active {index = x; offset} @@ at in [{ttype = TableType ({min = size; max = Some size}, $1)} @@ at], - [{index = x; offset = [i32_const (0l @@ at) @@ at] @@ at; init} @@ at], + [{etype = FuncRefType; einit; emode} @@ at], [], [] } data : - | LPAR DATA var offset string_list RPAR + | LPAR DATA bind_var_opt string_list RPAR { let at = at () in - fun c -> {index = $3 c memory; offset = $4 c; init = $5} @@ at } - | LPAR DATA offset string_list RPAR /* Sugar */ - { let at = at () in - fun c -> {index = 0l @@ at; offset = $3 c; init = $4} @@ at } + fun c -> ignore ($3 c anon_data bind_data); + fun () -> {dinit = $4; dmode = Passive @@ at} @@ at } + | LPAR DATA bind_var_opt memory_use offset string_list RPAR + { let at = at () in + fun c -> ignore ($3 c anon_data bind_data); + fun () -> + {dinit = $6; dmode = Active {index = $4 c memory; offset = $5 c} @@ at} @@ at } + | LPAR DATA bind_var_opt offset string_list RPAR /* Sugar */ + { let at = at () in + fun c -> ignore ($3 c anon_data bind_data); + fun () -> + {dinit = $5; dmode = Active {index = 0l @@ at; offset = $4 c} @@ at} @@ at } memory : | LPAR MEMORY bind_var_opt memory_fields RPAR @@ -669,10 +753,10 @@ memory_fields : mems, data, ims, $1 (MemoryExport x) c :: exs } | LPAR DATA string_list RPAR /* Sugar */ { fun c x at -> + let offset = [i32_const (0l @@ at) @@ at] @@ at in let size = Int32.(div (add (of_int (String.length $3)) 65535l) 65536l) in [{mtype = MemoryType {min = size; max = Some size}} @@ at], - [{index = x; - offset = [i32_const (0l @@ at) @@ at] @@ at; init = $3} @@ at], + [{dinit = $3; dmode = Active {index = x; offset} @@ at} @@ at], [], [] } global : @@ -683,7 +767,7 @@ global : global_fields : | global_type const_expr - { fun c x at -> [{gtype = $1; value = $2 c} @@ at], [], [] } + { fun c x at -> [{gtype = $1; ginit = $2 c} @@ at], [], [] } | inline_import global_type /* Sugar */ { fun c x at -> [], @@ -781,7 +865,7 @@ module_fields1 : fun () -> let mems, data, ims, exs = mmf () in let m = mf () in if mems <> [] && m.imports <> [] then error (List.hd m.imports).at "import after memory definition"; - { m with memories = mems @ m.memories; data = data @ m.data; + { m with memories = mems @ m.memories; datas = data @ m.datas; imports = ims @ m.imports; exports = exs @ m.exports } } | func module_fields { fun c -> let ff = $1 c in let mf = $2 c in @@ -791,13 +875,13 @@ module_fields1 : { m with funcs = funcs @ m.funcs; imports = ims @ m.imports; exports = exs @ m.exports } } | elem module_fields - { fun c -> let mf = $2 c in - fun () -> let m = mf () in - {m with elems = $1 c :: m.elems} } + { fun c -> let ef = $1 c in let mf = $2 c in + fun () -> let elems = ef () in let m = mf () in + {m with elems = elems :: m.elems} } | data module_fields - { fun c -> let mf = $2 c in - fun () -> let m = mf () in - {m with data = $1 c :: m.data} } + { fun c -> let df = $1 c in let mf = $2 c in + fun () -> let data = df () in let m = mf () in + {m with datas = data :: m.datas} } | start module_fields { fun c -> let mf = $2 c in fun () -> let m = mf () in let x = $1 c in @@ -837,9 +921,9 @@ script_var_opt : script_module : | module_ { $1 } | LPAR MODULE module_var_opt BIN string_list RPAR - { $3, Encoded (string_of_region (at()), $5) @@ at() } + { $3, Encoded ("binary:" ^ string_of_pos (at()).left, $5) @@ at() } | LPAR MODULE module_var_opt QUOTE string_list RPAR - { $3, Quoted (string_of_region (at()), $5) @@ at() } + { $3, Quoted ("quote:" ^ string_of_pos (at()).left, $5) @@ at() } action : | LPAR INVOKE module_var_opt name const_list RPAR diff --git a/interpreter/util/lib.ml b/interpreter/util/lib.ml index 2b196384c2..675890cb5c 100644 --- a/interpreter/util/lib.ml +++ b/interpreter/util/lib.ml @@ -133,6 +133,11 @@ struct | 0l, _ -> xs | n, _::xs' when n > 0l -> drop (Int32.sub n 1l) xs' | _ -> failwith "drop" + + let rec mapi f xs = mapi' f 0l xs + and mapi' f i = function + | [] -> [] + | x::xs -> f i x :: mapi' f (Int32.add i 1l) xs end module Array32 = diff --git a/interpreter/util/lib.mli b/interpreter/util/lib.mli index cace75cd7a..a44253e502 100644 --- a/interpreter/util/lib.mli +++ b/interpreter/util/lib.mli @@ -30,6 +30,7 @@ sig val nth : 'a list -> int32 -> 'a (* raises Failure *) val take : int32 -> 'a list -> 'a list (* raises Failure *) val drop : int32 -> 'a list -> 'a list (* raises Failure *) + val mapi : (int32 -> 'a -> 'b) -> 'a list -> 'b list end module Array32 : diff --git a/interpreter/util/source.ml b/interpreter/util/source.ml index 0115825c87..f659f6f235 100644 --- a/interpreter/util/source.ml +++ b/interpreter/util/source.ml @@ -3,6 +3,7 @@ type region = {left : pos; right : pos} type 'a phrase = {at : region; it : 'a} let (@@) x region = {it = x; at = region} +let at region x = x @@ region (* Positions and regions *) diff --git a/interpreter/util/source.mli b/interpreter/util/source.mli index 8cab3db869..240fe64138 100644 --- a/interpreter/util/source.mli +++ b/interpreter/util/source.mli @@ -9,3 +9,4 @@ val string_of_pos : pos -> string val string_of_region : region -> string val (@@) : 'a -> region -> 'a phrase +val at : region -> 'a -> 'a phrase diff --git a/interpreter/valid/valid.ml b/interpreter/valid/valid.ml index bb8f7bea14..9edbc1e16e 100644 --- a/interpreter/valid/valid.ml +++ b/interpreter/valid/valid.ml @@ -21,6 +21,8 @@ type context = tables : table_type list; memories : memory_type list; globals : global_type list; + datas : unit list; + elems : unit list; locals : value_type list; results : value_type list; labels : stack_type list; @@ -28,7 +30,8 @@ type context = let empty_context = { types = []; funcs = []; tables = []; memories = []; - globals = []; locals = []; results = []; labels = [] } + globals = []; datas = []; elems = []; + locals = []; results = []; labels = [] } let lookup category list x = try Lib.List32.nth list x.it with Failure _ -> @@ -39,6 +42,8 @@ let func (c : context) x = lookup "function" c.funcs x let table (c : context) x = lookup "table" c.tables x let memory (c : context) x = lookup "memory" c.memories x let global (c : context) x = lookup "global" c.globals x +let data (c : context) x = lookup "data segment" c.datas x +let elem (c : context) x = lookup "elem segment" c.elems x let local (c : context) x = lookup "local" c.locals x let label (c : context) x = lookup "label" c.labels x @@ -272,6 +277,21 @@ let rec check_instr (c : context) (e : instr) (s : infer_stack_type) : op_type = let TableType (_lim, t) = table c x in [NumType I32Type; RefType t; NumType I32Type] --> [] + | TableCopy (x, y) -> + ignore (table c x); + ignore (table c y); + [NumType I32Type; NumType I32Type; NumType I32Type] --> [] + + | TableInit (x, y) -> + ignore (table c x); + ignore (elem c y); + [NumType I32Type; NumType I32Type; NumType I32Type] --> [] + + | ElemDrop x -> + ignore (table c (0l @@ e.at)); + ignore (elem c x); + [] --> [] + | Load memop -> check_memop c memop (Lib.Option.map fst) e.at; [NumType I32Type] --> [NumType memop.ty] @@ -288,6 +308,24 @@ let rec check_instr (c : context) (e : instr) (s : infer_stack_type) : op_type = let _mt = memory c (0l @@ e.at) in [NumType I32Type] --> [NumType I32Type] + | MemoryFill -> + ignore (memory c (0l @@ e.at)); + [NumType I32Type; NumType I32Type; NumType I32Type] --> [] + + | MemoryCopy -> + ignore (memory c (0l @@ e.at)); + [NumType I32Type; NumType I32Type; NumType I32Type] --> [] + + | MemoryInit x -> + ignore (memory c (0l @@ e.at)); + ignore (data c x); + [NumType I32Type; NumType I32Type; NumType I32Type] --> [] + + | DataDrop x -> + ignore (memory c (0l @@ e.at)); + ignore (data c x); + [] --> [] + | RefNull -> [] --> [RefType NullRefType] @@ -433,21 +471,35 @@ let check_memory (c : context) (mem : memory) = let {mtype} = mem.it in check_memory_type mtype mem.at -let check_elem (c : context) (seg : table_segment) = - let {index; offset; init} = seg.it in - let _tt = table c index in - let _xs = List.map (func c) init in - check_const c offset (NumType I32Type) - -let check_data (c : context) (seg : memory_segment) = - let {index; offset; init} = seg.it in - let _mt = memory c index in - check_const c offset (NumType I32Type) +let check_elem_mode (c : context) (t : ref_type) (mode : segment_mode) = + match mode.it with + | Passive -> () + | Active {index; offset} -> + let TableType (_, et) = table c index in + require (match_ref_type t et) mode.at + "type mismatch in active element segment"; + check_const c offset (NumType I32Type) + +let check_elem (c : context) (seg : elem_segment) = + let {etype; einit; emode} = seg.it in + List.iter (fun const -> check_const c const (RefType etype)) einit; + check_elem_mode c etype emode + +let check_data_mode (c : context) (mode : segment_mode) = + match mode.it with + | Passive -> () + | Active {index; offset} -> + ignore (memory c index); + check_const c offset (NumType I32Type) + +let check_data (c : context) (seg : data_segment) = + let {dinit; dmode} = seg.it in + check_data_mode c dmode let check_global (c : context) (glob : global) = - let {gtype; value} = glob.it in + let {gtype; ginit} = glob.it in let GlobalType (t, mut) = gtype in - check_const c value t + check_const c ginit t (* Modules *) @@ -488,7 +540,7 @@ let check_export (c : context) (set : NameSet.t) (ex : export) : NameSet.t = let check_module (m : module_) = let - { types; imports; tables; memories; globals; funcs; start; elems; data; + { types; imports; tables; memories; globals; funcs; start; elems; datas; exports } = m.it in let c0 = @@ -500,6 +552,8 @@ let check_module (m : module_) = funcs = c0.funcs @ List.map (fun f -> type_ c0 f.it.ftype) funcs; tables = c0.tables @ List.map (fun tab -> tab.it.ttype) tables; memories = c0.memories @ List.map (fun mem -> mem.it.mtype) memories; + elems = List.map (fun _ -> ()) elems; + datas = List.map (fun _ -> ()) datas; } in let c = @@ -510,7 +564,7 @@ let check_module (m : module_) = List.iter (check_table c1) tables; List.iter (check_memory c1) memories; List.iter (check_elem c1) elems; - List.iter (check_data c1) data; + List.iter (check_data c1) datas; List.iter (check_func c) funcs; check_start c start; ignore (List.fold_left (check_export c) NameSet.empty exports); diff --git a/proposals/bulk-memory-operations/Overview.md b/proposals/bulk-memory-operations/Overview.md new file mode 100644 index 0000000000..a743504599 --- /dev/null +++ b/proposals/bulk-memory-operations/Overview.md @@ -0,0 +1,469 @@ +# Bulk Memory Operations and Conditional Segment Initialization + +## Motivation for Bulk Memory Operations + +Some people have mentioned that `memcpy` and `memmove` functions are hot +when profiling some WebAssembly benchmarks. Some examples: + +- https://github.com/WebAssembly/design/issues/236#issuecomment-283279499 + +> I've been looking at perf profiles for wasm unity benchmark a bit recently and see that some + of the hottest functions are doing memcpy or memset like things. If this is any indication of + normal wasm code patterns, I think we could see significant improvement with an intrinsic so + it may be worth prioritizing. + +- https://github.com/WebAssembly/design/issues/977#issue-204960079 + +> In a number of game engines I've been optimizing and benchmarking, interestingly the performance + of memcpy() does show up relatively high in profiles. (~2%-5% of total execution time) + +### Bulk Memory Operations Prototype + +I implemented a prototype implementation of a `memory.copy` instruction in v8 which just calls out +to v8's [`MemMove` function](https://cs.chromium.org/chromium/src/v8/src/utils.h?l=446). I compared +this to an implementation [generated by emscripten](https://gist.github.com/binji/c57dc945bba60985439ef8e5b574eee0) and currently used in the Unity demo. This implementation aligns then performs copies using `i32.load` and `i32.store`. I've also included performance achieved by unrolling this loop manually and increasing the size to `i64`. + +Each test copies `size` bytes from one address to another, non-overlapping. This is repeated `N` times. Each row copies a total of 1 Gib of data, and only touches 1 Mib of memory in the source and destination ranges. + +This is the core loop: + +```javascript + let mask = Mib - 1; + let start = performance.now(); + for (let i = 0; i < N; ++i) { + f(dst_base + dst, src_base + src, size); + dst = (dst + size) & mask; + src = (src + size) & mask; + } + let end = performance.now(); +``` + +The code for the benchmark can be found [here](https://gist.github.com/binji/b8e8bc0c0121235d9f1668bc447c7f8c). +Note that this will not run properly without a WebAssembly implementation of `memory.copy`. For my tests, I +hacked a version of v8 to replace any exported function called `memcpy` or `memmove` with a new function with +the following contents: + +```wasm +(func (param $dst i32) (param $src i32) (param $size i32) (result i32) + get_local $dst + get_local $src + get_local $size + memory.copy + get_local $dst) +``` + +Here are the results on my machine (x86_64, 2.9GHz, L1 32k, L2 256k, L3 256k): + +| | intrinsic | i64 load/store x 4 | i64 load/store x 2 | i32 load/store x 2 | i32 load/store | +| --- | --- | --- | --- | --- | --- | +| size=32b, N=33554432 | 1.382 Gib/s | 1.565 Gib/s | 1.493 Gib/s | 1.275 Gib/s | 1.166 Gib/s | +| size=64b, N=16777216 | 3.285 Gib/s | 2.669 Gib/s | 2.383 Gib/s | 1.861 Gib/s | 1.639 Gib/s | +| size=128b, N=8388608 | 6.162 Gib/s | 3.993 Gib/s | 3.480 Gib/s | 2.433 Gib/s | 2.060 Gib/s | +| size=256b, N=4194304 | 9.939 Gib/s | 5.323 Gib/s | 4.462 Gib/s | 2.724 Gib/s | 2.213 Gib/s | +| size=512b, N=2097152 | 15.777 Gib/s | 6.377 Gib/s | 4.913 Gib/s | 3.231 Gib/s | 2.457 Gib/s | +| size=1.0Kib, N=1048576 | 17.902 Gib/s | 7.010 Gib/s | 6.112 Gib/s | 3.568 Gib/s | 2.614 Gib/s | +| size=2.0Kib, N=524288 | 19.870 Gib/s | 8.248 Gib/s | 6.915 Gib/s | 3.764 Gib/s | 2.699 Gib/s | +| size=4.0Kib, N=262144 | 20.940 Gib/s | 9.145 Gib/s | 7.400 Gib/s | 3.871 Gib/s | 2.729 Gib/s | +| size=8.0Kib, N=131072 | 21.162 Gib/s | 9.258 Gib/s | 7.672 Gib/s | 3.925 Gib/s | 2.763 Gib/s | +| size=16.0Kib, N=65536 | 20.991 Gib/s | 9.758 Gib/s | 7.756 Gib/s | 3.945 Gib/s | 2.773 Gib/s | +| size=32.0Kib, N=32768 | 22.504 Gib/s | 9.956 Gib/s | 7.861 Gib/s | 3.966 Gib/s | 2.780 Gib/s | +| size=64.0Kib, N=16384 | 22.534 Gib/s | 10.088 Gib/s | 7.931 Gib/s | 3.974 Gib/s | 2.782 Gib/s | +| size=128.0Kib, N=8192 | 29.728 Gib/s | 10.032 Gib/s | 7.934 Gib/s | 3.975 Gib/s | 2.782 Gib/s | +| size=256.0Kib, N=4096 | 29.742 Gib/s | 10.116 Gib/s | 7.625 Gib/s | 3.886 Gib/s | 2.781 Gib/s | +| size=512.0Kib, N=2048 | 29.994 Gib/s | 10.090 Gib/s | 7.627 Gib/s | 3.985 Gib/s | 2.785 Gib/s | +| size=1.0Mib, N=1024 | 11.760 Gib/s | 10.091 Gib/s | 7.959 Gib/s | 3.989 Gib/s | 2.787 Gib/s | + + +## Motivation for Conditional Segment Initialization + +Under the current [threading proposal](https://github.com/WebAssembly/threads), +to share a module between multiple agents, the module must be instantiated +multiple times: once per agent. Instantiation initializes linear memory with +the contents in the module's data segments. If the memory is shared between +multiple agents, it will be initialized multiple times, potentially overwriting +stores that occurred after the previous initializations. + +For example: + +```webassembly +;; The module. +(module + (memory (export "memory") 1) + + ;; Some value used as a counter. + (data (i32.const 0) "\0") + + ;; Add one to the counter. + (func (export "addOne") + (i32.store8 + (i32.const 0) + (i32.add + (i32.load8_u (i32.const 0)) + (i32.const 1))) + ) +) +``` + +```javascript +// main.js +let moduleBytes = ...; + +WebAssembly.instantiate(moduleBytes).then( + ({module, instance}) => { + // Increment our counter. + instance.exports.addOne(); + + // Spawn a new Worker. + let worker = new Worker('worker.js'); + + // Send the module to the new Worker. + worker.postMessage(module); + }); + +// worker.js + +function onmessage(event) { + let module = event.data; + + // Use the module to create another instance. + WebAssembly.instantiate(module).then( + (instance) => { + // Oops, our counter has been clobbered. + }); +} + +``` + +This can be worked around by storing the data segments in a separate module +which is only instantiated once, then exporting this memory to be used by +another module that contains only code. This works, but it cumbersome since it +requires two modules where one should be enough. + + +## Motivation for combining Bulk Memory Operations + Conditional Segment Initialization Proposals + +When [discussing the design of Conditional Segment Initialization](https://github.com/WebAssembly/threads/issues/62), +we found that programmatic memory initialization from a read-only data segment +(via the `memory.init` instruction, described below) has similar behavior to the +proposed instruction to copy memory regions from linear memory (`memory.copy`, +also described below.) + +## Design + +Copying between regions in linear memory or a table is accomplished with the +new `*.copy` instructions: + +* `memory.copy`: copy from one region of linear memory to another +* `table.copy`: copy from one region of a table to another + +Filling a memory region can be accomplished with `memory.fill`: + +* `memory.fill`: fill a region of linear memory with a given byte value + +TODO: should we provide `memory.clear` and `table.clear` instead? + +The [binary format for the data +section](https://webassembly.github.io/spec/core/binary/modules.html#binary-datasec) +currently has a collection of segments, each of which has a memory index, an +initializer expression for its offset, and its raw data. + +Since WebAssembly currently does not allow for multiple memories, the memory +index of each segment must be zero. We can repurpose this 32-bit integer as a +flags field where new meaning is attached to nonzero values. + +When the new flags field is `1`, this segment is _passive_. A passive segment +will not be automatically copied into the memory or table on instantiation, and +must instead be applied manually using the following new instructions: + +* `memory.init`: copy a region from a data segment +* `table.init`: copy a region from an element segment + +A passive segment has no initializer expression, since it will be specified +as an operand to `memory.init` or `table.init`. + +Segments can also be discarded by using the following new instructions: + +* `data.drop`: prevent further use of a data segment +* `elem.drop`: prevent further use of an element segment + +An active segment is equivalent to a passive segment, but with an implicit +`memory.init` followed by a `data.drop` (or `table.init` followed by a +`elem.drop`) that is prepended to the module's start function. + +The new encoding of a data segment is now: + +| Field | Type | Present? | Description | +| - | - | - | - | +| flags | `varuint32` | always | Flags for passive and presence of fields below, only values of 0, 1, and 2 are valid | +| index | `varuint32`? | flags = 2 | Memory index; 0 if the field is not present | +| offset | `init_expr`? | flags != 1 | an `i32` initializer expression for offset | +| size | `varuint32` | always | size of `data` (in bytes) | +| data | `bytes` | always | sequence of `size` bytes | + +Another way of looking at it: + +| Flags | Active? | index | offset | +| - | - | - | - | +| 0 | Active | Always 0 | Present | +| 1 | Passive | - | - | +| 2 | Active | Present | Present | + +### Element segments + +The new binary format for element segments is similar to the new format for data segments, but +also includes an element type when the segment is passive. A passive segment also has a sequence +of `expr`s instead of function indices. + +| Field | Type | Present? | Description | +| - | - | - | - | +| flags | `varuint32` | always | Flags for passive and presence of fields below, only values of 0, 1, and 2 are valid | +| index | `varuint32`? | flags = 2 | Table index; 0 if the field is not present | +| element_type | `elem_type`? | flags = 1 | element type of this segment; `anyfunc` if not present | +| offset | `init_expr`? | flags != 1 | an `i32` initializer expression for offset | +| count | `varuint32` | always | number of elements | +| elems | `varuint32*` | flags != 1 | sequence of function indices | +| elems | `elem_expr*` | flags = 1 | sequence of element expressions | + +Another way of looking at it: + +| Flags | Active? | index | element_type | offset | +| - | - | - | - | - | +| 0 | Active | Always 0 | Always `anyfunc` | Present | +| 1 | Passive | - | Present | - | +| 2 | Active | Present | Always `anyfunc` | Present | + +An `elem_expr` is like an `init_expr`, but can only contain expressions of the following sequences: + +| Binary | Text | Description | +| - | - | - | +| `0xd0 0x0b` | `ref.null end` | Returns a null reference | +| `0xd2 varuint32 0x0b` | `ref.func $funcidx end` | Returns a reference to function `$funcidx` | + +TODO: coordinate with other proposals to determine the binary encoding for `ref.null` and `ref.func`. + +### Segment Initialization + +In the MVP, segments are initialized during module instantiation. If any segment +would be initialized out-of-bounds, then the memory or table instance is not +modified. + +This behavior is changed in the bulk memory proposal. + +Each active segment is initialized in module-definition order. For each +segment, each byte in the data segment is copied into the memory, in order of +lowest to highest addresses. If, for a given byte, the copy is out-of-bounds, +instantiation fails and no further bytes in this segment nor further segments +are copied. Bytes written before this point stay written. + +The behavior of element segment initialization is changed similarly, with the +difference that elements are copied from element segments into tables, instead +of bytes being copied from data segments into memories. + +### `memory.init` instruction + +The `memory.init` instruction copies data from a given passive segment into a target +memory. The target memory and source segment are given as immediates. + +The instruction has the signature `[i32 i32 i32] -> []`. The parameters are, in order: + +- top-2: destination address +- top-1: offset into the source segment +- top-0: size of memory region in bytes + +It is a validation error to use `memory.init` with an out-of-bounds segment index. + +A trap occurs if: +* the source offset plus size is greater than the length of the source data segment; + this includes the case that the segment has been dropped via `data.drop` +* the destination offset plus size is greater than the length of the target memory + +Note that it is allowed to use `memory.init` on the same data segment more than +once. + +Initialization takes place bytewise from lower addresses toward higher +addresses. A trap resulting from an access outside the source data +segment or target memory only occurs once the first byte that is +outside the source or target is reached. Bytes written before the +trap stay written. + +(Data are read and written as-if individual bytes were read and +written, but various optimizations are possible that avoid reading and +writing only individual bytes.) + +Note that the semantics require bytewise accesses, so a trap that +might result from, say, reading a sequence of several words before +writing any, will have to be handled carefully: the reads that +succeeded will have to be written, if possible. + +### `data.drop` instruction + +The `data.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 `memory.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. + +It is a validation error to use `data.drop` with an out-of-bounds segment index. + +A trap occurs if the segment was already dropped. This includes active segments +that were dropped after being copied into memory during module instantiation. + +### `memory.copy` instruction + +Copy data from a source memory region to destination region. The +regions are said to overlap if they are in the same memory and the +start address of one region is one of the addresses that's read or +written (by the copy operation) in the other region. + +This instruction has two immediate arguments: the source and +destination memory indices. They currently both must be zero. + +If the source region starts at a lower address than the target region, then the +copy takes place as if from higher to lower addresses: the highest source +address is read first and the value is written to the highest target address, +then the next highest, and so on. Otherwise, the copy takes place as if from +lower to higher addresses: the lowest source address is read first and the +value is written to the lowest target address, then the next lowest, and so on. + +(The direction of the copy is defined in order to future-proof +`memory.copy` for shared memory and a memory read/write protection +feature.) + +The instruction has the signature `[i32 i32 i32] -> []`. The parameters are, in order: + +- top-2: destination address +- top-1: source address +- top-0: size of memory region in bytes + +A trap occurs if: +* the source offset plus size is greater than the length of the source memory +* the destination offset plus size is greater than the length of the target memory + +A trap resulting from an access outside the source or target region +only occurs once the first byte that is outside the source or target +is reached (in the defined copy order). Bytes written before the trap +stay written. + +(Data are read and written as-if individual bytes were read and +written, but various optimizations are possible that avoid reading and +writing only individual bytes.) + +### `memory.fill` instruction + +Set all bytes in a memory region to a given byte. This instruction has an +immediate argument of which memory to operate on, and it must be zero for now. + +The instruction has the signature `[i32 i32 i32] -> []`. The parameters are, in order: + +- top-2: destination address +- top-1: byte value to set +- top-0: size of memory region in bytes + +A trap occurs if: +* the destination offset plus size is greater than the length of the target memory + +Filling takes place bytewise from lower addresses toward higher +addresses. A trap resulting from an access outside the target memory +only occurs once the first byte that is outside the target is reached. +Bytes written before the trap stay written. + +(Data are written as-if individual bytes were written, but various +optimizations are possible that avoid writing only individual bytes.) + +### `table.init`, `elem.drop`, and `table.copy` instructions + +The `table.*` instructions behave similary to the `memory.*` 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` and +`table.copy` have element units instead of bytes as well. + +## Passive Segment Initialization Example + +Consider if there are two data sections, the first is always active and the +second is conditionally active if global 0 has a non-zero value. This could be +implemented as follows: + +```webassembly +(import "a" "global" (global i32)) ;; global 0 +(memory 1) +(data (i32.const 0) "hello") ;; data segment 0, is active so always copied +(data passive "goodbye") ;; data segment 1, is passive + +(func $start + (if (get_global 0) + + ;; copy data segment 1 into memory 0 (the 0 is implicit) + (memory.init 1 + (i32.const 16) ;; target offset + (i32.const 0) ;; source offset + (i32.const 7)) ;; length + + ;; The memory used by this segment is no longer needed, so this segment can + ;; be dropped. + (data.drop 1)) +) +``` + +### Instruction encoding + +All bulk memory instructions are encoded as a 0xfc prefix byte, followed by +another opcode, optionally followed by more immediates: + +``` +instr ::= ... + | 0xfc operation:uint8 ... +``` + +| Name | Opcode | Immediate | Description | +| ---- | ---- | ---- | ---- | +| `memory.init` | `0xfc 0x08` | `segment:varuint32`, `memory:0x00` | :thinking: copy from a passive data segment to linear memory | +| `data.drop` | `0xfc 0x09` | `segment:varuint32` | :thinking: prevent further use of passive data segment | +| `memory.copy` | `0xfc 0x0a` | `memory_dst:0x00` `memory_src:0x00` | :thinking: copy from one region of linear memory to another region | +| `memory.fill` | `0xfc 0x0b` | `memory:0x00` | :thinking: fill a region of linear memory with a given byte value | +| `table.init` | `0xfc 0x0c` | `segment:varuint32`, `table:0x00` | :thinking: copy from a passive element segment to a table | +| `elem.drop` | `0xfc 0x0d` | `segment:varuint32` | :thinking: prevent further use of a passive element segment | +| `table.copy` | `0xfc 0x0e` | `table_dst:0x00` `table_src:0x00` | :thinking: copy from one region of a table to another region | + +### `DataCount` section + +The WebAssembly binary format is designed to be validated in a single pass. If +a section requires information to validate, it is guaranteed that this +information will be present in a previous section. + +The `memory.{init,drop}` instructions break this guarantee. Both of these +instructions are used in the `Code` section. They each have a data segment +index immediate, but the vector of data segments is not available until the +`Data` section is parsed, which occurs after the `Code` section. + +To keep single-pass validation, the number of data segments defined in the +`Data` section must be available before the `Code` section. This information is +provided in a new `DataCount` section with the code `12`. + +Like all sections, the `DataCount` section is optional. If present, it must +appear in the following order: + +| Section Name | Code | Description | +| ------------ | ---- | ----------- | +| Type | `1` | Function signature declarations | +| Import | `2` | Import declarations | +| Function | `3` | Function declarations | +| Table | `4` | Indirect function table and other tables | +| Memory | `5` | Memory attributes | +| Global | `6` | Global declarations | +| Export | `7` | Exports | +| Start | `8` | Start function declaration | +| Element | `9` | Elements section | +| DataCount | `12` | Data segment count | +| Code | `10` | Function bodies (code) | +| Data | `11` | Data segments | + +The `DataCount` section has just one field that specifies the number of data +segments in the `Data` section: + +| Field | Type | Description | +| ----- | ---- | ----------- | +| count | `varuint32` | count of data segments in `Data` section | + +It is a validation error if `count` is not equal to the number of data segments +in the `Data` section. It is also a validation error if the `DataCount` section +is omitted and a `memory.init` or `data.drop` instruction is used. diff --git a/test/core/binary.wast b/test/core/binary.wast index 9f27273e46..002a9f26e9 100644 --- a/test/core/binary.wast +++ b/test/core/binary.wast @@ -133,6 +133,16 @@ "\41\00\0b\00" ;; (i32.const 0) with no elements ) +;; Data segment memory index can have non-minimal length +(module binary + "\00asm" "\01\00\00\00" + "\05\03\01" ;; Memory section with 1 entry + "\00\00" ;; no max, minimum 0 + "\0b\07\01" ;; Data section with 1 entry + "\80\00" ;; Memory index 0, encoded with 2 bytes + "\41\00\0b\00" ;; (i32.const 0) with contents "" +) + ;; Element segment table index can have non-minimal length (module binary "\00asm" "\01\00\00\00" @@ -140,9 +150,164 @@ "\70\00\00" ;; no max, minimum 0, funcref "\09\09\01" ;; Element section with 1 entry "\02\80\00" ;; Table index 0, encoded with 2 bytes - "\41\00\0b\00\00" ;; (i32.const 0) with no elements + "\41\00\0b\00\00" ;; (i32.const 0) with no elements ) +;; Unsigned LEB128 must not be overlong +(assert_malformed + (module binary + "\00asm" "\01\00\00\00" + "\05\08\01" ;; Memory section with 1 entry + "\00\82\80\80\80\80\00" ;; no max, minimum 2 with one byte too many + ) + "integer representation too long" +) + +;; Signed LEB128 must not be overlong +(assert_malformed + (module binary + "\00asm" "\01\00\00\00" + "\06\0b\01" ;; Global section with 1 entry + "\7f\00" ;; i32, immutable + "\41\80\80\80\80\80\00" ;; i32.const 0 with one byte too many + "\0b" ;; end + ) + "integer representation too long" +) +(assert_malformed + (module binary + "\00asm" "\01\00\00\00" + "\06\0b\01" ;; Global section with 1 entry + "\7f\00" ;; i32, immutable + "\41\ff\ff\ff\ff\ff\7f" ;; i32.const -1 with one byte too many + "\0b" ;; end + ) + "integer representation too long" +) + +(assert_malformed + (module binary + "\00asm" "\01\00\00\00" + "\06\10\01" ;; Global section with 1 entry + "\7e\00" ;; i64, immutable + "\42\80\80\80\80\80\80\80\80\80\80\00" ;; i64.const 0 with one byte too many + "\0b" ;; end + ) + "integer representation too long" +) +(assert_malformed + (module binary + "\00asm" "\01\00\00\00" + "\06\10\01" ;; Global section with 1 entry + "\7e\00" ;; i64, immutable + "\42\ff\ff\ff\ff\ff\ff\ff\ff\ff\ff\7f" ;; i64.const -1 with one byte too many + "\0b" ;; end + ) + "integer representation too long" +) + +;; Unsigned LEB128s zero-extend +(assert_malformed + (module binary + "\00asm" "\01\00\00\00" + "\05\07\01" ;; Memory section with 1 entry + "\00\82\80\80\80\70" ;; no max, minimum 2 with unused bits set + ) + "integer too large" +) +(assert_malformed + (module binary + "\00asm" "\01\00\00\00" + "\05\07\01" ;; Memory section with 1 entry + "\00\82\80\80\80\40" ;; no max, minimum 2 with some unused bits set + ) + "integer too large" +) + +;; Signed LEB128s sign-extend +(assert_malformed + (module binary + "\00asm" "\01\00\00\00" + "\06\0a\01" ;; Global section with 1 entry + "\7f\00" ;; i32, immutable + "\41\80\80\80\80\70" ;; i32.const 0 with unused bits set + "\0b" ;; end + ) + "integer too large" +) +(assert_malformed + (module binary + "\00asm" "\01\00\00\00" + "\06\0a\01" ;; Global section with 1 entry + "\7f\00" ;; i32, immutable + "\41\ff\ff\ff\ff\0f" ;; i32.const -1 with unused bits unset + "\0b" ;; end + ) + "integer too large" +) +(assert_malformed + (module binary + "\00asm" "\01\00\00\00" + "\06\0a\01" ;; Global section with 1 entry + "\7f\00" ;; i32, immutable + "\41\80\80\80\80\1f" ;; i32.const 0 with some unused bits set + "\0b" ;; end + ) + "integer too large" +) +(assert_malformed + (module binary + "\00asm" "\01\00\00\00" + "\06\0a\01" ;; Global section with 1 entry + "\7f\00" ;; i32, immutable + "\41\ff\ff\ff\ff\4f" ;; i32.const -1 with some unused bits unset + "\0b" ;; end + ) + "integer too large" +) + +(assert_malformed + (module binary + "\00asm" "\01\00\00\00" + "\06\0f\01" ;; Global section with 1 entry + "\7e\00" ;; i64, immutable + "\42\80\80\80\80\80\80\80\80\80\7e" ;; i64.const 0 with unused bits set + "\0b" ;; end + ) + "integer too large" +) +(assert_malformed + (module binary + "\00asm" "\01\00\00\00" + "\06\0f\01" ;; Global section with 1 entry + "\7e\00" ;; i64, immutable + "\42\ff\ff\ff\ff\ff\ff\ff\ff\ff\01" ;; i64.const -1 with unused bits unset + "\0b" ;; end + ) + "integer too large" +) +(assert_malformed + (module binary + "\00asm" "\01\00\00\00" + "\06\0f\01" ;; Global section with 1 entry + "\7e\00" ;; i64, immutable + "\42\80\80\80\80\80\80\80\80\80\02" ;; i64.const 0 with some unused bits set + "\0b" ;; end + ) + "integer too large" +) +(assert_malformed + (module binary + "\00asm" "\01\00\00\00" + "\06\0f\01" ;; Global section with 1 entry + "\7e\00" ;; i64, immutable + "\42\ff\ff\ff\ff\ff\ff\ff\ff\ff\41" ;; i64.const -1 with some unused bits unset + "\0b" ;; end + ) + "integer too large" +) + + ;; Unsigned LEB128 must not be overlong (assert_malformed (module binary @@ -801,6 +966,168 @@ "\0a\01\00" ;; Code section with 0 functions ) +;; Fewer passive segments than datacount +(assert_malformed + (module binary + "\00asm" "\01\00\00\00" + "\0c\01\03" ;; Datacount section with value "3" + "\0b\05\02" ;; Data section with two entries + "\01\00" ;; Passive data section + "\01\00") ;; Passive data section + "data count and data section have inconsistent lengths") + +;; More passive segments than datacount +(assert_malformed + (module binary + "\00asm" "\01\00\00\00" + "\0c\01\01" ;; Datacount section with value "1" + "\0b\05\02" ;; Data section with two entries + "\01\00" ;; Passive data section + "\01\00") ;; Passive data section + "data count and data section have inconsistent lengths") + +;; memory.init requires a datacount section +(assert_malformed + (module binary + "\00asm" "\01\00\00\00" + + "\01\04\01\60\00\00" ;; Type section + "\03\02\01\00" ;; Function section + "\05\03\01\00\00" ;; Memory section + "\0a\0e\01" ;; Code section + + ;; function 0 + "\0c\00" + "\41\00" ;; zero args + "\41\00" + "\41\00" + "\fc\08\00\00" ;; memory.init + "\0b" + + "\0b\03\01\01\00" ;; Data section + ) ;; end + "data count section required") + +;; data.drop requires a datacount section +(assert_malformed + (module binary + "\00asm" "\01\00\00\00" + + "\01\04\01\60\00\00" ;; Type section + "\03\02\01\00" ;; Function section + "\05\03\01\00\00" ;; Memory section + "\0a\07\01" ;; Code section + + ;; function 0 + "\05\00" + "\fc\09\00" ;; data.drop + "\0b" + + "\0b\03\01\01\00" ;; Data section + ) ;; end + "data count section required") + +;; passive element segment containing opcode other than ref.func or ref.null +(assert_malformed + (module binary + "\00asm" "\01\00\00\00" + + "\01\04\01\60\00\00" ;; Type section + + "\03\02\01\00" ;; Function section + + "\04\04\01" ;; Table section with 1 entry + "\70\00\00" ;; no max, minimum 0, funcref + + "\05\03\01\00\00" ;; Memory section + + "\09\07\01" ;; Element section with one segment + "\05\70" ;; Passive, funcref + "\01" ;; 1 element + "\d3\00\0b" ;; bad opcode, index 0, end + + "\0a\04\01" ;; Code section + + ;; function 0 + "\02\00" + "\0b") ;; end + "illegal opcode") + +;; passive element segment containing type other than funcref +(assert_malformed + (module binary + "\00asm" "\01\00\00\00" + + "\01\04\01\60\00\00" ;; Type section + + "\03\02\01\00" ;; Function section + + "\04\04\01" ;; Table section with 1 entry + "\70\00\00" ;; no max, minimum 0, funcref + + "\05\03\01\00\00" ;; Memory section + + "\09\07\01" ;; Element section with one segment + "\05\7f" ;; Passive, i32 + "\01" ;; 1 element + "\d2\00\0b" ;; ref.func, index 0, end + + "\0a\04\01" ;; Code section + + ;; function 0 + "\02\00" + "\0b") ;; end + "invalid reference type") + +;; passive element segment containing opcode ref.func +(module binary + "\00asm" "\01\00\00\00" + + "\01\04\01\60\00\00" ;; Type section + + "\03\02\01\00" ;; Function section + + "\04\04\01" ;; Table section with 1 entry + "\70\00\00" ;; no max, minimum 0, funcref + + "\05\03\01\00\00" ;; Memory section + + "\09\07\01" ;; Element section with one segment + "\05\70" ;; Passive, funcref + "\01" ;; 1 element + "\d2\00\0b" ;; ref.func, index 0, end + + "\0a\04\01" ;; Code section + + ;; function 0 + "\02\00" + "\0b") ;; end + +;; passive element segment containing opcode ref.null +(module binary + "\00asm" "\01\00\00\00" + + "\01\04\01\60\00\00" ;; Type section + + "\03\02\01\00" ;; Function section + + "\04\04\01" ;; Table section with 1 entry + "\70\00\00" ;; no max, minimum 0, funcref + + "\05\03\01\00\00" ;; Memory section + + "\09\06\01" ;; Element section with one segment + "\05\70" ;; Passive, funcref + "\01" ;; 1 element + "\d0\0b" ;; ref.null, end + + "\0a\04\01" ;; Code section + + ;; function 0 + "\02\00" + "\0b") ;; end + + ;; Type count can be zero (module binary "\00asm" "\01\00\00\00" @@ -1023,7 +1350,7 @@ "\0a\04\01" ;; code section "\02\00\0b" ;; function body ) - "invalid segment kind" + "invalid elements segment kind" ) ;; 1 elem segment declared, 2 given diff --git a/test/core/bulk.wast b/test/core/bulk.wast new file mode 100644 index 0000000000..fe71939d3b --- /dev/null +++ b/test/core/bulk.wast @@ -0,0 +1,307 @@ +;; segment syntax +(module + (memory 1) + (data "foo")) + +(module + (table 3 funcref) + (elem funcref (ref.func 0) (ref.null) (ref.func 1)) + (func) + (func)) + +;; memory.fill +(module + (memory 1) + + (func (export "fill") (param i32 i32 i32) + (memory.fill + (local.get 0) + (local.get 1) + (local.get 2))) + + (func (export "load8_u") (param i32) (result i32) + (i32.load8_u (local.get 0))) +) + +;; Basic fill test. +(invoke "fill" (i32.const 1) (i32.const 0xff) (i32.const 3)) +(assert_return (invoke "load8_u" (i32.const 0)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 1)) (i32.const 0xff)) +(assert_return (invoke "load8_u" (i32.const 2)) (i32.const 0xff)) +(assert_return (invoke "load8_u" (i32.const 3)) (i32.const 0xff)) +(assert_return (invoke "load8_u" (i32.const 4)) (i32.const 0)) + +;; Fill value is stored as a byte. +(invoke "fill" (i32.const 0) (i32.const 0xbbaa) (i32.const 2)) +(assert_return (invoke "load8_u" (i32.const 0)) (i32.const 0xaa)) +(assert_return (invoke "load8_u" (i32.const 1)) (i32.const 0xaa)) + +;; Fill all of memory +(invoke "fill" (i32.const 0) (i32.const 0) (i32.const 0x10000)) + +;; Out-of-bounds writes trap, and nothing is written +(assert_trap (invoke "fill" (i32.const 0xff00) (i32.const 1) (i32.const 0x101)) + "out of bounds memory access") +(assert_return (invoke "load8_u" (i32.const 0xff00)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 0xffff)) (i32.const 0)) + +;; Succeed when writing 0 bytes at the end of the region. +(invoke "fill" (i32.const 0x10000) (i32.const 0) (i32.const 0)) + +;; Writing 0 bytes outside the memory traps. +(assert_trap (invoke "fill" (i32.const 0x10001) (i32.const 0) (i32.const 0)) + "out of bounds memory access") + + +;; memory.copy +(module + (memory (data "\aa\bb\cc\dd")) + + (func (export "copy") (param i32 i32 i32) + (memory.copy + (local.get 0) + (local.get 1) + (local.get 2))) + + (func (export "load8_u") (param i32) (result i32) + (i32.load8_u (local.get 0))) +) + +;; Non-overlapping copy. +(invoke "copy" (i32.const 10) (i32.const 0) (i32.const 4)) + +(assert_return (invoke "load8_u" (i32.const 9)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 10)) (i32.const 0xaa)) +(assert_return (invoke "load8_u" (i32.const 11)) (i32.const 0xbb)) +(assert_return (invoke "load8_u" (i32.const 12)) (i32.const 0xcc)) +(assert_return (invoke "load8_u" (i32.const 13)) (i32.const 0xdd)) +(assert_return (invoke "load8_u" (i32.const 14)) (i32.const 0)) + +;; Overlap, source > dest +(invoke "copy" (i32.const 8) (i32.const 10) (i32.const 4)) +(assert_return (invoke "load8_u" (i32.const 8)) (i32.const 0xaa)) +(assert_return (invoke "load8_u" (i32.const 9)) (i32.const 0xbb)) +(assert_return (invoke "load8_u" (i32.const 10)) (i32.const 0xcc)) +(assert_return (invoke "load8_u" (i32.const 11)) (i32.const 0xdd)) +(assert_return (invoke "load8_u" (i32.const 12)) (i32.const 0xcc)) +(assert_return (invoke "load8_u" (i32.const 13)) (i32.const 0xdd)) + +;; Overlap, source < dest +(invoke "copy" (i32.const 10) (i32.const 7) (i32.const 6)) +(assert_return (invoke "load8_u" (i32.const 10)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 11)) (i32.const 0xaa)) +(assert_return (invoke "load8_u" (i32.const 12)) (i32.const 0xbb)) +(assert_return (invoke "load8_u" (i32.const 13)) (i32.const 0xcc)) +(assert_return (invoke "load8_u" (i32.const 14)) (i32.const 0xdd)) +(assert_return (invoke "load8_u" (i32.const 15)) (i32.const 0xcc)) +(assert_return (invoke "load8_u" (i32.const 16)) (i32.const 0)) + +;; Copy ending at memory limit is ok. +(invoke "copy" (i32.const 0xff00) (i32.const 0) (i32.const 0x100)) +(invoke "copy" (i32.const 0xfe00) (i32.const 0xff00) (i32.const 0x100)) + +;; Succeed when copying 0 bytes at the end of the region. +(invoke "copy" (i32.const 0x10000) (i32.const 0) (i32.const 0)) +(invoke "copy" (i32.const 0) (i32.const 0x10000) (i32.const 0)) + +;; Copying 0 bytes outside the memory traps. +(assert_trap (invoke "copy" (i32.const 0x10001) (i32.const 0) (i32.const 0)) + "out of bounds memory access") +(assert_trap (invoke "copy" (i32.const 0) (i32.const 0x10001) (i32.const 0)) + "out of bounds memory access") + + +;; memory.init +(module + (memory 1) + (data "\aa\bb\cc\dd") + + (func (export "init") (param i32 i32 i32) + (memory.init 0 + (local.get 0) + (local.get 1) + (local.get 2))) + + (func (export "load8_u") (param i32) (result i32) + (i32.load8_u (local.get 0))) +) + +(invoke "init" (i32.const 0) (i32.const 1) (i32.const 2)) +(assert_return (invoke "load8_u" (i32.const 0)) (i32.const 0xbb)) +(assert_return (invoke "load8_u" (i32.const 1)) (i32.const 0xcc)) +(assert_return (invoke "load8_u" (i32.const 2)) (i32.const 0)) + +;; Init ending at memory limit and segment limit is ok. +(invoke "init" (i32.const 0xfffc) (i32.const 0) (i32.const 4)) + +;; Out-of-bounds writes trap, and nothing is written. +(assert_trap (invoke "init" (i32.const 0xfffe) (i32.const 0) (i32.const 3)) + "out of bounds memory access") +(assert_return (invoke "load8_u" (i32.const 0xfffe)) (i32.const 0xcc)) +(assert_return (invoke "load8_u" (i32.const 0xffff)) (i32.const 0xdd)) + +;; Succeed when writing 0 bytes at the end of either region. +(invoke "init" (i32.const 0x10000) (i32.const 0) (i32.const 0)) +(invoke "init" (i32.const 0) (i32.const 4) (i32.const 0)) + +;; Writing 0 bytes outside the memory traps. +(assert_trap (invoke "init" (i32.const 0x10001) (i32.const 0) (i32.const 0)) + "out of bounds memory access") +(assert_trap (invoke "init" (i32.const 0) (i32.const 5) (i32.const 0)) + "out of bounds memory access") + +;; data.drop +(module + (memory 1) + (data $p "x") + (data $a (memory 0) (i32.const 0) "x") + + (func (export "drop_passive") (data.drop $p)) + (func (export "init_passive") (param $len i32) + (memory.init $p (i32.const 0) (i32.const 0) (local.get $len))) + + (func (export "drop_active") (data.drop $a)) + (func (export "init_active") (param $len i32) + (memory.init $a (i32.const 0) (i32.const 0) (local.get $len))) +) + +(invoke "init_passive" (i32.const 1)) +(invoke "drop_passive") +(invoke "drop_passive") +(assert_return (invoke "init_passive" (i32.const 0))) +(assert_trap (invoke "init_passive" (i32.const 1)) "out of bounds") +(invoke "init_passive" (i32.const 0)) +(invoke "drop_active") +(assert_return (invoke "init_active" (i32.const 0))) +(assert_trap (invoke "init_active" (i32.const 1)) "out of bounds") +(invoke "init_active" (i32.const 0)) + + +;; table.init +(module + (table 3 funcref) + (elem funcref + (ref.func $zero) (ref.func $one) (ref.func $zero) (ref.func $one)) + + (func $zero (result i32) (i32.const 0)) + (func $one (result i32) (i32.const 1)) + + (func (export "init") (param i32 i32 i32) + (table.init 0 + (local.get 0) + (local.get 1) + (local.get 2))) + + (func (export "call") (param i32) (result i32) + (call_indirect (result i32) + (local.get 0))) +) + +;; Out-of-bounds stores trap, and nothing is written. +(assert_trap (invoke "init" (i32.const 2) (i32.const 0) (i32.const 2)) + "out of bounds table access") +(assert_trap (invoke "call" (i32.const 2)) + "uninitialized element 2") + +(invoke "init" (i32.const 0) (i32.const 1) (i32.const 2)) +(assert_return (invoke "call" (i32.const 0)) (i32.const 1)) +(assert_return (invoke "call" (i32.const 1)) (i32.const 0)) +(assert_trap (invoke "call" (i32.const 2)) "uninitialized element") + +;; Init ending at table limit and segment limit is ok. +(invoke "init" (i32.const 1) (i32.const 2) (i32.const 2)) + +;; Succeed when storing 0 elements at the end of either region. +(invoke "init" (i32.const 3) (i32.const 0) (i32.const 0)) +(invoke "init" (i32.const 0) (i32.const 4) (i32.const 0)) + +;; Writing 0 elements outside the table traps. +(assert_trap (invoke "init" (i32.const 4) (i32.const 0) (i32.const 0)) + "out of bounds table access") +(assert_trap (invoke "init" (i32.const 0) (i32.const 5) (i32.const 0)) + "out of bounds table access") + + +;; elem.drop +(module + (table 1 funcref) + (func $f) + (elem $p funcref (ref.func $f)) + (elem $a (table 0) (i32.const 0) func $f) + + (func (export "drop_passive") (elem.drop $p)) + (func (export "init_passive") (param $len i32) + (table.init $p (i32.const 0) (i32.const 0) (local.get $len)) + ) + + (func (export "drop_active") (elem.drop $a)) + (func (export "init_active") (param $len i32) + (table.init $a (i32.const 0) (i32.const 0) (local.get $len)) + ) +) + +(invoke "init_passive" (i32.const 1)) +(invoke "drop_passive") +(invoke "drop_passive") +(assert_return (invoke "init_passive" (i32.const 0))) +(assert_trap (invoke "init_passive" (i32.const 1)) "out of bounds") +(invoke "init_passive" (i32.const 0)) +(invoke "drop_active") +(assert_return (invoke "init_active" (i32.const 0))) +(assert_trap (invoke "init_active" (i32.const 1)) "out of bounds") +(invoke "init_active" (i32.const 0)) + + +;; table.copy +(module + (table 10 funcref) + (elem (i32.const 0) $zero $one $two) + (func $zero (result i32) (i32.const 0)) + (func $one (result i32) (i32.const 1)) + (func $two (result i32) (i32.const 2)) + + (func (export "copy") (param i32 i32 i32) + (table.copy + (local.get 0) + (local.get 1) + (local.get 2))) + + (func (export "call") (param i32) (result i32) + (call_indirect (result i32) + (local.get 0))) +) + +;; Non-overlapping copy. +(invoke "copy" (i32.const 3) (i32.const 0) (i32.const 3)) +;; Now [$zero, $one, $two, $zero, $one, $two, ...] +(assert_return (invoke "call" (i32.const 3)) (i32.const 0)) +(assert_return (invoke "call" (i32.const 4)) (i32.const 1)) +(assert_return (invoke "call" (i32.const 5)) (i32.const 2)) + +;; Overlap, source > dest +(invoke "copy" (i32.const 0) (i32.const 1) (i32.const 3)) +;; Now [$one, $two, $zero, $zero, $one, $two, ...] +(assert_return (invoke "call" (i32.const 0)) (i32.const 1)) +(assert_return (invoke "call" (i32.const 1)) (i32.const 2)) +(assert_return (invoke "call" (i32.const 2)) (i32.const 0)) + +;; Overlap, source < dest +(invoke "copy" (i32.const 2) (i32.const 0) (i32.const 3)) +;; Now [$one, $two, $one, $two, $zero, $two, ...] +(assert_return (invoke "call" (i32.const 2)) (i32.const 1)) +(assert_return (invoke "call" (i32.const 3)) (i32.const 2)) +(assert_return (invoke "call" (i32.const 4)) (i32.const 0)) + +;; Copy ending at table limit is ok. +(invoke "copy" (i32.const 6) (i32.const 8) (i32.const 2)) +(invoke "copy" (i32.const 8) (i32.const 6) (i32.const 2)) + +;; Succeed when copying 0 elements at the end of the region. +(invoke "copy" (i32.const 10) (i32.const 0) (i32.const 0)) +(invoke "copy" (i32.const 0) (i32.const 10) (i32.const 0)) + +;; Fail on out-of-bounds when copying 0 elements outside of table. +(assert_trap (invoke "copy" (i32.const 11) (i32.const 0) (i32.const 0)) + "out of bounds") +(assert_trap (invoke "copy" (i32.const 0) (i32.const 11) (i32.const 0)) + "out of bounds") diff --git a/test/core/custom.wast b/test/core/custom.wast index fb04f2f6b9..0310f76b54 100644 --- a/test/core/custom.wast +++ b/test/core/custom.wast @@ -118,3 +118,13 @@ ) "length out of bounds" ) + +(assert_malformed + (module binary + "\00asm" "\01\00\00\00" + "\05\03\01\00\01" ;; memory section + "\0c\01\02" ;; data count section (2 segments) + "\0b\06\01\00\41\00\0b\00" ;; data section (1 segment) + ) + "data count and data section have inconsistent lengths" +) diff --git a/test/core/data.wast b/test/core/data.wast index 7d69454173..aabe1021b2 100644 --- a/test/core/data.wast +++ b/test/core/data.wast @@ -8,14 +8,26 @@ (data (i32.const 1) "a" "" "bcd") (data (offset (i32.const 0))) (data (offset (i32.const 0)) "" "a" "bc" "") - (data 0 (i32.const 0)) - (data 0x0 (i32.const 1) "a" "" "bcd") - (data 0x000 (offset (i32.const 0))) - (data 0 (offset (i32.const 0)) "" "a" "bc" "") - (data $m (i32.const 0)) - (data $m (i32.const 1) "a" "" "bcd") - (data $m (offset (i32.const 0))) - (data $m (offset (i32.const 0)) "" "a" "bc" "") + (data (memory 0) (i32.const 0)) + (data (memory 0x0) (i32.const 1) "a" "" "bcd") + (data (memory 0x000) (offset (i32.const 0))) + (data (memory 0) (offset (i32.const 0)) "" "a" "bc" "") + (data (memory $m) (i32.const 0)) + (data (memory $m) (i32.const 1) "a" "" "bcd") + (data (memory $m) (offset (i32.const 0))) + (data (memory $m) (offset (i32.const 0)) "" "a" "bc" "") + (data $d1 (i32.const 0)) + (data $d2 (i32.const 1) "a" "" "bcd") + (data $d3 (offset (i32.const 0))) + (data $d4 (offset (i32.const 0)) "" "a" "bc" "") + (data $d5 (memory 0) (i32.const 0)) + (data $d6 (memory 0x0) (i32.const 1) "a" "" "bcd") + (data $d7 (memory 0x000) (offset (i32.const 0))) + (data $d8 (memory 0) (offset (i32.const 0)) "" "a" "bc" "") + (data $d9 (memory $m) (i32.const 0)) + (data $d10 (memory $m) (i32.const 1) "a" "" "bcd") + (data $d11 (memory $m) (offset (i32.const 0))) + (data $d12 (memory $m) (offset (i32.const 0)) "" "a" "bc" "") ) ;; Basic use @@ -158,44 +170,42 @@ ;; Invalid bounds for data -(assert_unlinkable +(assert_trap (module (memory 0) (data (i32.const 0) "a") ) - "data segment does not fit" + "out of bounds" ) -(assert_unlinkable +(assert_trap (module (memory 0 0) (data (i32.const 0) "a") ) - "data segment does not fit" + "out of bounds" ) -(assert_unlinkable +(assert_trap (module (memory 0 1) (data (i32.const 0) "a") ) - "data segment does not fit" + "out of bounds" ) - -(assert_unlinkable +(assert_trap (module (memory 0) (data (i32.const 1)) ) - "data segment does not fit" + "out of bounds" ) - -(assert_unlinkable +(assert_trap (module (memory 0 1) (data (i32.const 1)) ) - "data segment does not fit" + "out of bounds" ) ;; This seems to cause a time-out on Travis. @@ -204,77 +214,77 @@ (memory 0x10000) (data (i32.const 0xffffffff) "ab") ) - "" ;; either out of memory or segment does not fit + "" ;; either out of memory or out of bounds ;) -(assert_unlinkable +(assert_trap (module (global (import "spectest" "global_i32") i32) (memory 0) (data (global.get 0) "a") ) - "data segment does not fit" + "out of bounds" ) -(assert_unlinkable +(assert_trap (module (memory 1 2) (data (i32.const 0x1_0000) "a") ) - "data segment does not fit" + "out of bounds" ) -(assert_unlinkable +(assert_trap (module (import "spectest" "memory" (memory 1)) (data (i32.const 0x1_0000) "a") ) - "data segment does not fit" + "out of bounds" ) -(assert_unlinkable +(assert_trap (module (memory 2) (data (i32.const 0x2_0000) "a") ) - "data segment does not fit" + "out of bounds" ) -(assert_unlinkable +(assert_trap (module (memory 2 3) (data (i32.const 0x2_0000) "a") ) - "data segment does not fit" + "out of bounds" ) -(assert_unlinkable +(assert_trap (module (memory 1) (data (i32.const -1) "a") ) - "data segment does not fit" + "out of bounds" ) -(assert_unlinkable +(assert_trap (module (import "spectest" "memory" (memory 1)) (data (i32.const -1) "a") ) - "data segment does not fit" + "out of bounds" ) -(assert_unlinkable +(assert_trap (module (memory 2) (data (i32.const -100) "a") ) - "data segment does not fit" + "out of bounds" ) -(assert_unlinkable +(assert_trap (module (import "spectest" "memory" (memory 1)) (data (i32.const -100) "a") ) - "data segment does not fit" + "out of bounds" ) ;; Data without memory diff --git a/test/core/elem.wast b/test/core/elem.wast index 1ea2b06184..bb622ee662 100644 --- a/test/core/elem.wast +++ b/test/core/elem.wast @@ -4,20 +4,73 @@ (module (table $t 10 funcref) (func $f) - (elem (i32.const 0)) - (elem (i32.const 0) $f $f) + (func $g) + + ;; Passive + (elem funcref) + (elem funcref (ref.func $f) (ref.func $f) (ref.null) (ref.func $g)) + (elem func) + (elem func $f $f $g $g) + + (elem $p1 funcref) + (elem $p2 funcref (ref.func $f) (ref.func $f) (ref.null) (ref.func $g)) + (elem $p3 func) + (elem $p4 func $f $f $g $g) + + ;; Active + (elem (table $t) (i32.const 0) funcref) + (elem (table $t) (i32.const 0) funcref (ref.func $f) (ref.null)) + (elem (table $t) (i32.const 0) func) + (elem (table $t) (i32.const 0) func $f $g) + (elem (table $t) (offset (i32.const 0)) funcref) + (elem (table $t) (offset (i32.const 0)) func $f $g) + (elem (table 0) (i32.const 0) func) + (elem (table 0x0) (i32.const 0) func $f $f) + (elem (table 0x000) (offset (i32.const 0)) func) + (elem (table 0) (offset (i32.const 0)) func $f $f) + (elem (table $t) (i32.const 0) func) + (elem (table $t) (i32.const 0) func $f $f) + (elem (table $t) (offset (i32.const 0)) func) + (elem (table $t) (offset (i32.const 0)) func $f $f) (elem (offset (i32.const 0))) + (elem (offset (i32.const 0)) funcref (ref.func $f) (ref.null)) + (elem (offset (i32.const 0)) func $f $f) (elem (offset (i32.const 0)) $f $f) - (elem 0 (i32.const 0)) - (elem 0x0 (i32.const 0) $f $f) - (elem 0x000 (offset (i32.const 0))) - (elem 0 (offset (i32.const 0)) $f $f) - (elem $t (i32.const 0)) - (elem $t (i32.const 0) $f $f) - (elem $t (offset (i32.const 0))) - (elem $t (offset (i32.const 0)) $f $f) + (elem (i32.const 0)) + (elem (i32.const 0) funcref (ref.func $f) (ref.null)) + (elem (i32.const 0) func $f $f) + (elem (i32.const 0) $f $f) + + (elem $a1 (table $t) (i32.const 0) funcref) + (elem $a2 (table $t) (i32.const 0) funcref (ref.func $f) (ref.null)) + (elem $a3 (table $t) (i32.const 0) func) + (elem $a4 (table $t) (i32.const 0) func $f $g) + (elem $a9 (table $t) (offset (i32.const 0)) funcref) + (elem $a10 (table $t) (offset (i32.const 0)) func $f $g) + (elem $a11 (table 0) (i32.const 0) func) + (elem $a12 (table 0x0) (i32.const 0) func $f $f) + (elem $a13 (table 0x000) (offset (i32.const 0)) func) + (elem $a14 (table 0) (offset (i32.const 0)) func $f $f) + (elem $a15 (table $t) (i32.const 0) func) + (elem $a16 (table $t) (i32.const 0) func $f $f) + (elem $a17 (table $t) (offset (i32.const 0)) func) + (elem $a18 (table $t) (offset (i32.const 0)) func $f $f) + (elem $a19 (offset (i32.const 0))) + (elem $a20 (offset (i32.const 0)) funcref (ref.func $f) (ref.null)) + (elem $a21 (offset (i32.const 0)) func $f $f) + (elem $a22 (offset (i32.const 0)) $f $f) + (elem $a23 (i32.const 0)) + (elem $a24 (i32.const 0) funcref (ref.func $f) (ref.null)) + (elem $a25 (i32.const 0) func $f $f) + (elem $a26 (i32.const 0) $f $f) ) +(module + (func $f) + (func $g) + + (table $t funcref (elem (ref.func $f) (ref.null) (ref.func $g))) +) ;; Basic use (module @@ -139,107 +192,106 @@ ;; Invalid bounds for elements -(assert_unlinkable +(assert_trap (module (table 0 funcref) (func $f) (elem (i32.const 0) $f) ) - "elements segment does not fit" + "out of bounds" ) -(assert_unlinkable +(assert_trap (module (table 0 0 funcref) (func $f) (elem (i32.const 0) $f) ) - "elements segment does not fit" + "out of bounds" ) -(assert_unlinkable +(assert_trap (module (table 0 1 funcref) (func $f) (elem (i32.const 0) $f) ) - "elements segment does not fit" + "out of bounds" ) -(assert_unlinkable +(assert_trap (module (table 0 funcref) (elem (i32.const 1)) ) - "elements segment does not fit" + "out of bounds" ) - -(assert_unlinkable +(assert_trap (module (table 10 funcref) (func $f) (elem (i32.const 10) $f) ) - "elements segment does not fit" + "out of bounds" ) -(assert_unlinkable +(assert_trap (module (import "spectest" "table" (table 10 funcref)) (func $f) (elem (i32.const 10) $f) ) - "elements segment does not fit" + "out of bounds" ) -(assert_unlinkable +(assert_trap (module (table 10 20 funcref) (func $f) (elem (i32.const 10) $f) ) - "elements segment does not fit" + "out of bounds" ) -(assert_unlinkable +(assert_trap (module (import "spectest" "table" (table 10 funcref)) (func $f) (elem (i32.const 10) $f) ) - "elements segment does not fit" + "out of bounds" ) -(assert_unlinkable +(assert_trap (module (table 10 funcref) (func $f) (elem (i32.const -1) $f) ) - "elements segment does not fit" + "out of bounds" ) -(assert_unlinkable +(assert_trap (module (import "spectest" "table" (table 10 funcref)) (func $f) (elem (i32.const -1) $f) ) - "elements segment does not fit" + "out of bounds" ) -(assert_unlinkable +(assert_trap (module (table 10 funcref) (func $f) (elem (i32.const -10) $f) ) - "elements segment does not fit" + "out of bounds" ) -(assert_unlinkable +(assert_trap (module (import "spectest" "table" (table 10 funcref)) (func $f) (elem (i32.const -10) $f) ) - "elements segment does not fit" + "out of bounds" ) ;; Element without table diff --git a/test/core/imports.wast b/test/core/imports.wast index 0a396d1be2..c3a011d73c 100644 --- a/test/core/imports.wast +++ b/test/core/imports.wast @@ -272,7 +272,7 @@ (module (type (func (result i32))) (import "spectest" "table" (table $tab 10 20 funcref)) - (elem $tab (i32.const 1) $f $g) + (elem (table $tab) (i32.const 1) func $f $g) (func (export "call") (param i32) (result i32) (call_indirect $tab (type 0) (local.get 0)) @@ -291,7 +291,7 @@ (module (type (func (result i32))) (table $tab (import "spectest" "table") 10 20 funcref) - (elem $tab (i32.const 1) $f $g) + (elem (table $tab) (i32.const 1) func $f $g) (func (export "call") (param i32) (result i32) (call_indirect $tab (type 0) (local.get 0)) @@ -392,7 +392,7 @@ (module (import "spectest" "memory" (memory 1 2)) - (data 0 (i32.const 10) "\10") + (data (memory 0) (i32.const 10) "\10") (func (export "load") (param i32) (result i32) (i32.load (local.get 0))) ) @@ -404,7 +404,7 @@ (module (memory (import "spectest" "memory") 1 2) - (data 0 (i32.const 10) "\10") + (data (memory 0) (i32.const 10) "\10") (func (export "load") (param i32) (result i32) (i32.load (local.get 0))) ) diff --git a/test/core/linking.wast b/test/core/linking.wast index e72f928b5f..bf6356fbb9 100644 --- a/test/core/linking.wast +++ b/test/core/linking.wast @@ -266,13 +266,13 @@ ) (assert_return (get $G2 "g") (i32.const 5)) -(assert_unlinkable +(assert_trap (module (table (import "Mt" "tab") 0 funcref) (elem (i32.const 10) $f) (func $f) ) - "elements segment does not fit" + "out of bounds" ) (assert_unlinkable @@ -287,28 +287,30 @@ ) (assert_trap (invoke $Mt "call" (i32.const 7)) "uninitialized") -(assert_unlinkable +;; Unlike in the v1 spec, active element segments stored before an +;; out-of-bounds access persist after the instantiation failure. +(assert_trap (module (table (import "Mt" "tab") 10 funcref) (func $f (result i32) (i32.const 0)) (elem (i32.const 7) $f) (elem (i32.const 12) $f) ;; out of bounds ) - "elements segment does not fit" + "out of bounds" ) -(assert_trap (invoke $Mt "call" (i32.const 7)) "uninitialized") +(assert_return (invoke $Mt "call" (i32.const 7)) (i32.const 0)) -(assert_unlinkable +(assert_trap (module (table (import "Mt" "tab") 10 funcref) (func $f (result i32) (i32.const 0)) (elem (i32.const 7) $f) (memory 1) - (data (i32.const 0x10000) "d") ;; out of bounds + (data (i32.const 0x10000) "d") ;; out of bounds ) - "data segment does not fit" + "out of bounds" ) -(assert_trap (invoke $Mt "call" (i32.const 7)) "uninitialized") +(assert_return (invoke $Mt "call" (i32.const 7)) (i32.const 0)) (module $Mtable_ex @@ -397,12 +399,12 @@ (data (i32.const 0xffff) "a") ) -(assert_unlinkable +(assert_trap (module (memory (import "Mm" "mem") 0) (data (i32.const 0x10000) "a") ) - "data segment does not fit" + "out of bounds" ) (module $Pm @@ -433,27 +435,29 @@ ) (assert_return (invoke $Mm "load" (i32.const 0)) (i32.const 0)) -(assert_unlinkable +;; Unlike in v1 spec, active data segments written before an +;; out-of-bounds access persist after the instantiation failure. +(assert_trap (module (memory (import "Mm" "mem") 1) (data (i32.const 0) "abc") (data (i32.const 0x50000) "d") ;; out of bounds ) - "data segment does not fit" + "out of bounds" ) -(assert_return (invoke $Mm "load" (i32.const 0)) (i32.const 0)) +(assert_return (invoke $Mm "load" (i32.const 0)) (i32.const 97)) -(assert_unlinkable +(assert_trap (module (memory (import "Mm" "mem") 1) (data (i32.const 0) "abc") (table 0 funcref) (func) - (elem (i32.const 0) 0) ;; out of bounds + (elem (i32.const 0) 0) ;; out of bounds ) - "elements segment does not fit" + "out of bounds" ) -(assert_return (invoke $Mm "load" (i32.const 0)) (i32.const 0)) +(assert_return (invoke $Mm "load" (i32.const 0)) (i32.const 97)) ;; Store is modified if the start function traps. (module $Ms diff --git a/test/core/memory_copy.wast b/test/core/memory_copy.wast new file mode 100644 index 0000000000..692e1ad85f --- /dev/null +++ b/test/core/memory_copy.wast @@ -0,0 +1,5577 @@ +;; +;; Generated by ../meta/generate_memory_copy.js +;; + +(module + (memory (export "memory0") 1 1) + (data (i32.const 2) "\03\01\04\01") + (data (i32.const 12) "\07\05\02\03\06") + (func (export "test") + (nop)) + (func (export "load8_u") (param i32) (result i32) + (i32.load8_u (local.get 0)))) + +(invoke "test") + +(assert_return (invoke "load8_u" (i32.const 0)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 1)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 2)) (i32.const 3)) +(assert_return (invoke "load8_u" (i32.const 3)) (i32.const 1)) +(assert_return (invoke "load8_u" (i32.const 4)) (i32.const 4)) +(assert_return (invoke "load8_u" (i32.const 5)) (i32.const 1)) +(assert_return (invoke "load8_u" (i32.const 6)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 7)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 8)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 9)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 10)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 11)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 12)) (i32.const 7)) +(assert_return (invoke "load8_u" (i32.const 13)) (i32.const 5)) +(assert_return (invoke "load8_u" (i32.const 14)) (i32.const 2)) +(assert_return (invoke "load8_u" (i32.const 15)) (i32.const 3)) +(assert_return (invoke "load8_u" (i32.const 16)) (i32.const 6)) +(assert_return (invoke "load8_u" (i32.const 17)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 18)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 19)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 20)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 21)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 22)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 23)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 24)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 25)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 26)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 27)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 28)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 29)) (i32.const 0)) + +(module + (memory (export "memory0") 1 1) + (data (i32.const 2) "\03\01\04\01") + (data (i32.const 12) "\07\05\02\03\06") + (func (export "test") + (memory.copy (i32.const 13) (i32.const 2) (i32.const 3))) + (func (export "load8_u") (param i32) (result i32) + (i32.load8_u (local.get 0)))) + +(invoke "test") + +(assert_return (invoke "load8_u" (i32.const 0)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 1)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 2)) (i32.const 3)) +(assert_return (invoke "load8_u" (i32.const 3)) (i32.const 1)) +(assert_return (invoke "load8_u" (i32.const 4)) (i32.const 4)) +(assert_return (invoke "load8_u" (i32.const 5)) (i32.const 1)) +(assert_return (invoke "load8_u" (i32.const 6)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 7)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 8)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 9)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 10)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 11)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 12)) (i32.const 7)) +(assert_return (invoke "load8_u" (i32.const 13)) (i32.const 3)) +(assert_return (invoke "load8_u" (i32.const 14)) (i32.const 1)) +(assert_return (invoke "load8_u" (i32.const 15)) (i32.const 4)) +(assert_return (invoke "load8_u" (i32.const 16)) (i32.const 6)) +(assert_return (invoke "load8_u" (i32.const 17)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 18)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 19)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 20)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 21)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 22)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 23)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 24)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 25)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 26)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 27)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 28)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 29)) (i32.const 0)) + +(module + (memory (export "memory0") 1 1) + (data (i32.const 2) "\03\01\04\01") + (data (i32.const 12) "\07\05\02\03\06") + (func (export "test") + (memory.copy (i32.const 25) (i32.const 15) (i32.const 2))) + (func (export "load8_u") (param i32) (result i32) + (i32.load8_u (local.get 0)))) + +(invoke "test") + +(assert_return (invoke "load8_u" (i32.const 0)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 1)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 2)) (i32.const 3)) +(assert_return (invoke "load8_u" (i32.const 3)) (i32.const 1)) +(assert_return (invoke "load8_u" (i32.const 4)) (i32.const 4)) +(assert_return (invoke "load8_u" (i32.const 5)) (i32.const 1)) +(assert_return (invoke "load8_u" (i32.const 6)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 7)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 8)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 9)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 10)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 11)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 12)) (i32.const 7)) +(assert_return (invoke "load8_u" (i32.const 13)) (i32.const 5)) +(assert_return (invoke "load8_u" (i32.const 14)) (i32.const 2)) +(assert_return (invoke "load8_u" (i32.const 15)) (i32.const 3)) +(assert_return (invoke "load8_u" (i32.const 16)) (i32.const 6)) +(assert_return (invoke "load8_u" (i32.const 17)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 18)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 19)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 20)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 21)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 22)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 23)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 24)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 25)) (i32.const 3)) +(assert_return (invoke "load8_u" (i32.const 26)) (i32.const 6)) +(assert_return (invoke "load8_u" (i32.const 27)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 28)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 29)) (i32.const 0)) + +(module + (memory (export "memory0") 1 1) + (data (i32.const 2) "\03\01\04\01") + (data (i32.const 12) "\07\05\02\03\06") + (func (export "test") + (memory.copy (i32.const 13) (i32.const 25) (i32.const 3))) + (func (export "load8_u") (param i32) (result i32) + (i32.load8_u (local.get 0)))) + +(invoke "test") + +(assert_return (invoke "load8_u" (i32.const 0)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 1)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 2)) (i32.const 3)) +(assert_return (invoke "load8_u" (i32.const 3)) (i32.const 1)) +(assert_return (invoke "load8_u" (i32.const 4)) (i32.const 4)) +(assert_return (invoke "load8_u" (i32.const 5)) (i32.const 1)) +(assert_return (invoke "load8_u" (i32.const 6)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 7)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 8)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 9)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 10)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 11)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 12)) (i32.const 7)) +(assert_return (invoke "load8_u" (i32.const 13)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 14)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 15)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 16)) (i32.const 6)) +(assert_return (invoke "load8_u" (i32.const 17)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 18)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 19)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 20)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 21)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 22)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 23)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 24)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 25)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 26)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 27)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 28)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 29)) (i32.const 0)) + +(module + (memory (export "memory0") 1 1) + (data (i32.const 2) "\03\01\04\01") + (data (i32.const 12) "\07\05\02\03\06") + (func (export "test") + (memory.copy (i32.const 20) (i32.const 22) (i32.const 4))) + (func (export "load8_u") (param i32) (result i32) + (i32.load8_u (local.get 0)))) + +(invoke "test") + +(assert_return (invoke "load8_u" (i32.const 0)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 1)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 2)) (i32.const 3)) +(assert_return (invoke "load8_u" (i32.const 3)) (i32.const 1)) +(assert_return (invoke "load8_u" (i32.const 4)) (i32.const 4)) +(assert_return (invoke "load8_u" (i32.const 5)) (i32.const 1)) +(assert_return (invoke "load8_u" (i32.const 6)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 7)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 8)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 9)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 10)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 11)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 12)) (i32.const 7)) +(assert_return (invoke "load8_u" (i32.const 13)) (i32.const 5)) +(assert_return (invoke "load8_u" (i32.const 14)) (i32.const 2)) +(assert_return (invoke "load8_u" (i32.const 15)) (i32.const 3)) +(assert_return (invoke "load8_u" (i32.const 16)) (i32.const 6)) +(assert_return (invoke "load8_u" (i32.const 17)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 18)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 19)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 20)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 21)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 22)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 23)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 24)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 25)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 26)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 27)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 28)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 29)) (i32.const 0)) + +(module + (memory (export "memory0") 1 1) + (data (i32.const 2) "\03\01\04\01") + (data (i32.const 12) "\07\05\02\03\06") + (func (export "test") + (memory.copy (i32.const 25) (i32.const 1) (i32.const 3))) + (func (export "load8_u") (param i32) (result i32) + (i32.load8_u (local.get 0)))) + +(invoke "test") + +(assert_return (invoke "load8_u" (i32.const 0)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 1)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 2)) (i32.const 3)) +(assert_return (invoke "load8_u" (i32.const 3)) (i32.const 1)) +(assert_return (invoke "load8_u" (i32.const 4)) (i32.const 4)) +(assert_return (invoke "load8_u" (i32.const 5)) (i32.const 1)) +(assert_return (invoke "load8_u" (i32.const 6)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 7)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 8)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 9)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 10)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 11)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 12)) (i32.const 7)) +(assert_return (invoke "load8_u" (i32.const 13)) (i32.const 5)) +(assert_return (invoke "load8_u" (i32.const 14)) (i32.const 2)) +(assert_return (invoke "load8_u" (i32.const 15)) (i32.const 3)) +(assert_return (invoke "load8_u" (i32.const 16)) (i32.const 6)) +(assert_return (invoke "load8_u" (i32.const 17)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 18)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 19)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 20)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 21)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 22)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 23)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 24)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 25)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 26)) (i32.const 3)) +(assert_return (invoke "load8_u" (i32.const 27)) (i32.const 1)) +(assert_return (invoke "load8_u" (i32.const 28)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 29)) (i32.const 0)) + +(module + (memory (export "memory0") 1 1) + (data (i32.const 2) "\03\01\04\01") + (data (i32.const 12) "\07\05\02\03\06") + (func (export "test") + (memory.copy (i32.const 10) (i32.const 12) (i32.const 7))) + (func (export "load8_u") (param i32) (result i32) + (i32.load8_u (local.get 0)))) + +(invoke "test") + +(assert_return (invoke "load8_u" (i32.const 0)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 1)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 2)) (i32.const 3)) +(assert_return (invoke "load8_u" (i32.const 3)) (i32.const 1)) +(assert_return (invoke "load8_u" (i32.const 4)) (i32.const 4)) +(assert_return (invoke "load8_u" (i32.const 5)) (i32.const 1)) +(assert_return (invoke "load8_u" (i32.const 6)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 7)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 8)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 9)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 10)) (i32.const 7)) +(assert_return (invoke "load8_u" (i32.const 11)) (i32.const 5)) +(assert_return (invoke "load8_u" (i32.const 12)) (i32.const 2)) +(assert_return (invoke "load8_u" (i32.const 13)) (i32.const 3)) +(assert_return (invoke "load8_u" (i32.const 14)) (i32.const 6)) +(assert_return (invoke "load8_u" (i32.const 15)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 16)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 17)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 18)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 19)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 20)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 21)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 22)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 23)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 24)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 25)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 26)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 27)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 28)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 29)) (i32.const 0)) + +(module + (memory (export "memory0") 1 1) + (data (i32.const 2) "\03\01\04\01") + (data (i32.const 12) "\07\05\02\03\06") + (func (export "test") + (memory.copy (i32.const 12) (i32.const 10) (i32.const 7))) + (func (export "load8_u") (param i32) (result i32) + (i32.load8_u (local.get 0)))) + +(invoke "test") + +(assert_return (invoke "load8_u" (i32.const 0)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 1)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 2)) (i32.const 3)) +(assert_return (invoke "load8_u" (i32.const 3)) (i32.const 1)) +(assert_return (invoke "load8_u" (i32.const 4)) (i32.const 4)) +(assert_return (invoke "load8_u" (i32.const 5)) (i32.const 1)) +(assert_return (invoke "load8_u" (i32.const 6)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 7)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 8)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 9)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 10)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 11)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 12)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 13)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 14)) (i32.const 7)) +(assert_return (invoke "load8_u" (i32.const 15)) (i32.const 5)) +(assert_return (invoke "load8_u" (i32.const 16)) (i32.const 2)) +(assert_return (invoke "load8_u" (i32.const 17)) (i32.const 3)) +(assert_return (invoke "load8_u" (i32.const 18)) (i32.const 6)) +(assert_return (invoke "load8_u" (i32.const 19)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 20)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 21)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 22)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 23)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 24)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 25)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 26)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 27)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 28)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 29)) (i32.const 0)) + +(module + (memory (export "mem") 1 1 ) + (data (i32.const 0) "\00\01\02\03\04\05\06\07\08\09\0a\0b\0c\0d\0e\0f\10\11\12\13") + (func (export "run") (param $targetOffs i32) (param $srcOffs i32) (param $len i32) + (memory.copy (local.get $targetOffs) (local.get $srcOffs) (local.get $len))) + (func (export "load8_u") (param i32) (result i32) + (i32.load8_u (local.get 0)))) + +(assert_trap (invoke "run" (i32.const 65516) (i32.const 0) (i32.const 40)) + "out of bounds") + +(assert_return (invoke "load8_u" (i32.const 0)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 1)) (i32.const 1)) +(assert_return (invoke "load8_u" (i32.const 2)) (i32.const 2)) +(assert_return (invoke "load8_u" (i32.const 3)) (i32.const 3)) +(assert_return (invoke "load8_u" (i32.const 4)) (i32.const 4)) +(assert_return (invoke "load8_u" (i32.const 5)) (i32.const 5)) +(assert_return (invoke "load8_u" (i32.const 6)) (i32.const 6)) +(assert_return (invoke "load8_u" (i32.const 7)) (i32.const 7)) +(assert_return (invoke "load8_u" (i32.const 8)) (i32.const 8)) +(assert_return (invoke "load8_u" (i32.const 9)) (i32.const 9)) +(assert_return (invoke "load8_u" (i32.const 10)) (i32.const 10)) +(assert_return (invoke "load8_u" (i32.const 11)) (i32.const 11)) +(assert_return (invoke "load8_u" (i32.const 12)) (i32.const 12)) +(assert_return (invoke "load8_u" (i32.const 13)) (i32.const 13)) +(assert_return (invoke "load8_u" (i32.const 14)) (i32.const 14)) +(assert_return (invoke "load8_u" (i32.const 15)) (i32.const 15)) +(assert_return (invoke "load8_u" (i32.const 16)) (i32.const 16)) +(assert_return (invoke "load8_u" (i32.const 17)) (i32.const 17)) +(assert_return (invoke "load8_u" (i32.const 18)) (i32.const 18)) +(assert_return (invoke "load8_u" (i32.const 19)) (i32.const 19)) +(assert_return (invoke "load8_u" (i32.const 218)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 417)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 616)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 815)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 1014)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 1213)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 1412)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 1611)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 1810)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 2009)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 2208)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 2407)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 2606)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 2805)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 3004)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 3203)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 3402)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 3601)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 3800)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 3999)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 4198)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 4397)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 4596)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 4795)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 4994)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 5193)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 5392)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 5591)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 5790)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 5989)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 6188)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 6387)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 6586)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 6785)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 6984)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 7183)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 7382)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 7581)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 7780)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 7979)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 8178)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 8377)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 8576)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 8775)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 8974)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 9173)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 9372)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 9571)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 9770)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 9969)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 10168)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 10367)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 10566)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 10765)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 10964)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 11163)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 11362)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 11561)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 11760)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 11959)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 12158)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 12357)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 12556)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 12755)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 12954)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 13153)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 13352)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 13551)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 13750)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 13949)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 14148)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 14347)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 14546)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 14745)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 14944)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 15143)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 15342)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 15541)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 15740)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 15939)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 16138)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 16337)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 16536)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 16735)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 16934)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 17133)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 17332)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 17531)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 17730)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 17929)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 18128)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 18327)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 18526)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 18725)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 18924)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 19123)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 19322)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 19521)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 19720)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 19919)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 20118)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 20317)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 20516)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 20715)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 20914)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 21113)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 21312)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 21511)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 21710)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 21909)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 22108)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 22307)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 22506)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 22705)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 22904)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 23103)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 23302)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 23501)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 23700)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 23899)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 24098)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 24297)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 24496)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 24695)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 24894)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 25093)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 25292)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 25491)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 25690)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 25889)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 26088)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 26287)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 26486)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 26685)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 26884)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 27083)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 27282)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 27481)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 27680)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 27879)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 28078)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 28277)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 28476)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 28675)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 28874)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 29073)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 29272)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 29471)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 29670)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 29869)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 30068)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 30267)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 30466)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 30665)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 30864)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 31063)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 31262)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 31461)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 31660)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 31859)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 32058)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 32257)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 32456)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 32655)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 32854)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 33053)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 33252)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 33451)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 33650)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 33849)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 34048)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 34247)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 34446)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 34645)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 34844)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 35043)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 35242)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 35441)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 35640)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 35839)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 36038)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 36237)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 36436)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 36635)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 36834)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 37033)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 37232)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 37431)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 37630)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 37829)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 38028)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 38227)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 38426)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 38625)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 38824)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 39023)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 39222)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 39421)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 39620)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 39819)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 40018)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 40217)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 40416)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 40615)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 40814)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 41013)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 41212)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 41411)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 41610)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 41809)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 42008)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 42207)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 42406)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 42605)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 42804)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 43003)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 43202)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 43401)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 43600)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 43799)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 43998)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 44197)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 44396)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 44595)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 44794)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 44993)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 45192)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 45391)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 45590)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 45789)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 45988)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 46187)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 46386)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 46585)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 46784)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 46983)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 47182)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 47381)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 47580)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 47779)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 47978)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 48177)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 48376)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 48575)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 48774)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 48973)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 49172)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 49371)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 49570)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 49769)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 49968)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 50167)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 50366)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 50565)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 50764)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 50963)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 51162)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 51361)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 51560)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 51759)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 51958)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 52157)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 52356)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 52555)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 52754)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 52953)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 53152)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 53351)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 53550)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 53749)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 53948)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 54147)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 54346)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 54545)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 54744)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 54943)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 55142)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 55341)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 55540)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 55739)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 55938)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 56137)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 56336)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 56535)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 56734)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 56933)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 57132)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 57331)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 57530)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 57729)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 57928)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 58127)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 58326)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 58525)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 58724)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 58923)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 59122)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 59321)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 59520)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 59719)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 59918)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 60117)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 60316)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 60515)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 60714)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 60913)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 61112)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 61311)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 61510)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 61709)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 61908)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 62107)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 62306)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 62505)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 62704)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 62903)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 63102)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 63301)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 63500)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 63699)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 63898)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 64097)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 64296)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 64495)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 64694)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 64893)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 65092)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 65291)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 65490)) (i32.const 0)) + +(module + (memory (export "mem") 1 1 ) + (data (i32.const 0) "\00\01\02\03\04\05\06\07\08\09\0a\0b\0c\0d\0e\0f\10\11\12\13\14") + (func (export "run") (param $targetOffs i32) (param $srcOffs i32) (param $len i32) + (memory.copy (local.get $targetOffs) (local.get $srcOffs) (local.get $len))) + (func (export "load8_u") (param i32) (result i32) + (i32.load8_u (local.get 0)))) + +(assert_trap (invoke "run" (i32.const 65515) (i32.const 0) (i32.const 39)) + "out of bounds") + +(assert_return (invoke "load8_u" (i32.const 0)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 1)) (i32.const 1)) +(assert_return (invoke "load8_u" (i32.const 2)) (i32.const 2)) +(assert_return (invoke "load8_u" (i32.const 3)) (i32.const 3)) +(assert_return (invoke "load8_u" (i32.const 4)) (i32.const 4)) +(assert_return (invoke "load8_u" (i32.const 5)) (i32.const 5)) +(assert_return (invoke "load8_u" (i32.const 6)) (i32.const 6)) +(assert_return (invoke "load8_u" (i32.const 7)) (i32.const 7)) +(assert_return (invoke "load8_u" (i32.const 8)) (i32.const 8)) +(assert_return (invoke "load8_u" (i32.const 9)) (i32.const 9)) +(assert_return (invoke "load8_u" (i32.const 10)) (i32.const 10)) +(assert_return (invoke "load8_u" (i32.const 11)) (i32.const 11)) +(assert_return (invoke "load8_u" (i32.const 12)) (i32.const 12)) +(assert_return (invoke "load8_u" (i32.const 13)) (i32.const 13)) +(assert_return (invoke "load8_u" (i32.const 14)) (i32.const 14)) +(assert_return (invoke "load8_u" (i32.const 15)) (i32.const 15)) +(assert_return (invoke "load8_u" (i32.const 16)) (i32.const 16)) +(assert_return (invoke "load8_u" (i32.const 17)) (i32.const 17)) +(assert_return (invoke "load8_u" (i32.const 18)) (i32.const 18)) +(assert_return (invoke "load8_u" (i32.const 19)) (i32.const 19)) +(assert_return (invoke "load8_u" (i32.const 20)) (i32.const 20)) +(assert_return (invoke "load8_u" (i32.const 219)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 418)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 617)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 816)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 1015)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 1214)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 1413)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 1612)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 1811)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 2010)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 2209)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 2408)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 2607)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 2806)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 3005)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 3204)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 3403)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 3602)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 3801)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 4000)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 4199)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 4398)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 4597)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 4796)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 4995)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 5194)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 5393)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 5592)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 5791)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 5990)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 6189)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 6388)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 6587)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 6786)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 6985)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 7184)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 7383)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 7582)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 7781)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 7980)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 8179)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 8378)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 8577)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 8776)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 8975)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 9174)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 9373)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 9572)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 9771)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 9970)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 10169)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 10368)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 10567)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 10766)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 10965)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 11164)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 11363)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 11562)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 11761)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 11960)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 12159)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 12358)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 12557)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 12756)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 12955)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 13154)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 13353)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 13552)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 13751)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 13950)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 14149)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 14348)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 14547)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 14746)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 14945)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 15144)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 15343)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 15542)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 15741)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 15940)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 16139)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 16338)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 16537)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 16736)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 16935)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 17134)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 17333)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 17532)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 17731)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 17930)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 18129)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 18328)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 18527)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 18726)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 18925)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 19124)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 19323)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 19522)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 19721)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 19920)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 20119)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 20318)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 20517)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 20716)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 20915)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 21114)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 21313)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 21512)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 21711)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 21910)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 22109)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 22308)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 22507)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 22706)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 22905)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 23104)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 23303)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 23502)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 23701)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 23900)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 24099)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 24298)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 24497)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 24696)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 24895)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 25094)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 25293)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 25492)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 25691)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 25890)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 26089)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 26288)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 26487)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 26686)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 26885)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 27084)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 27283)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 27482)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 27681)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 27880)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 28079)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 28278)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 28477)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 28676)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 28875)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 29074)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 29273)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 29472)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 29671)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 29870)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 30069)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 30268)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 30467)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 30666)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 30865)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 31064)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 31263)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 31462)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 31661)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 31860)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 32059)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 32258)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 32457)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 32656)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 32855)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 33054)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 33253)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 33452)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 33651)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 33850)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 34049)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 34248)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 34447)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 34646)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 34845)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 35044)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 35243)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 35442)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 35641)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 35840)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 36039)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 36238)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 36437)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 36636)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 36835)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 37034)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 37233)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 37432)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 37631)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 37830)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 38029)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 38228)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 38427)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 38626)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 38825)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 39024)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 39223)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 39422)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 39621)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 39820)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 40019)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 40218)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 40417)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 40616)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 40815)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 41014)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 41213)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 41412)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 41611)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 41810)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 42009)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 42208)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 42407)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 42606)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 42805)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 43004)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 43203)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 43402)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 43601)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 43800)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 43999)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 44198)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 44397)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 44596)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 44795)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 44994)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 45193)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 45392)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 45591)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 45790)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 45989)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 46188)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 46387)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 46586)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 46785)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 46984)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 47183)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 47382)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 47581)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 47780)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 47979)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 48178)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 48377)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 48576)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 48775)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 48974)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 49173)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 49372)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 49571)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 49770)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 49969)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 50168)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 50367)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 50566)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 50765)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 50964)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 51163)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 51362)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 51561)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 51760)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 51959)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 52158)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 52357)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 52556)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 52755)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 52954)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 53153)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 53352)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 53551)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 53750)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 53949)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 54148)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 54347)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 54546)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 54745)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 54944)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 55143)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 55342)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 55541)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 55740)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 55939)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 56138)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 56337)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 56536)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 56735)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 56934)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 57133)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 57332)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 57531)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 57730)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 57929)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 58128)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 58327)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 58526)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 58725)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 58924)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 59123)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 59322)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 59521)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 59720)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 59919)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 60118)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 60317)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 60516)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 60715)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 60914)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 61113)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 61312)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 61511)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 61710)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 61909)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 62108)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 62307)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 62506)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 62705)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 62904)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 63103)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 63302)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 63501)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 63700)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 63899)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 64098)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 64297)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 64496)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 64695)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 64894)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 65093)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 65292)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 65491)) (i32.const 0)) + +(module + (memory (export "mem") 1 1 ) + (data (i32.const 65516) "\00\01\02\03\04\05\06\07\08\09\0a\0b\0c\0d\0e\0f\10\11\12\13") + (func (export "run") (param $targetOffs i32) (param $srcOffs i32) (param $len i32) + (memory.copy (local.get $targetOffs) (local.get $srcOffs) (local.get $len))) + (func (export "load8_u") (param i32) (result i32) + (i32.load8_u (local.get 0)))) + +(assert_trap (invoke "run" (i32.const 0) (i32.const 65516) (i32.const 40)) + "out of bounds") + +(assert_return (invoke "load8_u" (i32.const 198)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 397)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 596)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 795)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 994)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 1193)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 1392)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 1591)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 1790)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 1989)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 2188)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 2387)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 2586)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 2785)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 2984)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 3183)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 3382)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 3581)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 3780)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 3979)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 4178)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 4377)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 4576)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 4775)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 4974)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 5173)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 5372)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 5571)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 5770)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 5969)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 6168)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 6367)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 6566)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 6765)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 6964)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 7163)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 7362)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 7561)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 7760)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 7959)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 8158)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 8357)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 8556)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 8755)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 8954)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 9153)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 9352)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 9551)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 9750)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 9949)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 10148)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 10347)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 10546)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 10745)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 10944)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 11143)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 11342)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 11541)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 11740)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 11939)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 12138)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 12337)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 12536)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 12735)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 12934)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 13133)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 13332)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 13531)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 13730)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 13929)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 14128)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 14327)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 14526)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 14725)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 14924)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 15123)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 15322)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 15521)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 15720)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 15919)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 16118)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 16317)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 16516)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 16715)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 16914)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 17113)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 17312)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 17511)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 17710)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 17909)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 18108)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 18307)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 18506)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 18705)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 18904)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 19103)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 19302)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 19501)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 19700)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 19899)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 20098)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 20297)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 20496)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 20695)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 20894)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 21093)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 21292)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 21491)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 21690)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 21889)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 22088)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 22287)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 22486)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 22685)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 22884)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 23083)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 23282)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 23481)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 23680)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 23879)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 24078)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 24277)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 24476)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 24675)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 24874)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 25073)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 25272)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 25471)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 25670)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 25869)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 26068)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 26267)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 26466)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 26665)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 26864)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 27063)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 27262)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 27461)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 27660)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 27859)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 28058)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 28257)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 28456)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 28655)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 28854)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 29053)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 29252)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 29451)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 29650)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 29849)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 30048)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 30247)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 30446)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 30645)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 30844)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 31043)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 31242)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 31441)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 31640)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 31839)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 32038)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 32237)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 32436)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 32635)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 32834)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 33033)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 33232)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 33431)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 33630)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 33829)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 34028)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 34227)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 34426)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 34625)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 34824)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 35023)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 35222)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 35421)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 35620)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 35819)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 36018)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 36217)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 36416)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 36615)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 36814)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 37013)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 37212)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 37411)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 37610)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 37809)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 38008)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 38207)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 38406)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 38605)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 38804)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 39003)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 39202)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 39401)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 39600)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 39799)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 39998)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 40197)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 40396)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 40595)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 40794)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 40993)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 41192)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 41391)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 41590)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 41789)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 41988)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 42187)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 42386)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 42585)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 42784)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 42983)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 43182)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 43381)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 43580)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 43779)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 43978)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 44177)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 44376)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 44575)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 44774)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 44973)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 45172)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 45371)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 45570)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 45769)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 45968)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 46167)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 46366)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 46565)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 46764)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 46963)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 47162)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 47361)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 47560)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 47759)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 47958)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 48157)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 48356)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 48555)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 48754)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 48953)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 49152)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 49351)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 49550)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 49749)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 49948)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 50147)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 50346)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 50545)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 50744)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 50943)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 51142)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 51341)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 51540)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 51739)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 51938)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 52137)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 52336)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 52535)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 52734)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 52933)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 53132)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 53331)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 53530)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 53729)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 53928)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 54127)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 54326)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 54525)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 54724)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 54923)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 55122)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 55321)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 55520)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 55719)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 55918)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 56117)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 56316)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 56515)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 56714)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 56913)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 57112)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 57311)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 57510)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 57709)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 57908)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 58107)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 58306)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 58505)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 58704)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 58903)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 59102)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 59301)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 59500)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 59699)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 59898)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 60097)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 60296)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 60495)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 60694)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 60893)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 61092)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 61291)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 61490)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 61689)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 61888)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 62087)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 62286)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 62485)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 62684)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 62883)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 63082)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 63281)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 63480)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 63679)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 63878)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 64077)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 64276)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 64475)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 64674)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 64873)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 65072)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 65271)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 65470)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 65516)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 65517)) (i32.const 1)) +(assert_return (invoke "load8_u" (i32.const 65518)) (i32.const 2)) +(assert_return (invoke "load8_u" (i32.const 65519)) (i32.const 3)) +(assert_return (invoke "load8_u" (i32.const 65520)) (i32.const 4)) +(assert_return (invoke "load8_u" (i32.const 65521)) (i32.const 5)) +(assert_return (invoke "load8_u" (i32.const 65522)) (i32.const 6)) +(assert_return (invoke "load8_u" (i32.const 65523)) (i32.const 7)) +(assert_return (invoke "load8_u" (i32.const 65524)) (i32.const 8)) +(assert_return (invoke "load8_u" (i32.const 65525)) (i32.const 9)) +(assert_return (invoke "load8_u" (i32.const 65526)) (i32.const 10)) +(assert_return (invoke "load8_u" (i32.const 65527)) (i32.const 11)) +(assert_return (invoke "load8_u" (i32.const 65528)) (i32.const 12)) +(assert_return (invoke "load8_u" (i32.const 65529)) (i32.const 13)) +(assert_return (invoke "load8_u" (i32.const 65530)) (i32.const 14)) +(assert_return (invoke "load8_u" (i32.const 65531)) (i32.const 15)) +(assert_return (invoke "load8_u" (i32.const 65532)) (i32.const 16)) +(assert_return (invoke "load8_u" (i32.const 65533)) (i32.const 17)) +(assert_return (invoke "load8_u" (i32.const 65534)) (i32.const 18)) +(assert_return (invoke "load8_u" (i32.const 65535)) (i32.const 19)) + +(module + (memory (export "mem") 1 1 ) + (data (i32.const 65515) "\00\01\02\03\04\05\06\07\08\09\0a\0b\0c\0d\0e\0f\10\11\12\13\14") + (func (export "run") (param $targetOffs i32) (param $srcOffs i32) (param $len i32) + (memory.copy (local.get $targetOffs) (local.get $srcOffs) (local.get $len))) + (func (export "load8_u") (param i32) (result i32) + (i32.load8_u (local.get 0)))) + +(assert_trap (invoke "run" (i32.const 0) (i32.const 65515) (i32.const 39)) + "out of bounds") + +(assert_return (invoke "load8_u" (i32.const 198)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 397)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 596)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 795)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 994)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 1193)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 1392)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 1591)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 1790)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 1989)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 2188)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 2387)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 2586)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 2785)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 2984)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 3183)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 3382)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 3581)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 3780)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 3979)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 4178)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 4377)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 4576)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 4775)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 4974)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 5173)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 5372)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 5571)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 5770)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 5969)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 6168)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 6367)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 6566)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 6765)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 6964)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 7163)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 7362)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 7561)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 7760)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 7959)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 8158)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 8357)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 8556)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 8755)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 8954)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 9153)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 9352)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 9551)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 9750)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 9949)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 10148)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 10347)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 10546)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 10745)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 10944)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 11143)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 11342)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 11541)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 11740)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 11939)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 12138)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 12337)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 12536)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 12735)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 12934)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 13133)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 13332)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 13531)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 13730)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 13929)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 14128)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 14327)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 14526)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 14725)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 14924)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 15123)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 15322)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 15521)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 15720)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 15919)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 16118)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 16317)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 16516)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 16715)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 16914)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 17113)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 17312)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 17511)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 17710)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 17909)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 18108)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 18307)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 18506)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 18705)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 18904)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 19103)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 19302)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 19501)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 19700)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 19899)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 20098)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 20297)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 20496)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 20695)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 20894)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 21093)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 21292)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 21491)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 21690)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 21889)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 22088)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 22287)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 22486)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 22685)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 22884)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 23083)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 23282)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 23481)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 23680)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 23879)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 24078)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 24277)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 24476)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 24675)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 24874)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 25073)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 25272)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 25471)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 25670)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 25869)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 26068)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 26267)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 26466)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 26665)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 26864)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 27063)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 27262)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 27461)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 27660)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 27859)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 28058)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 28257)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 28456)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 28655)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 28854)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 29053)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 29252)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 29451)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 29650)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 29849)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 30048)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 30247)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 30446)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 30645)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 30844)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 31043)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 31242)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 31441)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 31640)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 31839)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 32038)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 32237)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 32436)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 32635)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 32834)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 33033)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 33232)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 33431)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 33630)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 33829)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 34028)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 34227)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 34426)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 34625)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 34824)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 35023)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 35222)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 35421)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 35620)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 35819)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 36018)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 36217)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 36416)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 36615)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 36814)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 37013)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 37212)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 37411)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 37610)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 37809)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 38008)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 38207)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 38406)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 38605)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 38804)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 39003)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 39202)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 39401)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 39600)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 39799)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 39998)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 40197)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 40396)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 40595)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 40794)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 40993)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 41192)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 41391)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 41590)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 41789)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 41988)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 42187)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 42386)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 42585)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 42784)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 42983)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 43182)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 43381)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 43580)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 43779)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 43978)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 44177)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 44376)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 44575)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 44774)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 44973)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 45172)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 45371)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 45570)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 45769)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 45968)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 46167)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 46366)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 46565)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 46764)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 46963)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 47162)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 47361)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 47560)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 47759)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 47958)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 48157)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 48356)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 48555)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 48754)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 48953)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 49152)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 49351)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 49550)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 49749)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 49948)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 50147)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 50346)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 50545)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 50744)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 50943)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 51142)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 51341)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 51540)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 51739)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 51938)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 52137)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 52336)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 52535)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 52734)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 52933)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 53132)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 53331)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 53530)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 53729)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 53928)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 54127)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 54326)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 54525)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 54724)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 54923)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 55122)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 55321)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 55520)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 55719)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 55918)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 56117)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 56316)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 56515)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 56714)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 56913)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 57112)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 57311)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 57510)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 57709)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 57908)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 58107)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 58306)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 58505)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 58704)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 58903)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 59102)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 59301)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 59500)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 59699)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 59898)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 60097)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 60296)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 60495)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 60694)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 60893)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 61092)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 61291)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 61490)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 61689)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 61888)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 62087)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 62286)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 62485)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 62684)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 62883)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 63082)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 63281)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 63480)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 63679)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 63878)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 64077)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 64276)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 64475)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 64674)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 64873)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 65072)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 65271)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 65470)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 65515)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 65516)) (i32.const 1)) +(assert_return (invoke "load8_u" (i32.const 65517)) (i32.const 2)) +(assert_return (invoke "load8_u" (i32.const 65518)) (i32.const 3)) +(assert_return (invoke "load8_u" (i32.const 65519)) (i32.const 4)) +(assert_return (invoke "load8_u" (i32.const 65520)) (i32.const 5)) +(assert_return (invoke "load8_u" (i32.const 65521)) (i32.const 6)) +(assert_return (invoke "load8_u" (i32.const 65522)) (i32.const 7)) +(assert_return (invoke "load8_u" (i32.const 65523)) (i32.const 8)) +(assert_return (invoke "load8_u" (i32.const 65524)) (i32.const 9)) +(assert_return (invoke "load8_u" (i32.const 65525)) (i32.const 10)) +(assert_return (invoke "load8_u" (i32.const 65526)) (i32.const 11)) +(assert_return (invoke "load8_u" (i32.const 65527)) (i32.const 12)) +(assert_return (invoke "load8_u" (i32.const 65528)) (i32.const 13)) +(assert_return (invoke "load8_u" (i32.const 65529)) (i32.const 14)) +(assert_return (invoke "load8_u" (i32.const 65530)) (i32.const 15)) +(assert_return (invoke "load8_u" (i32.const 65531)) (i32.const 16)) +(assert_return (invoke "load8_u" (i32.const 65532)) (i32.const 17)) +(assert_return (invoke "load8_u" (i32.const 65533)) (i32.const 18)) +(assert_return (invoke "load8_u" (i32.const 65534)) (i32.const 19)) +(assert_return (invoke "load8_u" (i32.const 65535)) (i32.const 20)) + +(module + (memory (export "mem") 1 1 ) + (data (i32.const 65486) "\00\01\02\03\04\05\06\07\08\09\0a\0b\0c\0d\0e\0f\10\11\12\13") + (func (export "run") (param $targetOffs i32) (param $srcOffs i32) (param $len i32) + (memory.copy (local.get $targetOffs) (local.get $srcOffs) (local.get $len))) + (func (export "load8_u") (param i32) (result i32) + (i32.load8_u (local.get 0)))) + +(assert_trap (invoke "run" (i32.const 65516) (i32.const 65486) (i32.const 40)) + "out of bounds") + +(assert_return (invoke "load8_u" (i32.const 198)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 397)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 596)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 795)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 994)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 1193)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 1392)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 1591)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 1790)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 1989)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 2188)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 2387)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 2586)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 2785)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 2984)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 3183)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 3382)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 3581)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 3780)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 3979)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 4178)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 4377)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 4576)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 4775)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 4974)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 5173)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 5372)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 5571)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 5770)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 5969)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 6168)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 6367)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 6566)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 6765)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 6964)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 7163)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 7362)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 7561)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 7760)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 7959)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 8158)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 8357)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 8556)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 8755)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 8954)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 9153)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 9352)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 9551)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 9750)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 9949)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 10148)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 10347)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 10546)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 10745)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 10944)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 11143)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 11342)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 11541)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 11740)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 11939)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 12138)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 12337)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 12536)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 12735)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 12934)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 13133)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 13332)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 13531)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 13730)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 13929)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 14128)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 14327)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 14526)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 14725)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 14924)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 15123)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 15322)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 15521)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 15720)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 15919)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 16118)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 16317)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 16516)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 16715)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 16914)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 17113)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 17312)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 17511)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 17710)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 17909)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 18108)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 18307)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 18506)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 18705)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 18904)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 19103)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 19302)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 19501)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 19700)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 19899)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 20098)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 20297)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 20496)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 20695)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 20894)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 21093)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 21292)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 21491)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 21690)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 21889)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 22088)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 22287)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 22486)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 22685)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 22884)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 23083)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 23282)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 23481)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 23680)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 23879)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 24078)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 24277)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 24476)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 24675)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 24874)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 25073)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 25272)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 25471)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 25670)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 25869)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 26068)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 26267)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 26466)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 26665)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 26864)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 27063)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 27262)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 27461)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 27660)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 27859)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 28058)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 28257)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 28456)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 28655)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 28854)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 29053)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 29252)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 29451)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 29650)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 29849)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 30048)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 30247)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 30446)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 30645)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 30844)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 31043)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 31242)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 31441)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 31640)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 31839)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 32038)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 32237)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 32436)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 32635)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 32834)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 33033)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 33232)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 33431)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 33630)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 33829)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 34028)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 34227)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 34426)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 34625)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 34824)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 35023)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 35222)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 35421)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 35620)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 35819)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 36018)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 36217)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 36416)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 36615)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 36814)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 37013)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 37212)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 37411)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 37610)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 37809)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 38008)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 38207)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 38406)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 38605)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 38804)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 39003)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 39202)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 39401)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 39600)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 39799)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 39998)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 40197)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 40396)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 40595)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 40794)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 40993)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 41192)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 41391)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 41590)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 41789)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 41988)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 42187)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 42386)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 42585)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 42784)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 42983)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 43182)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 43381)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 43580)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 43779)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 43978)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 44177)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 44376)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 44575)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 44774)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 44973)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 45172)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 45371)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 45570)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 45769)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 45968)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 46167)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 46366)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 46565)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 46764)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 46963)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 47162)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 47361)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 47560)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 47759)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 47958)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 48157)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 48356)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 48555)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 48754)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 48953)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 49152)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 49351)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 49550)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 49749)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 49948)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 50147)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 50346)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 50545)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 50744)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 50943)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 51142)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 51341)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 51540)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 51739)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 51938)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 52137)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 52336)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 52535)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 52734)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 52933)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 53132)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 53331)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 53530)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 53729)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 53928)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 54127)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 54326)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 54525)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 54724)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 54923)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 55122)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 55321)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 55520)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 55719)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 55918)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 56117)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 56316)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 56515)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 56714)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 56913)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 57112)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 57311)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 57510)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 57709)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 57908)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 58107)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 58306)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 58505)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 58704)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 58903)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 59102)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 59301)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 59500)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 59699)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 59898)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 60097)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 60296)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 60495)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 60694)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 60893)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 61092)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 61291)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 61490)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 61689)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 61888)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 62087)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 62286)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 62485)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 62684)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 62883)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 63082)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 63281)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 63480)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 63679)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 63878)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 64077)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 64276)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 64475)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 64674)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 64873)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 65072)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 65271)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 65470)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 65486)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 65487)) (i32.const 1)) +(assert_return (invoke "load8_u" (i32.const 65488)) (i32.const 2)) +(assert_return (invoke "load8_u" (i32.const 65489)) (i32.const 3)) +(assert_return (invoke "load8_u" (i32.const 65490)) (i32.const 4)) +(assert_return (invoke "load8_u" (i32.const 65491)) (i32.const 5)) +(assert_return (invoke "load8_u" (i32.const 65492)) (i32.const 6)) +(assert_return (invoke "load8_u" (i32.const 65493)) (i32.const 7)) +(assert_return (invoke "load8_u" (i32.const 65494)) (i32.const 8)) +(assert_return (invoke "load8_u" (i32.const 65495)) (i32.const 9)) +(assert_return (invoke "load8_u" (i32.const 65496)) (i32.const 10)) +(assert_return (invoke "load8_u" (i32.const 65497)) (i32.const 11)) +(assert_return (invoke "load8_u" (i32.const 65498)) (i32.const 12)) +(assert_return (invoke "load8_u" (i32.const 65499)) (i32.const 13)) +(assert_return (invoke "load8_u" (i32.const 65500)) (i32.const 14)) +(assert_return (invoke "load8_u" (i32.const 65501)) (i32.const 15)) +(assert_return (invoke "load8_u" (i32.const 65502)) (i32.const 16)) +(assert_return (invoke "load8_u" (i32.const 65503)) (i32.const 17)) +(assert_return (invoke "load8_u" (i32.const 65504)) (i32.const 18)) +(assert_return (invoke "load8_u" (i32.const 65505)) (i32.const 19)) + +(module + (memory (export "mem") 1 1 ) + (data (i32.const 65516) "\00\01\02\03\04\05\06\07\08\09\0a\0b\0c\0d\0e\0f\10\11\12\13") + (func (export "run") (param $targetOffs i32) (param $srcOffs i32) (param $len i32) + (memory.copy (local.get $targetOffs) (local.get $srcOffs) (local.get $len))) + (func (export "load8_u") (param i32) (result i32) + (i32.load8_u (local.get 0)))) + +(assert_trap (invoke "run" (i32.const 65486) (i32.const 65516) (i32.const 40)) + "out of bounds") + +(assert_return (invoke "load8_u" (i32.const 198)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 397)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 596)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 795)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 994)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 1193)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 1392)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 1591)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 1790)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 1989)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 2188)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 2387)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 2586)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 2785)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 2984)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 3183)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 3382)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 3581)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 3780)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 3979)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 4178)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 4377)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 4576)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 4775)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 4974)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 5173)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 5372)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 5571)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 5770)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 5969)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 6168)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 6367)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 6566)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 6765)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 6964)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 7163)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 7362)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 7561)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 7760)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 7959)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 8158)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 8357)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 8556)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 8755)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 8954)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 9153)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 9352)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 9551)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 9750)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 9949)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 10148)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 10347)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 10546)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 10745)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 10944)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 11143)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 11342)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 11541)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 11740)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 11939)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 12138)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 12337)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 12536)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 12735)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 12934)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 13133)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 13332)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 13531)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 13730)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 13929)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 14128)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 14327)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 14526)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 14725)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 14924)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 15123)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 15322)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 15521)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 15720)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 15919)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 16118)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 16317)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 16516)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 16715)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 16914)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 17113)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 17312)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 17511)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 17710)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 17909)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 18108)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 18307)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 18506)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 18705)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 18904)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 19103)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 19302)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 19501)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 19700)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 19899)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 20098)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 20297)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 20496)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 20695)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 20894)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 21093)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 21292)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 21491)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 21690)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 21889)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 22088)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 22287)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 22486)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 22685)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 22884)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 23083)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 23282)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 23481)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 23680)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 23879)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 24078)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 24277)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 24476)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 24675)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 24874)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 25073)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 25272)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 25471)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 25670)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 25869)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 26068)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 26267)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 26466)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 26665)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 26864)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 27063)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 27262)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 27461)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 27660)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 27859)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 28058)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 28257)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 28456)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 28655)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 28854)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 29053)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 29252)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 29451)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 29650)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 29849)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 30048)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 30247)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 30446)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 30645)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 30844)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 31043)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 31242)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 31441)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 31640)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 31839)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 32038)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 32237)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 32436)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 32635)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 32834)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 33033)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 33232)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 33431)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 33630)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 33829)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 34028)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 34227)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 34426)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 34625)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 34824)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 35023)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 35222)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 35421)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 35620)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 35819)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 36018)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 36217)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 36416)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 36615)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 36814)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 37013)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 37212)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 37411)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 37610)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 37809)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 38008)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 38207)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 38406)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 38605)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 38804)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 39003)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 39202)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 39401)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 39600)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 39799)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 39998)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 40197)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 40396)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 40595)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 40794)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 40993)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 41192)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 41391)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 41590)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 41789)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 41988)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 42187)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 42386)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 42585)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 42784)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 42983)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 43182)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 43381)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 43580)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 43779)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 43978)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 44177)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 44376)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 44575)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 44774)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 44973)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 45172)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 45371)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 45570)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 45769)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 45968)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 46167)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 46366)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 46565)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 46764)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 46963)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 47162)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 47361)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 47560)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 47759)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 47958)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 48157)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 48356)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 48555)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 48754)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 48953)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 49152)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 49351)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 49550)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 49749)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 49948)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 50147)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 50346)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 50545)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 50744)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 50943)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 51142)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 51341)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 51540)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 51739)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 51938)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 52137)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 52336)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 52535)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 52734)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 52933)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 53132)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 53331)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 53530)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 53729)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 53928)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 54127)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 54326)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 54525)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 54724)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 54923)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 55122)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 55321)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 55520)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 55719)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 55918)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 56117)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 56316)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 56515)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 56714)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 56913)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 57112)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 57311)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 57510)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 57709)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 57908)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 58107)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 58306)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 58505)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 58704)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 58903)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 59102)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 59301)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 59500)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 59699)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 59898)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 60097)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 60296)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 60495)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 60694)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 60893)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 61092)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 61291)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 61490)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 61689)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 61888)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 62087)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 62286)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 62485)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 62684)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 62883)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 63082)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 63281)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 63480)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 63679)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 63878)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 64077)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 64276)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 64475)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 64674)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 64873)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 65072)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 65271)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 65470)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 65516)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 65517)) (i32.const 1)) +(assert_return (invoke "load8_u" (i32.const 65518)) (i32.const 2)) +(assert_return (invoke "load8_u" (i32.const 65519)) (i32.const 3)) +(assert_return (invoke "load8_u" (i32.const 65520)) (i32.const 4)) +(assert_return (invoke "load8_u" (i32.const 65521)) (i32.const 5)) +(assert_return (invoke "load8_u" (i32.const 65522)) (i32.const 6)) +(assert_return (invoke "load8_u" (i32.const 65523)) (i32.const 7)) +(assert_return (invoke "load8_u" (i32.const 65524)) (i32.const 8)) +(assert_return (invoke "load8_u" (i32.const 65525)) (i32.const 9)) +(assert_return (invoke "load8_u" (i32.const 65526)) (i32.const 10)) +(assert_return (invoke "load8_u" (i32.const 65527)) (i32.const 11)) +(assert_return (invoke "load8_u" (i32.const 65528)) (i32.const 12)) +(assert_return (invoke "load8_u" (i32.const 65529)) (i32.const 13)) +(assert_return (invoke "load8_u" (i32.const 65530)) (i32.const 14)) +(assert_return (invoke "load8_u" (i32.const 65531)) (i32.const 15)) +(assert_return (invoke "load8_u" (i32.const 65532)) (i32.const 16)) +(assert_return (invoke "load8_u" (i32.const 65533)) (i32.const 17)) +(assert_return (invoke "load8_u" (i32.const 65534)) (i32.const 18)) +(assert_return (invoke "load8_u" (i32.const 65535)) (i32.const 19)) + +(module + (memory (export "mem") 1 1 ) + (data (i32.const 65506) "\00\01\02\03\04\05\06\07\08\09\0a\0b\0c\0d\0e\0f\10\11\12\13") + (func (export "run") (param $targetOffs i32) (param $srcOffs i32) (param $len i32) + (memory.copy (local.get $targetOffs) (local.get $srcOffs) (local.get $len))) + (func (export "load8_u") (param i32) (result i32) + (i32.load8_u (local.get 0)))) + +(assert_trap (invoke "run" (i32.const 65516) (i32.const 65506) (i32.const 40)) + "out of bounds") + +(assert_return (invoke "load8_u" (i32.const 198)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 397)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 596)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 795)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 994)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 1193)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 1392)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 1591)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 1790)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 1989)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 2188)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 2387)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 2586)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 2785)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 2984)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 3183)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 3382)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 3581)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 3780)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 3979)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 4178)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 4377)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 4576)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 4775)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 4974)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 5173)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 5372)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 5571)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 5770)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 5969)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 6168)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 6367)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 6566)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 6765)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 6964)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 7163)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 7362)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 7561)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 7760)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 7959)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 8158)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 8357)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 8556)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 8755)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 8954)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 9153)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 9352)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 9551)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 9750)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 9949)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 10148)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 10347)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 10546)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 10745)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 10944)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 11143)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 11342)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 11541)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 11740)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 11939)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 12138)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 12337)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 12536)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 12735)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 12934)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 13133)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 13332)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 13531)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 13730)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 13929)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 14128)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 14327)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 14526)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 14725)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 14924)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 15123)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 15322)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 15521)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 15720)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 15919)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 16118)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 16317)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 16516)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 16715)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 16914)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 17113)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 17312)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 17511)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 17710)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 17909)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 18108)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 18307)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 18506)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 18705)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 18904)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 19103)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 19302)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 19501)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 19700)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 19899)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 20098)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 20297)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 20496)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 20695)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 20894)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 21093)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 21292)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 21491)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 21690)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 21889)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 22088)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 22287)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 22486)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 22685)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 22884)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 23083)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 23282)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 23481)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 23680)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 23879)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 24078)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 24277)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 24476)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 24675)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 24874)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 25073)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 25272)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 25471)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 25670)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 25869)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 26068)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 26267)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 26466)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 26665)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 26864)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 27063)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 27262)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 27461)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 27660)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 27859)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 28058)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 28257)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 28456)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 28655)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 28854)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 29053)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 29252)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 29451)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 29650)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 29849)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 30048)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 30247)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 30446)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 30645)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 30844)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 31043)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 31242)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 31441)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 31640)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 31839)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 32038)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 32237)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 32436)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 32635)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 32834)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 33033)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 33232)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 33431)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 33630)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 33829)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 34028)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 34227)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 34426)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 34625)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 34824)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 35023)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 35222)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 35421)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 35620)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 35819)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 36018)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 36217)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 36416)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 36615)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 36814)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 37013)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 37212)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 37411)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 37610)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 37809)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 38008)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 38207)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 38406)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 38605)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 38804)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 39003)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 39202)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 39401)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 39600)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 39799)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 39998)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 40197)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 40396)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 40595)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 40794)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 40993)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 41192)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 41391)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 41590)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 41789)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 41988)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 42187)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 42386)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 42585)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 42784)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 42983)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 43182)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 43381)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 43580)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 43779)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 43978)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 44177)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 44376)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 44575)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 44774)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 44973)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 45172)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 45371)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 45570)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 45769)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 45968)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 46167)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 46366)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 46565)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 46764)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 46963)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 47162)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 47361)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 47560)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 47759)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 47958)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 48157)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 48356)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 48555)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 48754)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 48953)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 49152)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 49351)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 49550)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 49749)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 49948)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 50147)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 50346)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 50545)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 50744)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 50943)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 51142)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 51341)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 51540)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 51739)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 51938)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 52137)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 52336)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 52535)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 52734)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 52933)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 53132)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 53331)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 53530)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 53729)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 53928)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 54127)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 54326)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 54525)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 54724)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 54923)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 55122)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 55321)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 55520)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 55719)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 55918)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 56117)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 56316)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 56515)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 56714)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 56913)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 57112)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 57311)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 57510)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 57709)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 57908)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 58107)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 58306)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 58505)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 58704)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 58903)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 59102)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 59301)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 59500)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 59699)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 59898)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 60097)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 60296)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 60495)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 60694)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 60893)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 61092)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 61291)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 61490)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 61689)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 61888)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 62087)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 62286)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 62485)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 62684)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 62883)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 63082)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 63281)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 63480)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 63679)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 63878)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 64077)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 64276)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 64475)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 64674)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 64873)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 65072)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 65271)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 65470)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 65506)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 65507)) (i32.const 1)) +(assert_return (invoke "load8_u" (i32.const 65508)) (i32.const 2)) +(assert_return (invoke "load8_u" (i32.const 65509)) (i32.const 3)) +(assert_return (invoke "load8_u" (i32.const 65510)) (i32.const 4)) +(assert_return (invoke "load8_u" (i32.const 65511)) (i32.const 5)) +(assert_return (invoke "load8_u" (i32.const 65512)) (i32.const 6)) +(assert_return (invoke "load8_u" (i32.const 65513)) (i32.const 7)) +(assert_return (invoke "load8_u" (i32.const 65514)) (i32.const 8)) +(assert_return (invoke "load8_u" (i32.const 65515)) (i32.const 9)) +(assert_return (invoke "load8_u" (i32.const 65516)) (i32.const 10)) +(assert_return (invoke "load8_u" (i32.const 65517)) (i32.const 11)) +(assert_return (invoke "load8_u" (i32.const 65518)) (i32.const 12)) +(assert_return (invoke "load8_u" (i32.const 65519)) (i32.const 13)) +(assert_return (invoke "load8_u" (i32.const 65520)) (i32.const 14)) +(assert_return (invoke "load8_u" (i32.const 65521)) (i32.const 15)) +(assert_return (invoke "load8_u" (i32.const 65522)) (i32.const 16)) +(assert_return (invoke "load8_u" (i32.const 65523)) (i32.const 17)) +(assert_return (invoke "load8_u" (i32.const 65524)) (i32.const 18)) +(assert_return (invoke "load8_u" (i32.const 65525)) (i32.const 19)) + +(module + (memory (export "mem") 1 1 ) + (data (i32.const 65516) "\00\01\02\03\04\05\06\07\08\09\0a\0b\0c\0d\0e\0f\10\11\12\13") + (func (export "run") (param $targetOffs i32) (param $srcOffs i32) (param $len i32) + (memory.copy (local.get $targetOffs) (local.get $srcOffs) (local.get $len))) + (func (export "load8_u") (param i32) (result i32) + (i32.load8_u (local.get 0)))) + +(assert_trap (invoke "run" (i32.const 65506) (i32.const 65516) (i32.const 40)) + "out of bounds") + +(assert_return (invoke "load8_u" (i32.const 198)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 397)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 596)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 795)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 994)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 1193)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 1392)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 1591)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 1790)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 1989)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 2188)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 2387)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 2586)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 2785)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 2984)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 3183)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 3382)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 3581)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 3780)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 3979)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 4178)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 4377)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 4576)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 4775)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 4974)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 5173)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 5372)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 5571)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 5770)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 5969)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 6168)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 6367)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 6566)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 6765)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 6964)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 7163)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 7362)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 7561)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 7760)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 7959)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 8158)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 8357)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 8556)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 8755)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 8954)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 9153)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 9352)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 9551)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 9750)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 9949)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 10148)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 10347)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 10546)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 10745)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 10944)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 11143)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 11342)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 11541)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 11740)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 11939)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 12138)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 12337)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 12536)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 12735)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 12934)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 13133)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 13332)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 13531)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 13730)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 13929)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 14128)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 14327)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 14526)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 14725)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 14924)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 15123)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 15322)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 15521)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 15720)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 15919)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 16118)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 16317)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 16516)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 16715)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 16914)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 17113)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 17312)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 17511)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 17710)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 17909)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 18108)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 18307)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 18506)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 18705)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 18904)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 19103)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 19302)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 19501)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 19700)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 19899)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 20098)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 20297)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 20496)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 20695)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 20894)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 21093)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 21292)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 21491)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 21690)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 21889)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 22088)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 22287)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 22486)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 22685)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 22884)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 23083)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 23282)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 23481)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 23680)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 23879)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 24078)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 24277)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 24476)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 24675)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 24874)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 25073)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 25272)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 25471)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 25670)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 25869)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 26068)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 26267)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 26466)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 26665)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 26864)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 27063)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 27262)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 27461)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 27660)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 27859)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 28058)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 28257)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 28456)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 28655)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 28854)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 29053)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 29252)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 29451)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 29650)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 29849)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 30048)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 30247)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 30446)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 30645)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 30844)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 31043)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 31242)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 31441)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 31640)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 31839)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 32038)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 32237)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 32436)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 32635)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 32834)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 33033)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 33232)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 33431)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 33630)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 33829)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 34028)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 34227)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 34426)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 34625)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 34824)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 35023)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 35222)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 35421)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 35620)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 35819)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 36018)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 36217)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 36416)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 36615)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 36814)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 37013)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 37212)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 37411)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 37610)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 37809)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 38008)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 38207)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 38406)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 38605)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 38804)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 39003)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 39202)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 39401)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 39600)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 39799)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 39998)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 40197)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 40396)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 40595)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 40794)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 40993)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 41192)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 41391)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 41590)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 41789)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 41988)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 42187)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 42386)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 42585)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 42784)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 42983)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 43182)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 43381)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 43580)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 43779)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 43978)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 44177)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 44376)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 44575)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 44774)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 44973)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 45172)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 45371)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 45570)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 45769)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 45968)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 46167)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 46366)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 46565)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 46764)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 46963)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 47162)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 47361)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 47560)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 47759)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 47958)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 48157)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 48356)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 48555)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 48754)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 48953)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 49152)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 49351)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 49550)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 49749)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 49948)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 50147)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 50346)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 50545)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 50744)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 50943)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 51142)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 51341)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 51540)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 51739)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 51938)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 52137)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 52336)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 52535)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 52734)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 52933)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 53132)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 53331)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 53530)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 53729)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 53928)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 54127)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 54326)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 54525)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 54724)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 54923)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 55122)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 55321)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 55520)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 55719)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 55918)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 56117)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 56316)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 56515)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 56714)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 56913)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 57112)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 57311)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 57510)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 57709)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 57908)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 58107)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 58306)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 58505)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 58704)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 58903)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 59102)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 59301)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 59500)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 59699)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 59898)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 60097)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 60296)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 60495)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 60694)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 60893)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 61092)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 61291)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 61490)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 61689)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 61888)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 62087)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 62286)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 62485)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 62684)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 62883)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 63082)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 63281)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 63480)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 63679)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 63878)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 64077)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 64276)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 64475)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 64674)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 64873)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 65072)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 65271)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 65470)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 65516)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 65517)) (i32.const 1)) +(assert_return (invoke "load8_u" (i32.const 65518)) (i32.const 2)) +(assert_return (invoke "load8_u" (i32.const 65519)) (i32.const 3)) +(assert_return (invoke "load8_u" (i32.const 65520)) (i32.const 4)) +(assert_return (invoke "load8_u" (i32.const 65521)) (i32.const 5)) +(assert_return (invoke "load8_u" (i32.const 65522)) (i32.const 6)) +(assert_return (invoke "load8_u" (i32.const 65523)) (i32.const 7)) +(assert_return (invoke "load8_u" (i32.const 65524)) (i32.const 8)) +(assert_return (invoke "load8_u" (i32.const 65525)) (i32.const 9)) +(assert_return (invoke "load8_u" (i32.const 65526)) (i32.const 10)) +(assert_return (invoke "load8_u" (i32.const 65527)) (i32.const 11)) +(assert_return (invoke "load8_u" (i32.const 65528)) (i32.const 12)) +(assert_return (invoke "load8_u" (i32.const 65529)) (i32.const 13)) +(assert_return (invoke "load8_u" (i32.const 65530)) (i32.const 14)) +(assert_return (invoke "load8_u" (i32.const 65531)) (i32.const 15)) +(assert_return (invoke "load8_u" (i32.const 65532)) (i32.const 16)) +(assert_return (invoke "load8_u" (i32.const 65533)) (i32.const 17)) +(assert_return (invoke "load8_u" (i32.const 65534)) (i32.const 18)) +(assert_return (invoke "load8_u" (i32.const 65535)) (i32.const 19)) + +(module + (memory (export "mem") 1 1 ) + (data (i32.const 65516) "\00\01\02\03\04\05\06\07\08\09\0a\0b\0c\0d\0e\0f\10\11\12\13") + (func (export "run") (param $targetOffs i32) (param $srcOffs i32) (param $len i32) + (memory.copy (local.get $targetOffs) (local.get $srcOffs) (local.get $len))) + (func (export "load8_u") (param i32) (result i32) + (i32.load8_u (local.get 0)))) + +(assert_trap (invoke "run" (i32.const 65516) (i32.const 65516) (i32.const 40)) + "out of bounds") + +(assert_return (invoke "load8_u" (i32.const 198)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 397)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 596)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 795)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 994)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 1193)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 1392)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 1591)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 1790)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 1989)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 2188)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 2387)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 2586)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 2785)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 2984)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 3183)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 3382)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 3581)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 3780)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 3979)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 4178)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 4377)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 4576)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 4775)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 4974)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 5173)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 5372)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 5571)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 5770)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 5969)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 6168)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 6367)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 6566)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 6765)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 6964)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 7163)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 7362)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 7561)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 7760)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 7959)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 8158)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 8357)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 8556)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 8755)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 8954)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 9153)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 9352)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 9551)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 9750)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 9949)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 10148)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 10347)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 10546)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 10745)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 10944)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 11143)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 11342)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 11541)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 11740)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 11939)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 12138)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 12337)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 12536)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 12735)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 12934)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 13133)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 13332)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 13531)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 13730)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 13929)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 14128)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 14327)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 14526)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 14725)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 14924)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 15123)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 15322)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 15521)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 15720)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 15919)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 16118)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 16317)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 16516)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 16715)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 16914)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 17113)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 17312)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 17511)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 17710)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 17909)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 18108)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 18307)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 18506)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 18705)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 18904)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 19103)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 19302)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 19501)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 19700)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 19899)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 20098)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 20297)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 20496)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 20695)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 20894)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 21093)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 21292)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 21491)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 21690)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 21889)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 22088)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 22287)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 22486)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 22685)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 22884)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 23083)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 23282)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 23481)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 23680)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 23879)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 24078)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 24277)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 24476)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 24675)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 24874)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 25073)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 25272)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 25471)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 25670)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 25869)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 26068)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 26267)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 26466)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 26665)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 26864)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 27063)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 27262)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 27461)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 27660)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 27859)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 28058)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 28257)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 28456)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 28655)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 28854)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 29053)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 29252)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 29451)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 29650)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 29849)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 30048)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 30247)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 30446)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 30645)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 30844)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 31043)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 31242)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 31441)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 31640)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 31839)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 32038)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 32237)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 32436)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 32635)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 32834)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 33033)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 33232)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 33431)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 33630)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 33829)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 34028)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 34227)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 34426)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 34625)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 34824)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 35023)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 35222)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 35421)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 35620)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 35819)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 36018)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 36217)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 36416)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 36615)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 36814)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 37013)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 37212)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 37411)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 37610)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 37809)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 38008)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 38207)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 38406)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 38605)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 38804)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 39003)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 39202)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 39401)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 39600)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 39799)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 39998)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 40197)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 40396)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 40595)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 40794)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 40993)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 41192)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 41391)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 41590)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 41789)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 41988)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 42187)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 42386)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 42585)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 42784)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 42983)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 43182)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 43381)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 43580)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 43779)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 43978)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 44177)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 44376)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 44575)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 44774)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 44973)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 45172)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 45371)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 45570)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 45769)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 45968)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 46167)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 46366)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 46565)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 46764)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 46963)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 47162)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 47361)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 47560)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 47759)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 47958)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 48157)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 48356)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 48555)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 48754)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 48953)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 49152)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 49351)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 49550)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 49749)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 49948)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 50147)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 50346)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 50545)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 50744)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 50943)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 51142)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 51341)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 51540)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 51739)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 51938)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 52137)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 52336)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 52535)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 52734)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 52933)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 53132)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 53331)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 53530)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 53729)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 53928)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 54127)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 54326)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 54525)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 54724)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 54923)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 55122)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 55321)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 55520)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 55719)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 55918)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 56117)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 56316)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 56515)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 56714)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 56913)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 57112)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 57311)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 57510)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 57709)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 57908)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 58107)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 58306)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 58505)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 58704)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 58903)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 59102)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 59301)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 59500)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 59699)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 59898)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 60097)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 60296)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 60495)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 60694)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 60893)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 61092)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 61291)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 61490)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 61689)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 61888)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 62087)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 62286)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 62485)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 62684)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 62883)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 63082)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 63281)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 63480)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 63679)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 63878)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 64077)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 64276)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 64475)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 64674)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 64873)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 65072)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 65271)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 65470)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 65516)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 65517)) (i32.const 1)) +(assert_return (invoke "load8_u" (i32.const 65518)) (i32.const 2)) +(assert_return (invoke "load8_u" (i32.const 65519)) (i32.const 3)) +(assert_return (invoke "load8_u" (i32.const 65520)) (i32.const 4)) +(assert_return (invoke "load8_u" (i32.const 65521)) (i32.const 5)) +(assert_return (invoke "load8_u" (i32.const 65522)) (i32.const 6)) +(assert_return (invoke "load8_u" (i32.const 65523)) (i32.const 7)) +(assert_return (invoke "load8_u" (i32.const 65524)) (i32.const 8)) +(assert_return (invoke "load8_u" (i32.const 65525)) (i32.const 9)) +(assert_return (invoke "load8_u" (i32.const 65526)) (i32.const 10)) +(assert_return (invoke "load8_u" (i32.const 65527)) (i32.const 11)) +(assert_return (invoke "load8_u" (i32.const 65528)) (i32.const 12)) +(assert_return (invoke "load8_u" (i32.const 65529)) (i32.const 13)) +(assert_return (invoke "load8_u" (i32.const 65530)) (i32.const 14)) +(assert_return (invoke "load8_u" (i32.const 65531)) (i32.const 15)) +(assert_return (invoke "load8_u" (i32.const 65532)) (i32.const 16)) +(assert_return (invoke "load8_u" (i32.const 65533)) (i32.const 17)) +(assert_return (invoke "load8_u" (i32.const 65534)) (i32.const 18)) +(assert_return (invoke "load8_u" (i32.const 65535)) (i32.const 19)) + +(module + (memory (export "mem") 1 ) + (data (i32.const 65516) "\00\01\02\03\04\05\06\07\08\09\0a\0b\0c\0d\0e\0f\10\11\12\13") + (func (export "run") (param $targetOffs i32) (param $srcOffs i32) (param $len i32) + (memory.copy (local.get $targetOffs) (local.get $srcOffs) (local.get $len))) + (func (export "load8_u") (param i32) (result i32) + (i32.load8_u (local.get 0)))) + +(assert_trap (invoke "run" (i32.const 0) (i32.const 65516) (i32.const 4294963200)) + "out of bounds") + +(assert_return (invoke "load8_u" (i32.const 198)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 397)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 596)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 795)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 994)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 1193)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 1392)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 1591)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 1790)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 1989)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 2188)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 2387)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 2586)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 2785)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 2984)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 3183)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 3382)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 3581)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 3780)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 3979)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 4178)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 4377)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 4576)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 4775)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 4974)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 5173)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 5372)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 5571)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 5770)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 5969)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 6168)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 6367)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 6566)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 6765)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 6964)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 7163)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 7362)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 7561)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 7760)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 7959)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 8158)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 8357)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 8556)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 8755)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 8954)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 9153)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 9352)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 9551)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 9750)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 9949)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 10148)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 10347)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 10546)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 10745)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 10944)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 11143)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 11342)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 11541)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 11740)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 11939)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 12138)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 12337)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 12536)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 12735)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 12934)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 13133)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 13332)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 13531)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 13730)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 13929)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 14128)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 14327)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 14526)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 14725)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 14924)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 15123)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 15322)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 15521)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 15720)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 15919)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 16118)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 16317)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 16516)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 16715)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 16914)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 17113)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 17312)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 17511)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 17710)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 17909)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 18108)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 18307)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 18506)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 18705)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 18904)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 19103)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 19302)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 19501)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 19700)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 19899)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 20098)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 20297)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 20496)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 20695)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 20894)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 21093)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 21292)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 21491)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 21690)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 21889)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 22088)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 22287)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 22486)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 22685)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 22884)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 23083)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 23282)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 23481)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 23680)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 23879)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 24078)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 24277)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 24476)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 24675)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 24874)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 25073)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 25272)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 25471)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 25670)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 25869)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 26068)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 26267)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 26466)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 26665)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 26864)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 27063)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 27262)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 27461)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 27660)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 27859)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 28058)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 28257)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 28456)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 28655)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 28854)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 29053)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 29252)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 29451)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 29650)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 29849)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 30048)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 30247)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 30446)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 30645)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 30844)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 31043)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 31242)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 31441)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 31640)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 31839)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 32038)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 32237)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 32436)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 32635)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 32834)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 33033)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 33232)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 33431)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 33630)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 33829)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 34028)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 34227)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 34426)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 34625)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 34824)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 35023)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 35222)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 35421)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 35620)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 35819)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 36018)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 36217)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 36416)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 36615)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 36814)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 37013)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 37212)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 37411)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 37610)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 37809)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 38008)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 38207)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 38406)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 38605)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 38804)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 39003)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 39202)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 39401)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 39600)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 39799)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 39998)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 40197)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 40396)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 40595)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 40794)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 40993)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 41192)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 41391)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 41590)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 41789)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 41988)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 42187)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 42386)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 42585)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 42784)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 42983)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 43182)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 43381)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 43580)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 43779)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 43978)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 44177)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 44376)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 44575)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 44774)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 44973)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 45172)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 45371)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 45570)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 45769)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 45968)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 46167)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 46366)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 46565)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 46764)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 46963)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 47162)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 47361)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 47560)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 47759)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 47958)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 48157)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 48356)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 48555)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 48754)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 48953)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 49152)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 49351)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 49550)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 49749)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 49948)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 50147)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 50346)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 50545)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 50744)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 50943)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 51142)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 51341)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 51540)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 51739)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 51938)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 52137)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 52336)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 52535)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 52734)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 52933)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 53132)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 53331)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 53530)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 53729)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 53928)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 54127)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 54326)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 54525)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 54724)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 54923)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 55122)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 55321)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 55520)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 55719)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 55918)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 56117)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 56316)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 56515)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 56714)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 56913)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 57112)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 57311)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 57510)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 57709)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 57908)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 58107)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 58306)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 58505)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 58704)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 58903)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 59102)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 59301)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 59500)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 59699)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 59898)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 60097)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 60296)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 60495)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 60694)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 60893)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 61092)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 61291)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 61490)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 61689)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 61888)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 62087)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 62286)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 62485)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 62684)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 62883)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 63082)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 63281)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 63480)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 63679)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 63878)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 64077)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 64276)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 64475)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 64674)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 64873)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 65072)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 65271)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 65470)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 65516)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 65517)) (i32.const 1)) +(assert_return (invoke "load8_u" (i32.const 65518)) (i32.const 2)) +(assert_return (invoke "load8_u" (i32.const 65519)) (i32.const 3)) +(assert_return (invoke "load8_u" (i32.const 65520)) (i32.const 4)) +(assert_return (invoke "load8_u" (i32.const 65521)) (i32.const 5)) +(assert_return (invoke "load8_u" (i32.const 65522)) (i32.const 6)) +(assert_return (invoke "load8_u" (i32.const 65523)) (i32.const 7)) +(assert_return (invoke "load8_u" (i32.const 65524)) (i32.const 8)) +(assert_return (invoke "load8_u" (i32.const 65525)) (i32.const 9)) +(assert_return (invoke "load8_u" (i32.const 65526)) (i32.const 10)) +(assert_return (invoke "load8_u" (i32.const 65527)) (i32.const 11)) +(assert_return (invoke "load8_u" (i32.const 65528)) (i32.const 12)) +(assert_return (invoke "load8_u" (i32.const 65529)) (i32.const 13)) +(assert_return (invoke "load8_u" (i32.const 65530)) (i32.const 14)) +(assert_return (invoke "load8_u" (i32.const 65531)) (i32.const 15)) +(assert_return (invoke "load8_u" (i32.const 65532)) (i32.const 16)) +(assert_return (invoke "load8_u" (i32.const 65533)) (i32.const 17)) +(assert_return (invoke "load8_u" (i32.const 65534)) (i32.const 18)) +(assert_return (invoke "load8_u" (i32.const 65535)) (i32.const 19)) + +(module + (memory (export "mem") 1 1 ) + (data (i32.const 61440) "\00\01\02\03\04\05\06\07\08\09\0a\0b\0c\0d\0e\0f\10\11\12\13") + (func (export "run") (param $targetOffs i32) (param $srcOffs i32) (param $len i32) + (memory.copy (local.get $targetOffs) (local.get $srcOffs) (local.get $len))) + (func (export "load8_u") (param i32) (result i32) + (i32.load8_u (local.get 0)))) + +(assert_trap (invoke "run" (i32.const 65516) (i32.const 61440) (i32.const 4294967040)) + "out of bounds") + +(assert_return (invoke "load8_u" (i32.const 198)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 397)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 596)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 795)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 994)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 1193)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 1392)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 1591)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 1790)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 1989)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 2188)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 2387)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 2586)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 2785)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 2984)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 3183)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 3382)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 3581)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 3780)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 3979)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 4178)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 4377)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 4576)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 4775)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 4974)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 5173)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 5372)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 5571)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 5770)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 5969)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 6168)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 6367)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 6566)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 6765)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 6964)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 7163)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 7362)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 7561)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 7760)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 7959)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 8158)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 8357)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 8556)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 8755)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 8954)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 9153)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 9352)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 9551)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 9750)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 9949)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 10148)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 10347)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 10546)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 10745)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 10944)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 11143)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 11342)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 11541)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 11740)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 11939)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 12138)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 12337)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 12536)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 12735)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 12934)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 13133)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 13332)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 13531)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 13730)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 13929)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 14128)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 14327)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 14526)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 14725)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 14924)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 15123)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 15322)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 15521)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 15720)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 15919)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 16118)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 16317)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 16516)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 16715)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 16914)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 17113)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 17312)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 17511)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 17710)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 17909)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 18108)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 18307)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 18506)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 18705)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 18904)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 19103)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 19302)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 19501)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 19700)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 19899)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 20098)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 20297)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 20496)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 20695)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 20894)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 21093)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 21292)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 21491)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 21690)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 21889)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 22088)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 22287)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 22486)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 22685)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 22884)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 23083)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 23282)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 23481)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 23680)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 23879)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 24078)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 24277)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 24476)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 24675)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 24874)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 25073)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 25272)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 25471)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 25670)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 25869)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 26068)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 26267)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 26466)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 26665)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 26864)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 27063)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 27262)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 27461)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 27660)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 27859)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 28058)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 28257)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 28456)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 28655)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 28854)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 29053)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 29252)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 29451)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 29650)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 29849)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 30048)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 30247)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 30446)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 30645)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 30844)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 31043)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 31242)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 31441)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 31640)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 31839)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 32038)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 32237)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 32436)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 32635)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 32834)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 33033)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 33232)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 33431)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 33630)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 33829)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 34028)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 34227)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 34426)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 34625)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 34824)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 35023)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 35222)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 35421)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 35620)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 35819)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 36018)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 36217)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 36416)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 36615)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 36814)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 37013)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 37212)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 37411)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 37610)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 37809)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 38008)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 38207)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 38406)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 38605)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 38804)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 39003)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 39202)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 39401)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 39600)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 39799)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 39998)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 40197)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 40396)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 40595)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 40794)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 40993)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 41192)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 41391)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 41590)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 41789)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 41988)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 42187)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 42386)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 42585)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 42784)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 42983)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 43182)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 43381)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 43580)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 43779)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 43978)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 44177)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 44376)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 44575)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 44774)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 44973)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 45172)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 45371)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 45570)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 45769)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 45968)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 46167)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 46366)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 46565)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 46764)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 46963)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 47162)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 47361)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 47560)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 47759)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 47958)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 48157)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 48356)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 48555)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 48754)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 48953)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 49152)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 49351)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 49550)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 49749)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 49948)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 50147)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 50346)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 50545)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 50744)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 50943)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 51142)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 51341)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 51540)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 51739)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 51938)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 52137)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 52336)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 52535)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 52734)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 52933)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 53132)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 53331)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 53530)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 53729)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 53928)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 54127)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 54326)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 54525)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 54724)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 54923)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 55122)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 55321)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 55520)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 55719)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 55918)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 56117)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 56316)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 56515)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 56714)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 56913)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 57112)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 57311)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 57510)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 57709)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 57908)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 58107)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 58306)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 58505)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 58704)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 58903)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 59102)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 59301)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 59500)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 59699)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 59898)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 60097)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 60296)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 60495)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 60694)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 60893)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 61092)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 61291)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 61440)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 61441)) (i32.const 1)) +(assert_return (invoke "load8_u" (i32.const 61442)) (i32.const 2)) +(assert_return (invoke "load8_u" (i32.const 61443)) (i32.const 3)) +(assert_return (invoke "load8_u" (i32.const 61444)) (i32.const 4)) +(assert_return (invoke "load8_u" (i32.const 61445)) (i32.const 5)) +(assert_return (invoke "load8_u" (i32.const 61446)) (i32.const 6)) +(assert_return (invoke "load8_u" (i32.const 61447)) (i32.const 7)) +(assert_return (invoke "load8_u" (i32.const 61448)) (i32.const 8)) +(assert_return (invoke "load8_u" (i32.const 61449)) (i32.const 9)) +(assert_return (invoke "load8_u" (i32.const 61450)) (i32.const 10)) +(assert_return (invoke "load8_u" (i32.const 61451)) (i32.const 11)) +(assert_return (invoke "load8_u" (i32.const 61452)) (i32.const 12)) +(assert_return (invoke "load8_u" (i32.const 61453)) (i32.const 13)) +(assert_return (invoke "load8_u" (i32.const 61454)) (i32.const 14)) +(assert_return (invoke "load8_u" (i32.const 61455)) (i32.const 15)) +(assert_return (invoke "load8_u" (i32.const 61456)) (i32.const 16)) +(assert_return (invoke "load8_u" (i32.const 61457)) (i32.const 17)) +(assert_return (invoke "load8_u" (i32.const 61458)) (i32.const 18)) +(assert_return (invoke "load8_u" (i32.const 61459)) (i32.const 19)) +(assert_return (invoke "load8_u" (i32.const 61510)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 61709)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 61908)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 62107)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 62306)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 62505)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 62704)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 62903)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 63102)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 63301)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 63500)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 63699)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 63898)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 64097)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 64296)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 64495)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 64694)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 64893)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 65092)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 65291)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 65490)) (i32.const 0)) + +(assert_invalid + (module + (func (export "testfn") + (memory.copy (i32.const 10) (i32.const 20) (i32.const 30)))) + "unknown memory 0") + +(assert_invalid + (module + (memory 1 1) + (func (export "testfn") + (memory.copy (i32.const 10) (i32.const 20) (f32.const 30)))) + "type mismatch") + +(assert_invalid + (module + (memory 1 1) + (func (export "testfn") + (memory.copy (i32.const 10) (i32.const 20) (i64.const 30)))) + "type mismatch") + +(assert_invalid + (module + (memory 1 1) + (func (export "testfn") + (memory.copy (i32.const 10) (i32.const 20) (f64.const 30)))) + "type mismatch") + +(assert_invalid + (module + (memory 1 1) + (func (export "testfn") + (memory.copy (i32.const 10) (f32.const 20) (i32.const 30)))) + "type mismatch") + +(assert_invalid + (module + (memory 1 1) + (func (export "testfn") + (memory.copy (i32.const 10) (f32.const 20) (f32.const 30)))) + "type mismatch") + +(assert_invalid + (module + (memory 1 1) + (func (export "testfn") + (memory.copy (i32.const 10) (f32.const 20) (i64.const 30)))) + "type mismatch") + +(assert_invalid + (module + (memory 1 1) + (func (export "testfn") + (memory.copy (i32.const 10) (f32.const 20) (f64.const 30)))) + "type mismatch") + +(assert_invalid + (module + (memory 1 1) + (func (export "testfn") + (memory.copy (i32.const 10) (i64.const 20) (i32.const 30)))) + "type mismatch") + +(assert_invalid + (module + (memory 1 1) + (func (export "testfn") + (memory.copy (i32.const 10) (i64.const 20) (f32.const 30)))) + "type mismatch") + +(assert_invalid + (module + (memory 1 1) + (func (export "testfn") + (memory.copy (i32.const 10) (i64.const 20) (i64.const 30)))) + "type mismatch") + +(assert_invalid + (module + (memory 1 1) + (func (export "testfn") + (memory.copy (i32.const 10) (i64.const 20) (f64.const 30)))) + "type mismatch") + +(assert_invalid + (module + (memory 1 1) + (func (export "testfn") + (memory.copy (i32.const 10) (f64.const 20) (i32.const 30)))) + "type mismatch") + +(assert_invalid + (module + (memory 1 1) + (func (export "testfn") + (memory.copy (i32.const 10) (f64.const 20) (f32.const 30)))) + "type mismatch") + +(assert_invalid + (module + (memory 1 1) + (func (export "testfn") + (memory.copy (i32.const 10) (f64.const 20) (i64.const 30)))) + "type mismatch") + +(assert_invalid + (module + (memory 1 1) + (func (export "testfn") + (memory.copy (i32.const 10) (f64.const 20) (f64.const 30)))) + "type mismatch") + +(assert_invalid + (module + (memory 1 1) + (func (export "testfn") + (memory.copy (f32.const 10) (i32.const 20) (i32.const 30)))) + "type mismatch") + +(assert_invalid + (module + (memory 1 1) + (func (export "testfn") + (memory.copy (f32.const 10) (i32.const 20) (f32.const 30)))) + "type mismatch") + +(assert_invalid + (module + (memory 1 1) + (func (export "testfn") + (memory.copy (f32.const 10) (i32.const 20) (i64.const 30)))) + "type mismatch") + +(assert_invalid + (module + (memory 1 1) + (func (export "testfn") + (memory.copy (f32.const 10) (i32.const 20) (f64.const 30)))) + "type mismatch") + +(assert_invalid + (module + (memory 1 1) + (func (export "testfn") + (memory.copy (f32.const 10) (f32.const 20) (i32.const 30)))) + "type mismatch") + +(assert_invalid + (module + (memory 1 1) + (func (export "testfn") + (memory.copy (f32.const 10) (f32.const 20) (f32.const 30)))) + "type mismatch") + +(assert_invalid + (module + (memory 1 1) + (func (export "testfn") + (memory.copy (f32.const 10) (f32.const 20) (i64.const 30)))) + "type mismatch") + +(assert_invalid + (module + (memory 1 1) + (func (export "testfn") + (memory.copy (f32.const 10) (f32.const 20) (f64.const 30)))) + "type mismatch") + +(assert_invalid + (module + (memory 1 1) + (func (export "testfn") + (memory.copy (f32.const 10) (i64.const 20) (i32.const 30)))) + "type mismatch") + +(assert_invalid + (module + (memory 1 1) + (func (export "testfn") + (memory.copy (f32.const 10) (i64.const 20) (f32.const 30)))) + "type mismatch") + +(assert_invalid + (module + (memory 1 1) + (func (export "testfn") + (memory.copy (f32.const 10) (i64.const 20) (i64.const 30)))) + "type mismatch") + +(assert_invalid + (module + (memory 1 1) + (func (export "testfn") + (memory.copy (f32.const 10) (i64.const 20) (f64.const 30)))) + "type mismatch") + +(assert_invalid + (module + (memory 1 1) + (func (export "testfn") + (memory.copy (f32.const 10) (f64.const 20) (i32.const 30)))) + "type mismatch") + +(assert_invalid + (module + (memory 1 1) + (func (export "testfn") + (memory.copy (f32.const 10) (f64.const 20) (f32.const 30)))) + "type mismatch") + +(assert_invalid + (module + (memory 1 1) + (func (export "testfn") + (memory.copy (f32.const 10) (f64.const 20) (i64.const 30)))) + "type mismatch") + +(assert_invalid + (module + (memory 1 1) + (func (export "testfn") + (memory.copy (f32.const 10) (f64.const 20) (f64.const 30)))) + "type mismatch") + +(assert_invalid + (module + (memory 1 1) + (func (export "testfn") + (memory.copy (i64.const 10) (i32.const 20) (i32.const 30)))) + "type mismatch") + +(assert_invalid + (module + (memory 1 1) + (func (export "testfn") + (memory.copy (i64.const 10) (i32.const 20) (f32.const 30)))) + "type mismatch") + +(assert_invalid + (module + (memory 1 1) + (func (export "testfn") + (memory.copy (i64.const 10) (i32.const 20) (i64.const 30)))) + "type mismatch") + +(assert_invalid + (module + (memory 1 1) + (func (export "testfn") + (memory.copy (i64.const 10) (i32.const 20) (f64.const 30)))) + "type mismatch") + +(assert_invalid + (module + (memory 1 1) + (func (export "testfn") + (memory.copy (i64.const 10) (f32.const 20) (i32.const 30)))) + "type mismatch") + +(assert_invalid + (module + (memory 1 1) + (func (export "testfn") + (memory.copy (i64.const 10) (f32.const 20) (f32.const 30)))) + "type mismatch") + +(assert_invalid + (module + (memory 1 1) + (func (export "testfn") + (memory.copy (i64.const 10) (f32.const 20) (i64.const 30)))) + "type mismatch") + +(assert_invalid + (module + (memory 1 1) + (func (export "testfn") + (memory.copy (i64.const 10) (f32.const 20) (f64.const 30)))) + "type mismatch") + +(assert_invalid + (module + (memory 1 1) + (func (export "testfn") + (memory.copy (i64.const 10) (i64.const 20) (i32.const 30)))) + "type mismatch") + +(assert_invalid + (module + (memory 1 1) + (func (export "testfn") + (memory.copy (i64.const 10) (i64.const 20) (f32.const 30)))) + "type mismatch") + +(assert_invalid + (module + (memory 1 1) + (func (export "testfn") + (memory.copy (i64.const 10) (i64.const 20) (i64.const 30)))) + "type mismatch") + +(assert_invalid + (module + (memory 1 1) + (func (export "testfn") + (memory.copy (i64.const 10) (i64.const 20) (f64.const 30)))) + "type mismatch") + +(assert_invalid + (module + (memory 1 1) + (func (export "testfn") + (memory.copy (i64.const 10) (f64.const 20) (i32.const 30)))) + "type mismatch") + +(assert_invalid + (module + (memory 1 1) + (func (export "testfn") + (memory.copy (i64.const 10) (f64.const 20) (f32.const 30)))) + "type mismatch") + +(assert_invalid + (module + (memory 1 1) + (func (export "testfn") + (memory.copy (i64.const 10) (f64.const 20) (i64.const 30)))) + "type mismatch") + +(assert_invalid + (module + (memory 1 1) + (func (export "testfn") + (memory.copy (i64.const 10) (f64.const 20) (f64.const 30)))) + "type mismatch") + +(assert_invalid + (module + (memory 1 1) + (func (export "testfn") + (memory.copy (f64.const 10) (i32.const 20) (i32.const 30)))) + "type mismatch") + +(assert_invalid + (module + (memory 1 1) + (func (export "testfn") + (memory.copy (f64.const 10) (i32.const 20) (f32.const 30)))) + "type mismatch") + +(assert_invalid + (module + (memory 1 1) + (func (export "testfn") + (memory.copy (f64.const 10) (i32.const 20) (i64.const 30)))) + "type mismatch") + +(assert_invalid + (module + (memory 1 1) + (func (export "testfn") + (memory.copy (f64.const 10) (i32.const 20) (f64.const 30)))) + "type mismatch") + +(assert_invalid + (module + (memory 1 1) + (func (export "testfn") + (memory.copy (f64.const 10) (f32.const 20) (i32.const 30)))) + "type mismatch") + +(assert_invalid + (module + (memory 1 1) + (func (export "testfn") + (memory.copy (f64.const 10) (f32.const 20) (f32.const 30)))) + "type mismatch") + +(assert_invalid + (module + (memory 1 1) + (func (export "testfn") + (memory.copy (f64.const 10) (f32.const 20) (i64.const 30)))) + "type mismatch") + +(assert_invalid + (module + (memory 1 1) + (func (export "testfn") + (memory.copy (f64.const 10) (f32.const 20) (f64.const 30)))) + "type mismatch") + +(assert_invalid + (module + (memory 1 1) + (func (export "testfn") + (memory.copy (f64.const 10) (i64.const 20) (i32.const 30)))) + "type mismatch") + +(assert_invalid + (module + (memory 1 1) + (func (export "testfn") + (memory.copy (f64.const 10) (i64.const 20) (f32.const 30)))) + "type mismatch") + +(assert_invalid + (module + (memory 1 1) + (func (export "testfn") + (memory.copy (f64.const 10) (i64.const 20) (i64.const 30)))) + "type mismatch") + +(assert_invalid + (module + (memory 1 1) + (func (export "testfn") + (memory.copy (f64.const 10) (i64.const 20) (f64.const 30)))) + "type mismatch") + +(assert_invalid + (module + (memory 1 1) + (func (export "testfn") + (memory.copy (f64.const 10) (f64.const 20) (i32.const 30)))) + "type mismatch") + +(assert_invalid + (module + (memory 1 1) + (func (export "testfn") + (memory.copy (f64.const 10) (f64.const 20) (f32.const 30)))) + "type mismatch") + +(assert_invalid + (module + (memory 1 1) + (func (export "testfn") + (memory.copy (f64.const 10) (f64.const 20) (i64.const 30)))) + "type mismatch") + +(assert_invalid + (module + (memory 1 1) + (func (export "testfn") + (memory.copy (f64.const 10) (f64.const 20) (f64.const 30)))) + "type mismatch") + + +(module + (memory 1 1) + (func (export "test") + (memory.fill (i32.const 10) (i32.const 0x55) (i32.const 10)) + (memory.copy (i32.const 9) (i32.const 10) (i32.const 5))) + + (func (export "checkRange") (param $from i32) (param $to i32) (param $expected i32) (result i32) + (loop $cont + (if (i32.eq (local.get $from) (local.get $to)) + (then + (return (i32.const -1)))) + (if (i32.eq (i32.load8_u (local.get $from)) (local.get $expected)) + (then + (local.set $from (i32.add (local.get $from) (i32.const 1))) + (br $cont)))) + (return (local.get $from))) +) +(invoke "test") + +(assert_return (invoke "checkRange" (i32.const 0) (i32.const 9) (i32.const 0)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 9) (i32.const 20) (i32.const 85)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 20) (i32.const 65536) (i32.const 0)) + (i32.const -1)) + +(module + (memory 1 1) + (func (export "test") + (memory.fill (i32.const 10) (i32.const 0x55) (i32.const 10)) + (memory.copy (i32.const 16) (i32.const 15) (i32.const 5))) + + (func (export "checkRange") (param $from i32) (param $to i32) (param $expected i32) (result i32) + (loop $cont + (if (i32.eq (local.get $from) (local.get $to)) + (then + (return (i32.const -1)))) + (if (i32.eq (i32.load8_u (local.get $from)) (local.get $expected)) + (then + (local.set $from (i32.add (local.get $from) (i32.const 1))) + (br $cont)))) + (return (local.get $from))) +) +(invoke "test") + +(assert_return (invoke "checkRange" (i32.const 0) (i32.const 10) (i32.const 0)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 10) (i32.const 21) (i32.const 85)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 21) (i32.const 65536) (i32.const 0)) + (i32.const -1)) + +(module + (memory 1 1) + (func (export "test") + (memory.copy (i32.const 0xFF00) (i32.const 0x8000) (i32.const 257)))) +(assert_trap (invoke "test") "out of bounds") + +(module + (memory 1 1) + (func (export "test") + (memory.copy (i32.const 0xFFFFFF00) (i32.const 0x4000) (i32.const 257)))) +(assert_trap (invoke "test") "out of bounds") + +(module + (memory 1 1) + (func (export "test") + (memory.copy (i32.const 0x8000) (i32.const 0xFF00) (i32.const 257)))) +(assert_trap (invoke "test") "out of bounds") + +(module + (memory 1 1) + (func (export "test") + (memory.copy (i32.const 0x4000) (i32.const 0xFFFFFF00) (i32.const 257)))) +(assert_trap (invoke "test") "out of bounds") + +(module + (memory 1 1) + (func (export "test") + (memory.fill (i32.const 0x0000) (i32.const 0x55) (i32.const 0x8000)) + (memory.fill (i32.const 0x8000) (i32.const 0xAA) (i32.const 0x8000)) + (memory.copy (i32.const 0x9000) (i32.const 0x7000) (i32.const 0))) + + (func (export "checkRange") (param $from i32) (param $to i32) (param $expected i32) (result i32) + (loop $cont + (if (i32.eq (local.get $from) (local.get $to)) + (then + (return (i32.const -1)))) + (if (i32.eq (i32.load8_u (local.get $from)) (local.get $expected)) + (then + (local.set $from (i32.add (local.get $from) (i32.const 1))) + (br $cont)))) + (return (local.get $from))) +) +(invoke "test") + +(assert_return (invoke "checkRange" (i32.const 0) (i32.const 32768) (i32.const 85)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 32768) (i32.const 65536) (i32.const 170)) + (i32.const -1)) +(module + (memory 1 1) + (func (export "test") + (memory.copy (i32.const 0x10000) (i32.const 0x7000) (i32.const 0)))) +(invoke "test") + +(module + (memory 1 1) + (func (export "test") + (memory.copy (i32.const 0x20000) (i32.const 0x7000) (i32.const 0)))) +(assert_trap (invoke "test") "out of bounds") + +(module + (memory 1 1) + (func (export "test") + (memory.copy (i32.const 0x9000) (i32.const 0x10000) (i32.const 0)))) +(invoke "test") + +(module + (memory 1 1) + (func (export "test") + (memory.copy (i32.const 0x9000) (i32.const 0x20000) (i32.const 0)))) +(assert_trap (invoke "test") "out of bounds") + +(module + (memory 1 1) + (func (export "test") + (memory.copy (i32.const 0x10000) (i32.const 0x10000) (i32.const 0)))) +(invoke "test") + +(module + (memory 1 1) + (func (export "test") + (memory.copy (i32.const 0x20000) (i32.const 0x20000) (i32.const 0)))) +(assert_trap (invoke "test") "out of bounds") + +(module + (memory 1 1) + (func (export "test") + (memory.fill (i32.const 17767) (i32.const 1) (i32.const 1344)) + (memory.fill (i32.const 39017) (i32.const 2) (i32.const 1055)) + (memory.fill (i32.const 56401) (i32.const 3) (i32.const 988)) + (memory.fill (i32.const 37962) (i32.const 4) (i32.const 322)) + (memory.fill (i32.const 7977) (i32.const 5) (i32.const 1994)) + (memory.fill (i32.const 22714) (i32.const 6) (i32.const 3036)) + (memory.fill (i32.const 16882) (i32.const 7) (i32.const 2372)) + (memory.fill (i32.const 43491) (i32.const 8) (i32.const 835)) + (memory.fill (i32.const 124) (i32.const 9) (i32.const 1393)) + (memory.fill (i32.const 2132) (i32.const 10) (i32.const 2758)) + (memory.fill (i32.const 8987) (i32.const 11) (i32.const 3098)) + (memory.fill (i32.const 52711) (i32.const 12) (i32.const 741)) + (memory.fill (i32.const 3958) (i32.const 13) (i32.const 2823)) + (memory.fill (i32.const 49715) (i32.const 14) (i32.const 1280)) + (memory.fill (i32.const 50377) (i32.const 15) (i32.const 1466)) + (memory.fill (i32.const 20493) (i32.const 16) (i32.const 3158)) + (memory.fill (i32.const 47665) (i32.const 17) (i32.const 544)) + (memory.fill (i32.const 12451) (i32.const 18) (i32.const 2669)) + (memory.fill (i32.const 24869) (i32.const 19) (i32.const 2651)) + (memory.fill (i32.const 45317) (i32.const 20) (i32.const 1570)) + (memory.fill (i32.const 43096) (i32.const 21) (i32.const 1691)) + (memory.fill (i32.const 33886) (i32.const 22) (i32.const 646)) + (memory.fill (i32.const 48555) (i32.const 23) (i32.const 1858)) + (memory.fill (i32.const 53453) (i32.const 24) (i32.const 2657)) + (memory.fill (i32.const 30363) (i32.const 25) (i32.const 981)) + (memory.fill (i32.const 9300) (i32.const 26) (i32.const 1807)) + (memory.fill (i32.const 50190) (i32.const 27) (i32.const 487)) + (memory.fill (i32.const 62753) (i32.const 28) (i32.const 530)) + (memory.fill (i32.const 36316) (i32.const 29) (i32.const 943)) + (memory.fill (i32.const 6768) (i32.const 30) (i32.const 381)) + (memory.fill (i32.const 51262) (i32.const 31) (i32.const 3089)) + (memory.fill (i32.const 49729) (i32.const 32) (i32.const 658)) + (memory.fill (i32.const 44540) (i32.const 33) (i32.const 1702)) + (memory.fill (i32.const 33342) (i32.const 34) (i32.const 1092)) + (memory.fill (i32.const 50814) (i32.const 35) (i32.const 1410)) + (memory.fill (i32.const 47594) (i32.const 36) (i32.const 2204)) + (memory.fill (i32.const 54123) (i32.const 37) (i32.const 2394)) + (memory.fill (i32.const 55183) (i32.const 38) (i32.const 250)) + (memory.fill (i32.const 22620) (i32.const 39) (i32.const 2097)) + (memory.fill (i32.const 17132) (i32.const 40) (i32.const 3264)) + (memory.fill (i32.const 54331) (i32.const 41) (i32.const 3299)) + (memory.fill (i32.const 39474) (i32.const 42) (i32.const 2796)) + (memory.fill (i32.const 36156) (i32.const 43) (i32.const 2070)) + (memory.fill (i32.const 35308) (i32.const 44) (i32.const 2763)) + (memory.fill (i32.const 32731) (i32.const 45) (i32.const 312)) + (memory.fill (i32.const 63746) (i32.const 46) (i32.const 192)) + (memory.fill (i32.const 30974) (i32.const 47) (i32.const 596)) + (memory.fill (i32.const 16635) (i32.const 48) (i32.const 501)) + (memory.fill (i32.const 57002) (i32.const 49) (i32.const 686)) + (memory.fill (i32.const 34299) (i32.const 50) (i32.const 385)) + (memory.fill (i32.const 60881) (i32.const 51) (i32.const 903)) + (memory.fill (i32.const 61445) (i32.const 52) (i32.const 2390)) + (memory.fill (i32.const 46972) (i32.const 53) (i32.const 1441)) + (memory.fill (i32.const 25973) (i32.const 54) (i32.const 3162)) + (memory.fill (i32.const 5566) (i32.const 55) (i32.const 2135)) + (memory.fill (i32.const 35977) (i32.const 56) (i32.const 519)) + (memory.fill (i32.const 44892) (i32.const 57) (i32.const 3280)) + (memory.fill (i32.const 46760) (i32.const 58) (i32.const 1678)) + (memory.fill (i32.const 46607) (i32.const 59) (i32.const 3168)) + (memory.fill (i32.const 22449) (i32.const 60) (i32.const 1441)) + (memory.fill (i32.const 58609) (i32.const 61) (i32.const 663)) + (memory.fill (i32.const 32261) (i32.const 62) (i32.const 1671)) + (memory.fill (i32.const 3063) (i32.const 63) (i32.const 721)) + (memory.fill (i32.const 34025) (i32.const 64) (i32.const 84)) + (memory.fill (i32.const 33338) (i32.const 65) (i32.const 2029)) + (memory.fill (i32.const 36810) (i32.const 66) (i32.const 29)) + (memory.fill (i32.const 19147) (i32.const 67) (i32.const 3034)) + (memory.fill (i32.const 12616) (i32.const 68) (i32.const 1043)) + (memory.fill (i32.const 18276) (i32.const 69) (i32.const 3324)) + (memory.fill (i32.const 4639) (i32.const 70) (i32.const 1091)) + (memory.fill (i32.const 16158) (i32.const 71) (i32.const 1997)) + (memory.fill (i32.const 18204) (i32.const 72) (i32.const 2259)) + (memory.fill (i32.const 50532) (i32.const 73) (i32.const 3189)) + (memory.fill (i32.const 11028) (i32.const 74) (i32.const 1968)) + (memory.fill (i32.const 15962) (i32.const 75) (i32.const 1455)) + (memory.fill (i32.const 45406) (i32.const 76) (i32.const 1177)) + (memory.fill (i32.const 54137) (i32.const 77) (i32.const 1568)) + (memory.fill (i32.const 33083) (i32.const 78) (i32.const 1642)) + (memory.fill (i32.const 61028) (i32.const 79) (i32.const 3284)) + (memory.fill (i32.const 51729) (i32.const 80) (i32.const 223)) + (memory.fill (i32.const 4361) (i32.const 81) (i32.const 2171)) + (memory.fill (i32.const 57514) (i32.const 82) (i32.const 1322)) + (memory.fill (i32.const 55724) (i32.const 83) (i32.const 2648)) + (memory.fill (i32.const 24091) (i32.const 84) (i32.const 1045)) + (memory.fill (i32.const 43183) (i32.const 85) (i32.const 3097)) + (memory.fill (i32.const 32307) (i32.const 86) (i32.const 2796)) + (memory.fill (i32.const 3811) (i32.const 87) (i32.const 2010)) + (memory.fill (i32.const 54856) (i32.const 88) (i32.const 0)) + (memory.fill (i32.const 49941) (i32.const 89) (i32.const 2069)) + (memory.fill (i32.const 20411) (i32.const 90) (i32.const 2896)) + (memory.fill (i32.const 33826) (i32.const 91) (i32.const 192)) + (memory.fill (i32.const 9402) (i32.const 92) (i32.const 2195)) + (memory.fill (i32.const 12413) (i32.const 93) (i32.const 24)) + (memory.fill (i32.const 14091) (i32.const 94) (i32.const 577)) + (memory.fill (i32.const 44058) (i32.const 95) (i32.const 2089)) + (memory.fill (i32.const 36735) (i32.const 96) (i32.const 3436)) + (memory.fill (i32.const 23288) (i32.const 97) (i32.const 2765)) + (memory.fill (i32.const 6392) (i32.const 98) (i32.const 830)) + (memory.fill (i32.const 33307) (i32.const 99) (i32.const 1938)) + (memory.fill (i32.const 21941) (i32.const 100) (i32.const 2750)) + (memory.copy (i32.const 59214) (i32.const 54248) (i32.const 2098)) + (memory.copy (i32.const 63026) (i32.const 39224) (i32.const 230)) + (memory.copy (i32.const 51833) (i32.const 23629) (i32.const 2300)) + (memory.copy (i32.const 6708) (i32.const 23996) (i32.const 639)) + (memory.copy (i32.const 6990) (i32.const 33399) (i32.const 1097)) + (memory.copy (i32.const 19403) (i32.const 10348) (i32.const 3197)) + (memory.copy (i32.const 27308) (i32.const 54406) (i32.const 100)) + (memory.copy (i32.const 27221) (i32.const 43682) (i32.const 1717)) + (memory.copy (i32.const 60528) (i32.const 8629) (i32.const 119)) + (memory.copy (i32.const 5947) (i32.const 2308) (i32.const 658)) + (memory.copy (i32.const 4787) (i32.const 51631) (i32.const 2269)) + (memory.copy (i32.const 12617) (i32.const 19197) (i32.const 833)) + (memory.copy (i32.const 11854) (i32.const 46505) (i32.const 3300)) + (memory.copy (i32.const 11376) (i32.const 45012) (i32.const 2281)) + (memory.copy (i32.const 34186) (i32.const 6697) (i32.const 2572)) + (memory.copy (i32.const 4936) (i32.const 1690) (i32.const 1328)) + (memory.copy (i32.const 63164) (i32.const 7637) (i32.const 1670)) + (memory.copy (i32.const 44568) (i32.const 18344) (i32.const 33)) + (memory.copy (i32.const 43918) (i32.const 22348) (i32.const 1427)) + (memory.copy (i32.const 46637) (i32.const 49819) (i32.const 1434)) + (memory.copy (i32.const 63684) (i32.const 8755) (i32.const 834)) + (memory.copy (i32.const 33485) (i32.const 20131) (i32.const 3317)) + (memory.copy (i32.const 40575) (i32.const 54317) (i32.const 3201)) + (memory.copy (i32.const 25812) (i32.const 59254) (i32.const 2452)) + (memory.copy (i32.const 19678) (i32.const 56882) (i32.const 346)) + (memory.copy (i32.const 15852) (i32.const 35914) (i32.const 2430)) + (memory.copy (i32.const 11824) (i32.const 35574) (i32.const 300)) + (memory.copy (i32.const 59427) (i32.const 13957) (i32.const 3153)) + (memory.copy (i32.const 34299) (i32.const 60594) (i32.const 1281)) + (memory.copy (i32.const 8964) (i32.const 12276) (i32.const 943)) + (memory.copy (i32.const 2827) (i32.const 10425) (i32.const 1887)) + (memory.copy (i32.const 43194) (i32.const 43910) (i32.const 738)) + (memory.copy (i32.const 63038) (i32.const 18949) (i32.const 122)) + (memory.copy (i32.const 24044) (i32.const 44761) (i32.const 1755)) + (memory.copy (i32.const 22608) (i32.const 14755) (i32.const 702)) + (memory.copy (i32.const 11284) (i32.const 26579) (i32.const 1830)) + (memory.copy (i32.const 23092) (i32.const 20471) (i32.const 1064)) + (memory.copy (i32.const 57248) (i32.const 54770) (i32.const 2631)) + (memory.copy (i32.const 25492) (i32.const 1025) (i32.const 3113)) + (memory.copy (i32.const 49588) (i32.const 44220) (i32.const 975)) + (memory.copy (i32.const 28280) (i32.const 41722) (i32.const 2336)) + (memory.copy (i32.const 61289) (i32.const 230) (i32.const 2872)) + (memory.copy (i32.const 22480) (i32.const 52506) (i32.const 2197)) + (memory.copy (i32.const 40553) (i32.const 9578) (i32.const 1958)) + (memory.copy (i32.const 29004) (i32.const 20862) (i32.const 2186)) + (memory.copy (i32.const 53029) (i32.const 43955) (i32.const 1037)) + (memory.copy (i32.const 25476) (i32.const 35667) (i32.const 1650)) + (memory.copy (i32.const 58516) (i32.const 45819) (i32.const 1986)) + (memory.copy (i32.const 38297) (i32.const 5776) (i32.const 1955)) + (memory.copy (i32.const 28503) (i32.const 55364) (i32.const 2368)) + (memory.copy (i32.const 62619) (i32.const 18108) (i32.const 1356)) + (memory.copy (i32.const 50149) (i32.const 13861) (i32.const 382)) + (memory.copy (i32.const 16904) (i32.const 36341) (i32.const 1900)) + (memory.copy (i32.const 48098) (i32.const 11358) (i32.const 2807)) + (memory.copy (i32.const 28512) (i32.const 40362) (i32.const 323)) + (memory.copy (i32.const 35506) (i32.const 27856) (i32.const 1670)) + (memory.copy (i32.const 62970) (i32.const 53332) (i32.const 1341)) + (memory.copy (i32.const 14133) (i32.const 46312) (i32.const 644)) + (memory.copy (i32.const 29030) (i32.const 19074) (i32.const 496)) + (memory.copy (i32.const 44952) (i32.const 47577) (i32.const 2784)) + (memory.copy (i32.const 39559) (i32.const 44661) (i32.const 1350)) + (memory.copy (i32.const 10352) (i32.const 29274) (i32.const 1475)) + (memory.copy (i32.const 46911) (i32.const 46178) (i32.const 1467)) + (memory.copy (i32.const 4905) (i32.const 28740) (i32.const 1895)) + (memory.copy (i32.const 38012) (i32.const 57253) (i32.const 1751)) + (memory.copy (i32.const 26446) (i32.const 27223) (i32.const 1127)) + (memory.copy (i32.const 58835) (i32.const 24657) (i32.const 1063)) + (memory.copy (i32.const 61356) (i32.const 38790) (i32.const 766)) + (memory.copy (i32.const 44160) (i32.const 2284) (i32.const 1520)) + (memory.copy (i32.const 32740) (i32.const 47237) (i32.const 3014)) + (memory.copy (i32.const 11148) (i32.const 21260) (i32.const 1011)) + (memory.copy (i32.const 7665) (i32.const 31612) (i32.const 3034)) + (memory.copy (i32.const 18044) (i32.const 12987) (i32.const 3320)) + (memory.copy (i32.const 57306) (i32.const 55905) (i32.const 308)) + (memory.copy (i32.const 24675) (i32.const 16815) (i32.const 1155)) + (memory.copy (i32.const 19900) (i32.const 10115) (i32.const 722)) + (memory.copy (i32.const 2921) (i32.const 5935) (i32.const 2370)) + (memory.copy (i32.const 32255) (i32.const 50095) (i32.const 2926)) + (memory.copy (i32.const 15126) (i32.const 17299) (i32.const 2607)) + (memory.copy (i32.const 45575) (i32.const 28447) (i32.const 2045)) + (memory.copy (i32.const 55149) (i32.const 36113) (i32.const 2596)) + (memory.copy (i32.const 28461) (i32.const 54157) (i32.const 1168)) + (memory.copy (i32.const 47951) (i32.const 53385) (i32.const 3137)) + (memory.copy (i32.const 30646) (i32.const 45155) (i32.const 2649)) + (memory.copy (i32.const 5057) (i32.const 4295) (i32.const 52)) + (memory.copy (i32.const 6692) (i32.const 24195) (i32.const 441)) + (memory.copy (i32.const 32984) (i32.const 27117) (i32.const 3445)) + (memory.copy (i32.const 32530) (i32.const 59372) (i32.const 2785)) + (memory.copy (i32.const 34361) (i32.const 8962) (i32.const 2406)) + (memory.copy (i32.const 17893) (i32.const 54538) (i32.const 3381)) + (memory.copy (i32.const 22685) (i32.const 44151) (i32.const 136)) + (memory.copy (i32.const 59089) (i32.const 7077) (i32.const 1045)) + (memory.copy (i32.const 42945) (i32.const 55028) (i32.const 2389)) + (memory.copy (i32.const 44693) (i32.const 20138) (i32.const 877)) + (memory.copy (i32.const 36810) (i32.const 25196) (i32.const 3447)) + (memory.copy (i32.const 45742) (i32.const 31888) (i32.const 854)) + (memory.copy (i32.const 24236) (i32.const 31866) (i32.const 1377)) + (memory.copy (i32.const 33778) (i32.const 692) (i32.const 1594)) + (memory.copy (i32.const 60618) (i32.const 18585) (i32.const 2987)) + (memory.copy (i32.const 50370) (i32.const 41271) (i32.const 1406)) + ) + + (func (export "checkRange") (param $from i32) (param $to i32) (param $expected i32) (result i32) + (loop $cont + (if (i32.eq (local.get $from) (local.get $to)) + (then + (return (i32.const -1)))) + (if (i32.eq (i32.load8_u (local.get $from)) (local.get $expected)) + (then + (local.set $from (i32.add (local.get $from) (i32.const 1))) + (br $cont)))) + (return (local.get $from))) +) +(invoke "test") + +(assert_return (invoke "checkRange" (i32.const 0) (i32.const 124) (i32.const 0)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 124) (i32.const 1517) (i32.const 9)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 1517) (i32.const 2132) (i32.const 0)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 2132) (i32.const 2827) (i32.const 10)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 2827) (i32.const 2921) (i32.const 92)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 2921) (i32.const 3538) (i32.const 83)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 3538) (i32.const 3786) (i32.const 77)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 3786) (i32.const 4042) (i32.const 97)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 4042) (i32.const 4651) (i32.const 99)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 4651) (i32.const 5057) (i32.const 0)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 5057) (i32.const 5109) (i32.const 99)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 5109) (i32.const 5291) (i32.const 0)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 5291) (i32.const 5524) (i32.const 72)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 5524) (i32.const 5691) (i32.const 92)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 5691) (i32.const 6552) (i32.const 83)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 6552) (i32.const 7133) (i32.const 77)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 7133) (i32.const 7665) (i32.const 99)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 7665) (i32.const 8314) (i32.const 0)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 8314) (i32.const 8360) (i32.const 62)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 8360) (i32.const 8793) (i32.const 86)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 8793) (i32.const 8979) (i32.const 83)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 8979) (i32.const 9373) (i32.const 79)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 9373) (i32.const 9518) (i32.const 95)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 9518) (i32.const 9934) (i32.const 59)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 9934) (i32.const 10087) (i32.const 77)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 10087) (i32.const 10206) (i32.const 5)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 10206) (i32.const 10230) (i32.const 77)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 10230) (i32.const 10249) (i32.const 41)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 10249) (i32.const 11148) (i32.const 83)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 11148) (i32.const 11356) (i32.const 74)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 11356) (i32.const 11380) (i32.const 93)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 11380) (i32.const 11939) (i32.const 74)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 11939) (i32.const 12159) (i32.const 68)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 12159) (i32.const 12575) (i32.const 83)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 12575) (i32.const 12969) (i32.const 79)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 12969) (i32.const 13114) (i32.const 95)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 13114) (i32.const 14133) (i32.const 59)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 14133) (i32.const 14404) (i32.const 76)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 14404) (i32.const 14428) (i32.const 57)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 14428) (i32.const 14458) (i32.const 59)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 14458) (i32.const 14580) (i32.const 32)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 14580) (i32.const 14777) (i32.const 89)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 14777) (i32.const 15124) (i32.const 59)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 15124) (i32.const 15126) (i32.const 36)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 15126) (i32.const 15192) (i32.const 100)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 15192) (i32.const 15871) (i32.const 96)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 15871) (i32.const 15998) (i32.const 95)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 15998) (i32.const 17017) (i32.const 59)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 17017) (i32.const 17288) (i32.const 76)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 17288) (i32.const 17312) (i32.const 57)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 17312) (i32.const 17342) (i32.const 59)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 17342) (i32.const 17464) (i32.const 32)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 17464) (i32.const 17661) (i32.const 89)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 17661) (i32.const 17727) (i32.const 59)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 17727) (i32.const 17733) (i32.const 5)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 17733) (i32.const 17893) (i32.const 96)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 17893) (i32.const 18553) (i32.const 77)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 18553) (i32.const 18744) (i32.const 42)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 18744) (i32.const 18801) (i32.const 76)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 18801) (i32.const 18825) (i32.const 57)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 18825) (i32.const 18876) (i32.const 59)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 18876) (i32.const 18885) (i32.const 77)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 18885) (i32.const 18904) (i32.const 41)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 18904) (i32.const 19567) (i32.const 83)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 19567) (i32.const 20403) (i32.const 96)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 20403) (i32.const 21274) (i32.const 77)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 21274) (i32.const 21364) (i32.const 100)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 21364) (i32.const 21468) (i32.const 74)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 21468) (i32.const 21492) (i32.const 93)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 21492) (i32.const 22051) (i32.const 74)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 22051) (i32.const 22480) (i32.const 68)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 22480) (i32.const 22685) (i32.const 100)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 22685) (i32.const 22694) (i32.const 68)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 22694) (i32.const 22821) (i32.const 10)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 22821) (i32.const 22869) (i32.const 100)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 22869) (i32.const 24107) (i32.const 97)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 24107) (i32.const 24111) (i32.const 37)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 24111) (i32.const 24236) (i32.const 77)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 24236) (i32.const 24348) (i32.const 72)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 24348) (i32.const 24515) (i32.const 92)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 24515) (i32.const 24900) (i32.const 83)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 24900) (i32.const 25136) (i32.const 95)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 25136) (i32.const 25182) (i32.const 85)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 25182) (i32.const 25426) (i32.const 68)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 25426) (i32.const 25613) (i32.const 89)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 25613) (i32.const 25830) (i32.const 96)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 25830) (i32.const 26446) (i32.const 100)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 26446) (i32.const 26517) (i32.const 10)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 26517) (i32.const 27468) (i32.const 92)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 27468) (i32.const 27503) (i32.const 95)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 27503) (i32.const 27573) (i32.const 77)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 27573) (i32.const 28245) (i32.const 92)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 28245) (i32.const 28280) (i32.const 95)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 28280) (i32.const 29502) (i32.const 77)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 29502) (i32.const 29629) (i32.const 42)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 29629) (i32.const 30387) (i32.const 83)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 30387) (i32.const 30646) (i32.const 77)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 30646) (i32.const 31066) (i32.const 92)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 31066) (i32.const 31131) (i32.const 77)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 31131) (i32.const 31322) (i32.const 42)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 31322) (i32.const 31379) (i32.const 76)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 31379) (i32.const 31403) (i32.const 57)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 31403) (i32.const 31454) (i32.const 59)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 31454) (i32.const 31463) (i32.const 77)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 31463) (i32.const 31482) (i32.const 41)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 31482) (i32.const 31649) (i32.const 83)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 31649) (i32.const 31978) (i32.const 72)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 31978) (i32.const 32145) (i32.const 92)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 32145) (i32.const 32530) (i32.const 83)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 32530) (i32.const 32766) (i32.const 95)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 32766) (i32.const 32812) (i32.const 85)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 32812) (i32.const 33056) (i32.const 68)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 33056) (i32.const 33660) (i32.const 89)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 33660) (i32.const 33752) (i32.const 59)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 33752) (i32.const 33775) (i32.const 36)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 33775) (i32.const 33778) (i32.const 32)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 33778) (i32.const 34603) (i32.const 9)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 34603) (i32.const 35218) (i32.const 0)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 35218) (i32.const 35372) (i32.const 10)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 35372) (i32.const 35486) (i32.const 77)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 35486) (i32.const 35605) (i32.const 5)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 35605) (i32.const 35629) (i32.const 77)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 35629) (i32.const 35648) (i32.const 41)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 35648) (i32.const 36547) (i32.const 83)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 36547) (i32.const 36755) (i32.const 74)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 36755) (i32.const 36767) (i32.const 93)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 36767) (i32.const 36810) (i32.const 83)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 36810) (i32.const 36839) (i32.const 100)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 36839) (i32.const 37444) (i32.const 96)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 37444) (i32.const 38060) (i32.const 100)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 38060) (i32.const 38131) (i32.const 10)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 38131) (i32.const 39082) (i32.const 92)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 39082) (i32.const 39117) (i32.const 95)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 39117) (i32.const 39187) (i32.const 77)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 39187) (i32.const 39859) (i32.const 92)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 39859) (i32.const 39894) (i32.const 95)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 39894) (i32.const 40257) (i32.const 77)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 40257) (i32.const 40344) (i32.const 89)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 40344) (i32.const 40371) (i32.const 59)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 40371) (i32.const 40804) (i32.const 77)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 40804) (i32.const 40909) (i32.const 5)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 40909) (i32.const 42259) (i32.const 92)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 42259) (i32.const 42511) (i32.const 77)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 42511) (i32.const 42945) (i32.const 83)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 42945) (i32.const 43115) (i32.const 77)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 43115) (i32.const 43306) (i32.const 42)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 43306) (i32.const 43363) (i32.const 76)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 43363) (i32.const 43387) (i32.const 57)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 43387) (i32.const 43438) (i32.const 59)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 43438) (i32.const 43447) (i32.const 77)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 43447) (i32.const 43466) (i32.const 41)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 43466) (i32.const 44129) (i32.const 83)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 44129) (i32.const 44958) (i32.const 96)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 44958) (i32.const 45570) (i32.const 77)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 45570) (i32.const 45575) (i32.const 92)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 45575) (i32.const 45640) (i32.const 77)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 45640) (i32.const 45742) (i32.const 42)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 45742) (i32.const 45832) (i32.const 72)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 45832) (i32.const 45999) (i32.const 92)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 45999) (i32.const 46384) (i32.const 83)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 46384) (i32.const 46596) (i32.const 95)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 46596) (i32.const 46654) (i32.const 92)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 46654) (i32.const 47515) (i32.const 83)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 47515) (i32.const 47620) (i32.const 77)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 47620) (i32.const 47817) (i32.const 79)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 47817) (i32.const 47951) (i32.const 95)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 47951) (i32.const 48632) (i32.const 100)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 48632) (i32.const 48699) (i32.const 97)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 48699) (i32.const 48703) (i32.const 37)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 48703) (i32.const 49764) (i32.const 77)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 49764) (i32.const 49955) (i32.const 42)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 49955) (i32.const 50012) (i32.const 76)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 50012) (i32.const 50036) (i32.const 57)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 50036) (i32.const 50087) (i32.const 59)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 50087) (i32.const 50096) (i32.const 77)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 50096) (i32.const 50115) (i32.const 41)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 50115) (i32.const 50370) (i32.const 83)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 50370) (i32.const 51358) (i32.const 92)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 51358) (i32.const 51610) (i32.const 77)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 51610) (i32.const 51776) (i32.const 83)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 51776) (i32.const 51833) (i32.const 89)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 51833) (i32.const 52895) (i32.const 100)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 52895) (i32.const 53029) (i32.const 97)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 53029) (i32.const 53244) (i32.const 68)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 53244) (i32.const 54066) (i32.const 100)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 54066) (i32.const 54133) (i32.const 97)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 54133) (i32.const 54137) (i32.const 37)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 54137) (i32.const 55198) (i32.const 77)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 55198) (i32.const 55389) (i32.const 42)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 55389) (i32.const 55446) (i32.const 76)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 55446) (i32.const 55470) (i32.const 57)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 55470) (i32.const 55521) (i32.const 59)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 55521) (i32.const 55530) (i32.const 77)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 55530) (i32.const 55549) (i32.const 41)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 55549) (i32.const 56212) (i32.const 83)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 56212) (i32.const 57048) (i32.const 96)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 57048) (i32.const 58183) (i32.const 77)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 58183) (i32.const 58202) (i32.const 41)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 58202) (i32.const 58516) (i32.const 83)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 58516) (i32.const 58835) (i32.const 95)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 58835) (i32.const 58855) (i32.const 77)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 58855) (i32.const 59089) (i32.const 95)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 59089) (i32.const 59145) (i32.const 77)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 59145) (i32.const 59677) (i32.const 99)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 59677) (i32.const 60134) (i32.const 0)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 60134) (i32.const 60502) (i32.const 89)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 60502) (i32.const 60594) (i32.const 59)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 60594) (i32.const 60617) (i32.const 36)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 60617) (i32.const 60618) (i32.const 32)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 60618) (i32.const 60777) (i32.const 42)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 60777) (i32.const 60834) (i32.const 76)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 60834) (i32.const 60858) (i32.const 57)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 60858) (i32.const 60909) (i32.const 59)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 60909) (i32.const 60918) (i32.const 77)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 60918) (i32.const 60937) (i32.const 41)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 60937) (i32.const 61600) (i32.const 83)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 61600) (i32.const 62436) (i32.const 96)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 62436) (i32.const 63307) (i32.const 77)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 63307) (i32.const 63397) (i32.const 100)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 63397) (i32.const 63501) (i32.const 74)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 63501) (i32.const 63525) (i32.const 93)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 63525) (i32.const 63605) (i32.const 74)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 63605) (i32.const 63704) (i32.const 100)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 63704) (i32.const 63771) (i32.const 97)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 63771) (i32.const 63775) (i32.const 37)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 63775) (i32.const 64311) (i32.const 77)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 64311) (i32.const 64331) (i32.const 26)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 64331) (i32.const 64518) (i32.const 92)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 64518) (i32.const 64827) (i32.const 11)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 64827) (i32.const 64834) (i32.const 26)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 64834) (i32.const 65536) (i32.const 0)) + (i32.const -1)) diff --git a/test/core/memory_fill.wast b/test/core/memory_fill.wast new file mode 100644 index 0000000000..caca80b5da --- /dev/null +++ b/test/core/memory_fill.wast @@ -0,0 +1,685 @@ +;; +;; Generated by ../meta/generate_memory_fill.js +;; + +(module + (memory 1 1) + + (func (export "checkRange") (param $from i32) (param $to i32) (param $expected i32) (result i32) + (loop $cont + (if (i32.eq (local.get $from) (local.get $to)) + (then + (return (i32.const -1)))) + (if (i32.eq (i32.load8_u (local.get $from)) (local.get $expected)) + (then + (local.set $from (i32.add (local.get $from) (i32.const 1))) + (br $cont)))) + (return (local.get $from))) + + (func (export "test") + (memory.fill (i32.const 0xFF00) (i32.const 0x55) (i32.const 256)))) +(invoke "test") + +(assert_return (invoke "checkRange" (i32.const 0) (i32.const 65280) (i32.const 0)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 65280) (i32.const 65536) (i32.const 85)) + (i32.const -1)) +(module + (memory 1 1) + + (func (export "checkRange") (param $from i32) (param $to i32) (param $expected i32) (result i32) + (loop $cont + (if (i32.eq (local.get $from) (local.get $to)) + (then + (return (i32.const -1)))) + (if (i32.eq (i32.load8_u (local.get $from)) (local.get $expected)) + (then + (local.set $from (i32.add (local.get $from) (i32.const 1))) + (br $cont)))) + (return (local.get $from))) + + (func (export "test") + (memory.fill (i32.const 0xFF00) (i32.const 0x55) (i32.const 257)))) +(assert_trap (invoke "test") "out of bounds memory access") + +(module + (memory 1 1) + + (func (export "checkRange") (param $from i32) (param $to i32) (param $expected i32) (result i32) + (loop $cont + (if (i32.eq (local.get $from) (local.get $to)) + (then + (return (i32.const -1)))) + (if (i32.eq (i32.load8_u (local.get $from)) (local.get $expected)) + (then + (local.set $from (i32.add (local.get $from) (i32.const 1))) + (br $cont)))) + (return (local.get $from))) + + (func (export "test") + (memory.fill (i32.const 0xFFFFFF00) (i32.const 0x55) (i32.const 257)))) +(assert_trap (invoke "test") "out of bounds memory access") + +(module + (memory 1 1) + + (func (export "checkRange") (param $from i32) (param $to i32) (param $expected i32) (result i32) + (loop $cont + (if (i32.eq (local.get $from) (local.get $to)) + (then + (return (i32.const -1)))) + (if (i32.eq (i32.load8_u (local.get $from)) (local.get $expected)) + (then + (local.set $from (i32.add (local.get $from) (i32.const 1))) + (br $cont)))) + (return (local.get $from))) + + (func (export "test") + (memory.fill (i32.const 0x12) (i32.const 0x55) (i32.const 0)))) +(invoke "test") + +(assert_return (invoke "checkRange" (i32.const 0) (i32.const 65536) (i32.const 0)) + (i32.const -1)) +(module + (memory 1 1) + + (func (export "checkRange") (param $from i32) (param $to i32) (param $expected i32) (result i32) + (loop $cont + (if (i32.eq (local.get $from) (local.get $to)) + (then + (return (i32.const -1)))) + (if (i32.eq (i32.load8_u (local.get $from)) (local.get $expected)) + (then + (local.set $from (i32.add (local.get $from) (i32.const 1))) + (br $cont)))) + (return (local.get $from))) + + (func (export "test") + (memory.fill (i32.const 0x10000) (i32.const 0x55) (i32.const 0)))) +(invoke "test") + +(module + (memory 1 1) + + (func (export "checkRange") (param $from i32) (param $to i32) (param $expected i32) (result i32) + (loop $cont + (if (i32.eq (local.get $from) (local.get $to)) + (then + (return (i32.const -1)))) + (if (i32.eq (i32.load8_u (local.get $from)) (local.get $expected)) + (then + (local.set $from (i32.add (local.get $from) (i32.const 1))) + (br $cont)))) + (return (local.get $from))) + + (func (export "test") + (memory.fill (i32.const 0x20000) (i32.const 0x55) (i32.const 0)))) +(assert_trap (invoke "test") "out of bounds") + +(module + (memory 1 1) + + (func (export "checkRange") (param $from i32) (param $to i32) (param $expected i32) (result i32) + (loop $cont + (if (i32.eq (local.get $from) (local.get $to)) + (then + (return (i32.const -1)))) + (if (i32.eq (i32.load8_u (local.get $from)) (local.get $expected)) + (then + (local.set $from (i32.add (local.get $from) (i32.const 1))) + (br $cont)))) + (return (local.get $from))) + + (func (export "test") + (memory.fill (i32.const 0x1) (i32.const 0xAA) (i32.const 0xFFFE)))) +(invoke "test") + +(assert_return (invoke "checkRange" (i32.const 0) (i32.const 1) (i32.const 0)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 1) (i32.const 65535) (i32.const 170)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 65535) (i32.const 65536) (i32.const 0)) + (i32.const -1)) + +(module + (memory 1 1) + + (func (export "checkRange") (param $from i32) (param $to i32) (param $expected i32) (result i32) + (loop $cont + (if (i32.eq (local.get $from) (local.get $to)) + (then + (return (i32.const -1)))) + (if (i32.eq (i32.load8_u (local.get $from)) (local.get $expected)) + (then + (local.set $from (i32.add (local.get $from) (i32.const 1))) + (br $cont)))) + (return (local.get $from))) + + (func (export "test") + (memory.fill (i32.const 0x12) (i32.const 0x55) (i32.const 10)) + (memory.fill (i32.const 0x15) (i32.const 0xAA) (i32.const 4)))) +(invoke "test") + +(assert_return (invoke "checkRange" (i32.const 0) (i32.const 18) (i32.const 0)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 18) (i32.const 21) (i32.const 85)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 21) (i32.const 25) (i32.const 170)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 25) (i32.const 28) (i32.const 85)) + (i32.const -1)) +(assert_return (invoke "checkRange" (i32.const 28) (i32.const 65536) (i32.const 0)) + (i32.const -1)) +(assert_invalid + (module + (func (export "testfn") + (memory.fill (i32.const 10) (i32.const 20) (i32.const 30)))) + "unknown memory 0") + +(assert_invalid + (module + (memory 1 1) + (func (export "testfn") + (memory.fill (i32.const 10) (i32.const 20) (f32.const 30)))) + "type mismatch") + +(assert_invalid + (module + (memory 1 1) + (func (export "testfn") + (memory.fill (i32.const 10) (i32.const 20) (i64.const 30)))) + "type mismatch") + +(assert_invalid + (module + (memory 1 1) + (func (export "testfn") + (memory.fill (i32.const 10) (i32.const 20) (f64.const 30)))) + "type mismatch") + +(assert_invalid + (module + (memory 1 1) + (func (export "testfn") + (memory.fill (i32.const 10) (f32.const 20) (i32.const 30)))) + "type mismatch") + +(assert_invalid + (module + (memory 1 1) + (func (export "testfn") + (memory.fill (i32.const 10) (f32.const 20) (f32.const 30)))) + "type mismatch") + +(assert_invalid + (module + (memory 1 1) + (func (export "testfn") + (memory.fill (i32.const 10) (f32.const 20) (i64.const 30)))) + "type mismatch") + +(assert_invalid + (module + (memory 1 1) + (func (export "testfn") + (memory.fill (i32.const 10) (f32.const 20) (f64.const 30)))) + "type mismatch") + +(assert_invalid + (module + (memory 1 1) + (func (export "testfn") + (memory.fill (i32.const 10) (i64.const 20) (i32.const 30)))) + "type mismatch") + +(assert_invalid + (module + (memory 1 1) + (func (export "testfn") + (memory.fill (i32.const 10) (i64.const 20) (f32.const 30)))) + "type mismatch") + +(assert_invalid + (module + (memory 1 1) + (func (export "testfn") + (memory.fill (i32.const 10) (i64.const 20) (i64.const 30)))) + "type mismatch") + +(assert_invalid + (module + (memory 1 1) + (func (export "testfn") + (memory.fill (i32.const 10) (i64.const 20) (f64.const 30)))) + "type mismatch") + +(assert_invalid + (module + (memory 1 1) + (func (export "testfn") + (memory.fill (i32.const 10) (f64.const 20) (i32.const 30)))) + "type mismatch") + +(assert_invalid + (module + (memory 1 1) + (func (export "testfn") + (memory.fill (i32.const 10) (f64.const 20) (f32.const 30)))) + "type mismatch") + +(assert_invalid + (module + (memory 1 1) + (func (export "testfn") + (memory.fill (i32.const 10) (f64.const 20) (i64.const 30)))) + "type mismatch") + +(assert_invalid + (module + (memory 1 1) + (func (export "testfn") + (memory.fill (i32.const 10) (f64.const 20) (f64.const 30)))) + "type mismatch") + +(assert_invalid + (module + (memory 1 1) + (func (export "testfn") + (memory.fill (f32.const 10) (i32.const 20) (i32.const 30)))) + "type mismatch") + +(assert_invalid + (module + (memory 1 1) + (func (export "testfn") + (memory.fill (f32.const 10) (i32.const 20) (f32.const 30)))) + "type mismatch") + +(assert_invalid + (module + (memory 1 1) + (func (export "testfn") + (memory.fill (f32.const 10) (i32.const 20) (i64.const 30)))) + "type mismatch") + +(assert_invalid + (module + (memory 1 1) + (func (export "testfn") + (memory.fill (f32.const 10) (i32.const 20) (f64.const 30)))) + "type mismatch") + +(assert_invalid + (module + (memory 1 1) + (func (export "testfn") + (memory.fill (f32.const 10) (f32.const 20) (i32.const 30)))) + "type mismatch") + +(assert_invalid + (module + (memory 1 1) + (func (export "testfn") + (memory.fill (f32.const 10) (f32.const 20) (f32.const 30)))) + "type mismatch") + +(assert_invalid + (module + (memory 1 1) + (func (export "testfn") + (memory.fill (f32.const 10) (f32.const 20) (i64.const 30)))) + "type mismatch") + +(assert_invalid + (module + (memory 1 1) + (func (export "testfn") + (memory.fill (f32.const 10) (f32.const 20) (f64.const 30)))) + "type mismatch") + +(assert_invalid + (module + (memory 1 1) + (func (export "testfn") + (memory.fill (f32.const 10) (i64.const 20) (i32.const 30)))) + "type mismatch") + +(assert_invalid + (module + (memory 1 1) + (func (export "testfn") + (memory.fill (f32.const 10) (i64.const 20) (f32.const 30)))) + "type mismatch") + +(assert_invalid + (module + (memory 1 1) + (func (export "testfn") + (memory.fill (f32.const 10) (i64.const 20) (i64.const 30)))) + "type mismatch") + +(assert_invalid + (module + (memory 1 1) + (func (export "testfn") + (memory.fill (f32.const 10) (i64.const 20) (f64.const 30)))) + "type mismatch") + +(assert_invalid + (module + (memory 1 1) + (func (export "testfn") + (memory.fill (f32.const 10) (f64.const 20) (i32.const 30)))) + "type mismatch") + +(assert_invalid + (module + (memory 1 1) + (func (export "testfn") + (memory.fill (f32.const 10) (f64.const 20) (f32.const 30)))) + "type mismatch") + +(assert_invalid + (module + (memory 1 1) + (func (export "testfn") + (memory.fill (f32.const 10) (f64.const 20) (i64.const 30)))) + "type mismatch") + +(assert_invalid + (module + (memory 1 1) + (func (export "testfn") + (memory.fill (f32.const 10) (f64.const 20) (f64.const 30)))) + "type mismatch") + +(assert_invalid + (module + (memory 1 1) + (func (export "testfn") + (memory.fill (i64.const 10) (i32.const 20) (i32.const 30)))) + "type mismatch") + +(assert_invalid + (module + (memory 1 1) + (func (export "testfn") + (memory.fill (i64.const 10) (i32.const 20) (f32.const 30)))) + "type mismatch") + +(assert_invalid + (module + (memory 1 1) + (func (export "testfn") + (memory.fill (i64.const 10) (i32.const 20) (i64.const 30)))) + "type mismatch") + +(assert_invalid + (module + (memory 1 1) + (func (export "testfn") + (memory.fill (i64.const 10) (i32.const 20) (f64.const 30)))) + "type mismatch") + +(assert_invalid + (module + (memory 1 1) + (func (export "testfn") + (memory.fill (i64.const 10) (f32.const 20) (i32.const 30)))) + "type mismatch") + +(assert_invalid + (module + (memory 1 1) + (func (export "testfn") + (memory.fill (i64.const 10) (f32.const 20) (f32.const 30)))) + "type mismatch") + +(assert_invalid + (module + (memory 1 1) + (func (export "testfn") + (memory.fill (i64.const 10) (f32.const 20) (i64.const 30)))) + "type mismatch") + +(assert_invalid + (module + (memory 1 1) + (func (export "testfn") + (memory.fill (i64.const 10) (f32.const 20) (f64.const 30)))) + "type mismatch") + +(assert_invalid + (module + (memory 1 1) + (func (export "testfn") + (memory.fill (i64.const 10) (i64.const 20) (i32.const 30)))) + "type mismatch") + +(assert_invalid + (module + (memory 1 1) + (func (export "testfn") + (memory.fill (i64.const 10) (i64.const 20) (f32.const 30)))) + "type mismatch") + +(assert_invalid + (module + (memory 1 1) + (func (export "testfn") + (memory.fill (i64.const 10) (i64.const 20) (i64.const 30)))) + "type mismatch") + +(assert_invalid + (module + (memory 1 1) + (func (export "testfn") + (memory.fill (i64.const 10) (i64.const 20) (f64.const 30)))) + "type mismatch") + +(assert_invalid + (module + (memory 1 1) + (func (export "testfn") + (memory.fill (i64.const 10) (f64.const 20) (i32.const 30)))) + "type mismatch") + +(assert_invalid + (module + (memory 1 1) + (func (export "testfn") + (memory.fill (i64.const 10) (f64.const 20) (f32.const 30)))) + "type mismatch") + +(assert_invalid + (module + (memory 1 1) + (func (export "testfn") + (memory.fill (i64.const 10) (f64.const 20) (i64.const 30)))) + "type mismatch") + +(assert_invalid + (module + (memory 1 1) + (func (export "testfn") + (memory.fill (i64.const 10) (f64.const 20) (f64.const 30)))) + "type mismatch") + +(assert_invalid + (module + (memory 1 1) + (func (export "testfn") + (memory.fill (f64.const 10) (i32.const 20) (i32.const 30)))) + "type mismatch") + +(assert_invalid + (module + (memory 1 1) + (func (export "testfn") + (memory.fill (f64.const 10) (i32.const 20) (f32.const 30)))) + "type mismatch") + +(assert_invalid + (module + (memory 1 1) + (func (export "testfn") + (memory.fill (f64.const 10) (i32.const 20) (i64.const 30)))) + "type mismatch") + +(assert_invalid + (module + (memory 1 1) + (func (export "testfn") + (memory.fill (f64.const 10) (i32.const 20) (f64.const 30)))) + "type mismatch") + +(assert_invalid + (module + (memory 1 1) + (func (export "testfn") + (memory.fill (f64.const 10) (f32.const 20) (i32.const 30)))) + "type mismatch") + +(assert_invalid + (module + (memory 1 1) + (func (export "testfn") + (memory.fill (f64.const 10) (f32.const 20) (f32.const 30)))) + "type mismatch") + +(assert_invalid + (module + (memory 1 1) + (func (export "testfn") + (memory.fill (f64.const 10) (f32.const 20) (i64.const 30)))) + "type mismatch") + +(assert_invalid + (module + (memory 1 1) + (func (export "testfn") + (memory.fill (f64.const 10) (f32.const 20) (f64.const 30)))) + "type mismatch") + +(assert_invalid + (module + (memory 1 1) + (func (export "testfn") + (memory.fill (f64.const 10) (i64.const 20) (i32.const 30)))) + "type mismatch") + +(assert_invalid + (module + (memory 1 1) + (func (export "testfn") + (memory.fill (f64.const 10) (i64.const 20) (f32.const 30)))) + "type mismatch") + +(assert_invalid + (module + (memory 1 1) + (func (export "testfn") + (memory.fill (f64.const 10) (i64.const 20) (i64.const 30)))) + "type mismatch") + +(assert_invalid + (module + (memory 1 1) + (func (export "testfn") + (memory.fill (f64.const 10) (i64.const 20) (f64.const 30)))) + "type mismatch") + +(assert_invalid + (module + (memory 1 1) + (func (export "testfn") + (memory.fill (f64.const 10) (f64.const 20) (i32.const 30)))) + "type mismatch") + +(assert_invalid + (module + (memory 1 1) + (func (export "testfn") + (memory.fill (f64.const 10) (f64.const 20) (f32.const 30)))) + "type mismatch") + +(assert_invalid + (module + (memory 1 1) + (func (export "testfn") + (memory.fill (f64.const 10) (f64.const 20) (i64.const 30)))) + "type mismatch") + +(assert_invalid + (module + (memory 1 1) + (func (export "testfn") + (memory.fill (f64.const 10) (f64.const 20) (f64.const 30)))) + "type mismatch") + +(module + (memory 1 1 ) + + (func (export "checkRange") (param $from i32) (param $to i32) (param $expected i32) (result i32) + (loop $cont + (if (i32.eq (local.get $from) (local.get $to)) + (then + (return (i32.const -1)))) + (if (i32.eq (i32.load8_u (local.get $from)) (local.get $expected)) + (then + (local.set $from (i32.add (local.get $from) (i32.const 1))) + (br $cont)))) + (return (local.get $from))) + + (func (export "run") (param $offs i32) (param $val i32) (param $len i32) + (memory.fill (local.get $offs) (local.get $val) (local.get $len)))) + +(assert_trap (invoke "run" (i32.const 65280) (i32.const 37) (i32.const 512)) + "out of bounds") + +(assert_return (invoke "checkRange" (i32.const 0) (i32.const 1) (i32.const 0)) + (i32.const -1)) +(module + (memory 1 1 ) + + (func (export "checkRange") (param $from i32) (param $to i32) (param $expected i32) (result i32) + (loop $cont + (if (i32.eq (local.get $from) (local.get $to)) + (then + (return (i32.const -1)))) + (if (i32.eq (i32.load8_u (local.get $from)) (local.get $expected)) + (then + (local.set $from (i32.add (local.get $from) (i32.const 1))) + (br $cont)))) + (return (local.get $from))) + + (func (export "run") (param $offs i32) (param $val i32) (param $len i32) + (memory.fill (local.get $offs) (local.get $val) (local.get $len)))) + +(assert_trap (invoke "run" (i32.const 65279) (i32.const 37) (i32.const 514)) + "out of bounds") + +(assert_return (invoke "checkRange" (i32.const 0) (i32.const 1) (i32.const 0)) + (i32.const -1)) +(module + (memory 1 1 ) + + (func (export "checkRange") (param $from i32) (param $to i32) (param $expected i32) (result i32) + (loop $cont + (if (i32.eq (local.get $from) (local.get $to)) + (then + (return (i32.const -1)))) + (if (i32.eq (i32.load8_u (local.get $from)) (local.get $expected)) + (then + (local.set $from (i32.add (local.get $from) (i32.const 1))) + (br $cont)))) + (return (local.get $from))) + + (func (export "run") (param $offs i32) (param $val i32) (param $len i32) + (memory.fill (local.get $offs) (local.get $val) (local.get $len)))) + +(assert_trap (invoke "run" (i32.const 65279) (i32.const 37) (i32.const 4294967295)) + "out of bounds") + +(assert_return (invoke "checkRange" (i32.const 0) (i32.const 1) (i32.const 0)) + (i32.const -1)) diff --git a/test/core/memory_init.wast b/test/core/memory_init.wast new file mode 100644 index 0000000000..c647079d91 --- /dev/null +++ b/test/core/memory_init.wast @@ -0,0 +1,951 @@ +;; +;; Generated by ../meta/generate_memory_init.js +;; + +(module + (memory (export "memory0") 1 1) + (data (i32.const 2) "\03\01\04\01") + (data "\02\07\01\08") + (data (i32.const 12) "\07\05\02\03\06") + (data "\05\09\02\07\06") + (func (export "test") + (nop)) + (func (export "load8_u") (param i32) (result i32) + (i32.load8_u (local.get 0)))) + +(invoke "test") + +(assert_return (invoke "load8_u" (i32.const 0)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 1)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 2)) (i32.const 3)) +(assert_return (invoke "load8_u" (i32.const 3)) (i32.const 1)) +(assert_return (invoke "load8_u" (i32.const 4)) (i32.const 4)) +(assert_return (invoke "load8_u" (i32.const 5)) (i32.const 1)) +(assert_return (invoke "load8_u" (i32.const 6)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 7)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 8)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 9)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 10)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 11)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 12)) (i32.const 7)) +(assert_return (invoke "load8_u" (i32.const 13)) (i32.const 5)) +(assert_return (invoke "load8_u" (i32.const 14)) (i32.const 2)) +(assert_return (invoke "load8_u" (i32.const 15)) (i32.const 3)) +(assert_return (invoke "load8_u" (i32.const 16)) (i32.const 6)) +(assert_return (invoke "load8_u" (i32.const 17)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 18)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 19)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 20)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 21)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 22)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 23)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 24)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 25)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 26)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 27)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 28)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 29)) (i32.const 0)) + +(module + (memory (export "memory0") 1 1) + (data (i32.const 2) "\03\01\04\01") + (data "\02\07\01\08") + (data (i32.const 12) "\07\05\02\03\06") + (data "\05\09\02\07\06") + (func (export "test") + (memory.init 1 (i32.const 7) (i32.const 0) (i32.const 4))) + (func (export "load8_u") (param i32) (result i32) + (i32.load8_u (local.get 0)))) + +(invoke "test") + +(assert_return (invoke "load8_u" (i32.const 0)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 1)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 2)) (i32.const 3)) +(assert_return (invoke "load8_u" (i32.const 3)) (i32.const 1)) +(assert_return (invoke "load8_u" (i32.const 4)) (i32.const 4)) +(assert_return (invoke "load8_u" (i32.const 5)) (i32.const 1)) +(assert_return (invoke "load8_u" (i32.const 6)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 7)) (i32.const 2)) +(assert_return (invoke "load8_u" (i32.const 8)) (i32.const 7)) +(assert_return (invoke "load8_u" (i32.const 9)) (i32.const 1)) +(assert_return (invoke "load8_u" (i32.const 10)) (i32.const 8)) +(assert_return (invoke "load8_u" (i32.const 11)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 12)) (i32.const 7)) +(assert_return (invoke "load8_u" (i32.const 13)) (i32.const 5)) +(assert_return (invoke "load8_u" (i32.const 14)) (i32.const 2)) +(assert_return (invoke "load8_u" (i32.const 15)) (i32.const 3)) +(assert_return (invoke "load8_u" (i32.const 16)) (i32.const 6)) +(assert_return (invoke "load8_u" (i32.const 17)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 18)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 19)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 20)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 21)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 22)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 23)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 24)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 25)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 26)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 27)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 28)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 29)) (i32.const 0)) + +(module + (memory (export "memory0") 1 1) + (data (i32.const 2) "\03\01\04\01") + (data "\02\07\01\08") + (data (i32.const 12) "\07\05\02\03\06") + (data "\05\09\02\07\06") + (func (export "test") + (memory.init 3 (i32.const 15) (i32.const 1) (i32.const 3))) + (func (export "load8_u") (param i32) (result i32) + (i32.load8_u (local.get 0)))) + +(invoke "test") + +(assert_return (invoke "load8_u" (i32.const 0)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 1)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 2)) (i32.const 3)) +(assert_return (invoke "load8_u" (i32.const 3)) (i32.const 1)) +(assert_return (invoke "load8_u" (i32.const 4)) (i32.const 4)) +(assert_return (invoke "load8_u" (i32.const 5)) (i32.const 1)) +(assert_return (invoke "load8_u" (i32.const 6)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 7)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 8)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 9)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 10)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 11)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 12)) (i32.const 7)) +(assert_return (invoke "load8_u" (i32.const 13)) (i32.const 5)) +(assert_return (invoke "load8_u" (i32.const 14)) (i32.const 2)) +(assert_return (invoke "load8_u" (i32.const 15)) (i32.const 9)) +(assert_return (invoke "load8_u" (i32.const 16)) (i32.const 2)) +(assert_return (invoke "load8_u" (i32.const 17)) (i32.const 7)) +(assert_return (invoke "load8_u" (i32.const 18)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 19)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 20)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 21)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 22)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 23)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 24)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 25)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 26)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 27)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 28)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 29)) (i32.const 0)) + +(module + (memory (export "memory0") 1 1) + (data (i32.const 2) "\03\01\04\01") + (data "\02\07\01\08") + (data (i32.const 12) "\07\05\02\03\06") + (data "\05\09\02\07\06") + (func (export "test") + (memory.init 1 (i32.const 7) (i32.const 0) (i32.const 4)) + (data.drop 1) + (memory.init 3 (i32.const 15) (i32.const 1) (i32.const 3)) + (data.drop 3) + (memory.copy (i32.const 20) (i32.const 15) (i32.const 5)) + (memory.copy (i32.const 21) (i32.const 29) (i32.const 1)) + (memory.copy (i32.const 24) (i32.const 10) (i32.const 1)) + (memory.copy (i32.const 13) (i32.const 11) (i32.const 4)) + (memory.copy (i32.const 19) (i32.const 20) (i32.const 5))) + (func (export "load8_u") (param i32) (result i32) + (i32.load8_u (local.get 0)))) + +(invoke "test") + +(assert_return (invoke "load8_u" (i32.const 0)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 1)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 2)) (i32.const 3)) +(assert_return (invoke "load8_u" (i32.const 3)) (i32.const 1)) +(assert_return (invoke "load8_u" (i32.const 4)) (i32.const 4)) +(assert_return (invoke "load8_u" (i32.const 5)) (i32.const 1)) +(assert_return (invoke "load8_u" (i32.const 6)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 7)) (i32.const 2)) +(assert_return (invoke "load8_u" (i32.const 8)) (i32.const 7)) +(assert_return (invoke "load8_u" (i32.const 9)) (i32.const 1)) +(assert_return (invoke "load8_u" (i32.const 10)) (i32.const 8)) +(assert_return (invoke "load8_u" (i32.const 11)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 12)) (i32.const 7)) +(assert_return (invoke "load8_u" (i32.const 13)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 14)) (i32.const 7)) +(assert_return (invoke "load8_u" (i32.const 15)) (i32.const 5)) +(assert_return (invoke "load8_u" (i32.const 16)) (i32.const 2)) +(assert_return (invoke "load8_u" (i32.const 17)) (i32.const 7)) +(assert_return (invoke "load8_u" (i32.const 18)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 19)) (i32.const 9)) +(assert_return (invoke "load8_u" (i32.const 20)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 21)) (i32.const 7)) +(assert_return (invoke "load8_u" (i32.const 22)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 23)) (i32.const 8)) +(assert_return (invoke "load8_u" (i32.const 24)) (i32.const 8)) +(assert_return (invoke "load8_u" (i32.const 25)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 26)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 27)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 28)) (i32.const 0)) +(assert_return (invoke "load8_u" (i32.const 29)) (i32.const 0)) +(assert_invalid + (module + (func (export "test") + (data.drop 0))) + "unknown memory 0") + +(assert_invalid + (module + (memory 1) + (data "\37") + (func (export "test") + (data.drop 4))) + "unknown data segment") + +(module + (memory 1) + (data "\37") + (func (export "test") + (data.drop 0) + (data.drop 0))) +(invoke "test") + +(module + (memory 1) + (data "\37") + (func (export "test") + (data.drop 0) + (memory.init 0 (i32.const 1234) (i32.const 1) (i32.const 1)))) +(assert_trap (invoke "test") "out of bounds") + +(module + (memory 1) + (data (i32.const 0) "\37") + (func (export "test") + (memory.init 0 (i32.const 1234) (i32.const 1) (i32.const 1)))) +(assert_trap (invoke "test") "out of bounds") + +(assert_invalid + (module + (func (export "test") + (memory.init 1 (i32.const 1234) (i32.const 1) (i32.const 1)))) + "unknown memory 0") + +(assert_invalid + (module + (memory 1) + (data "\37") + (func (export "test") + (memory.init 1 (i32.const 1234) (i32.const 1) (i32.const 1)))) + "unknown data segment 1") + +(module + (memory 1) + (data "\37") + (func (export "test") + (memory.init 0 (i32.const 1) (i32.const 0) (i32.const 1)) + (memory.init 0 (i32.const 1) (i32.const 0) (i32.const 1)))) +(invoke "test") + +(module + (memory 1) + (data "\37") + (func (export "test") + (memory.init 0 (i32.const 1234) (i32.const 0) (i32.const 5)))) +(assert_trap (invoke "test") "out of bounds") + +(module + (memory 1) + (data "\37") + (func (export "test") + (memory.init 0 (i32.const 1234) (i32.const 2) (i32.const 3)))) +(assert_trap (invoke "test") "out of bounds") + +(module + (memory 1) + (data "\37") + (func (export "test") + (memory.init 0 (i32.const 0xFFFE) (i32.const 1) (i32.const 3)))) +(assert_trap (invoke "test") "out of bounds") + +(module + (memory 1) + (data "\37") + (func (export "test") + (memory.init 0 (i32.const 1234) (i32.const 4) (i32.const 0)))) +(assert_trap (invoke "test") "out of bounds") + +(module + (memory 1) + (data "\37") + (func (export "test") + (memory.init 0 (i32.const 1234) (i32.const 1) (i32.const 0)))) +(invoke "test") + +(module + (memory 1) + (data "\37") + (func (export "test") + (memory.init 0 (i32.const 0x10001) (i32.const 0) (i32.const 0)))) +(assert_trap (invoke "test") "out of bounds") + +(module + (memory 1) + (data "\37") + (func (export "test") + (memory.init 0 (i32.const 0x10000) (i32.const 0) (i32.const 0)))) +(invoke "test") + +(module + (memory 1) + (data "\37") + (func (export "test") + (memory.init 0 (i32.const 0x10000) (i32.const 1) (i32.const 0)))) +(invoke "test") + +(module + (memory 1) + (data "\37") + (func (export "test") + (memory.init 0 (i32.const 0x10001) (i32.const 4) (i32.const 0)))) +(assert_trap (invoke "test") "out of bounds") + +(assert_invalid + (module + (memory 1) + (data "\37") + (func (export "test") + (memory.init 0 (i32.const 1) (i32.const 1) (f32.const 1)))) + "type mismatch") + +(assert_invalid + (module + (memory 1) + (data "\37") + (func (export "test") + (memory.init 0 (i32.const 1) (i32.const 1) (i64.const 1)))) + "type mismatch") + +(assert_invalid + (module + (memory 1) + (data "\37") + (func (export "test") + (memory.init 0 (i32.const 1) (i32.const 1) (f64.const 1)))) + "type mismatch") + +(assert_invalid + (module + (memory 1) + (data "\37") + (func (export "test") + (memory.init 0 (i32.const 1) (f32.const 1) (i32.const 1)))) + "type mismatch") + +(assert_invalid + (module + (memory 1) + (data "\37") + (func (export "test") + (memory.init 0 (i32.const 1) (f32.const 1) (f32.const 1)))) + "type mismatch") + +(assert_invalid + (module + (memory 1) + (data "\37") + (func (export "test") + (memory.init 0 (i32.const 1) (f32.const 1) (i64.const 1)))) + "type mismatch") + +(assert_invalid + (module + (memory 1) + (data "\37") + (func (export "test") + (memory.init 0 (i32.const 1) (f32.const 1) (f64.const 1)))) + "type mismatch") + +(assert_invalid + (module + (memory 1) + (data "\37") + (func (export "test") + (memory.init 0 (i32.const 1) (i64.const 1) (i32.const 1)))) + "type mismatch") + +(assert_invalid + (module + (memory 1) + (data "\37") + (func (export "test") + (memory.init 0 (i32.const 1) (i64.const 1) (f32.const 1)))) + "type mismatch") + +(assert_invalid + (module + (memory 1) + (data "\37") + (func (export "test") + (memory.init 0 (i32.const 1) (i64.const 1) (i64.const 1)))) + "type mismatch") + +(assert_invalid + (module + (memory 1) + (data "\37") + (func (export "test") + (memory.init 0 (i32.const 1) (i64.const 1) (f64.const 1)))) + "type mismatch") + +(assert_invalid + (module + (memory 1) + (data "\37") + (func (export "test") + (memory.init 0 (i32.const 1) (f64.const 1) (i32.const 1)))) + "type mismatch") + +(assert_invalid + (module + (memory 1) + (data "\37") + (func (export "test") + (memory.init 0 (i32.const 1) (f64.const 1) (f32.const 1)))) + "type mismatch") + +(assert_invalid + (module + (memory 1) + (data "\37") + (func (export "test") + (memory.init 0 (i32.const 1) (f64.const 1) (i64.const 1)))) + "type mismatch") + +(assert_invalid + (module + (memory 1) + (data "\37") + (func (export "test") + (memory.init 0 (i32.const 1) (f64.const 1) (f64.const 1)))) + "type mismatch") + +(assert_invalid + (module + (memory 1) + (data "\37") + (func (export "test") + (memory.init 0 (f32.const 1) (i32.const 1) (i32.const 1)))) + "type mismatch") + +(assert_invalid + (module + (memory 1) + (data "\37") + (func (export "test") + (memory.init 0 (f32.const 1) (i32.const 1) (f32.const 1)))) + "type mismatch") + +(assert_invalid + (module + (memory 1) + (data "\37") + (func (export "test") + (memory.init 0 (f32.const 1) (i32.const 1) (i64.const 1)))) + "type mismatch") + +(assert_invalid + (module + (memory 1) + (data "\37") + (func (export "test") + (memory.init 0 (f32.const 1) (i32.const 1) (f64.const 1)))) + "type mismatch") + +(assert_invalid + (module + (memory 1) + (data "\37") + (func (export "test") + (memory.init 0 (f32.const 1) (f32.const 1) (i32.const 1)))) + "type mismatch") + +(assert_invalid + (module + (memory 1) + (data "\37") + (func (export "test") + (memory.init 0 (f32.const 1) (f32.const 1) (f32.const 1)))) + "type mismatch") + +(assert_invalid + (module + (memory 1) + (data "\37") + (func (export "test") + (memory.init 0 (f32.const 1) (f32.const 1) (i64.const 1)))) + "type mismatch") + +(assert_invalid + (module + (memory 1) + (data "\37") + (func (export "test") + (memory.init 0 (f32.const 1) (f32.const 1) (f64.const 1)))) + "type mismatch") + +(assert_invalid + (module + (memory 1) + (data "\37") + (func (export "test") + (memory.init 0 (f32.const 1) (i64.const 1) (i32.const 1)))) + "type mismatch") + +(assert_invalid + (module + (memory 1) + (data "\37") + (func (export "test") + (memory.init 0 (f32.const 1) (i64.const 1) (f32.const 1)))) + "type mismatch") + +(assert_invalid + (module + (memory 1) + (data "\37") + (func (export "test") + (memory.init 0 (f32.const 1) (i64.const 1) (i64.const 1)))) + "type mismatch") + +(assert_invalid + (module + (memory 1) + (data "\37") + (func (export "test") + (memory.init 0 (f32.const 1) (i64.const 1) (f64.const 1)))) + "type mismatch") + +(assert_invalid + (module + (memory 1) + (data "\37") + (func (export "test") + (memory.init 0 (f32.const 1) (f64.const 1) (i32.const 1)))) + "type mismatch") + +(assert_invalid + (module + (memory 1) + (data "\37") + (func (export "test") + (memory.init 0 (f32.const 1) (f64.const 1) (f32.const 1)))) + "type mismatch") + +(assert_invalid + (module + (memory 1) + (data "\37") + (func (export "test") + (memory.init 0 (f32.const 1) (f64.const 1) (i64.const 1)))) + "type mismatch") + +(assert_invalid + (module + (memory 1) + (data "\37") + (func (export "test") + (memory.init 0 (f32.const 1) (f64.const 1) (f64.const 1)))) + "type mismatch") + +(assert_invalid + (module + (memory 1) + (data "\37") + (func (export "test") + (memory.init 0 (i64.const 1) (i32.const 1) (i32.const 1)))) + "type mismatch") + +(assert_invalid + (module + (memory 1) + (data "\37") + (func (export "test") + (memory.init 0 (i64.const 1) (i32.const 1) (f32.const 1)))) + "type mismatch") + +(assert_invalid + (module + (memory 1) + (data "\37") + (func (export "test") + (memory.init 0 (i64.const 1) (i32.const 1) (i64.const 1)))) + "type mismatch") + +(assert_invalid + (module + (memory 1) + (data "\37") + (func (export "test") + (memory.init 0 (i64.const 1) (i32.const 1) (f64.const 1)))) + "type mismatch") + +(assert_invalid + (module + (memory 1) + (data "\37") + (func (export "test") + (memory.init 0 (i64.const 1) (f32.const 1) (i32.const 1)))) + "type mismatch") + +(assert_invalid + (module + (memory 1) + (data "\37") + (func (export "test") + (memory.init 0 (i64.const 1) (f32.const 1) (f32.const 1)))) + "type mismatch") + +(assert_invalid + (module + (memory 1) + (data "\37") + (func (export "test") + (memory.init 0 (i64.const 1) (f32.const 1) (i64.const 1)))) + "type mismatch") + +(assert_invalid + (module + (memory 1) + (data "\37") + (func (export "test") + (memory.init 0 (i64.const 1) (f32.const 1) (f64.const 1)))) + "type mismatch") + +(assert_invalid + (module + (memory 1) + (data "\37") + (func (export "test") + (memory.init 0 (i64.const 1) (i64.const 1) (i32.const 1)))) + "type mismatch") + +(assert_invalid + (module + (memory 1) + (data "\37") + (func (export "test") + (memory.init 0 (i64.const 1) (i64.const 1) (f32.const 1)))) + "type mismatch") + +(assert_invalid + (module + (memory 1) + (data "\37") + (func (export "test") + (memory.init 0 (i64.const 1) (i64.const 1) (i64.const 1)))) + "type mismatch") + +(assert_invalid + (module + (memory 1) + (data "\37") + (func (export "test") + (memory.init 0 (i64.const 1) (i64.const 1) (f64.const 1)))) + "type mismatch") + +(assert_invalid + (module + (memory 1) + (data "\37") + (func (export "test") + (memory.init 0 (i64.const 1) (f64.const 1) (i32.const 1)))) + "type mismatch") + +(assert_invalid + (module + (memory 1) + (data "\37") + (func (export "test") + (memory.init 0 (i64.const 1) (f64.const 1) (f32.const 1)))) + "type mismatch") + +(assert_invalid + (module + (memory 1) + (data "\37") + (func (export "test") + (memory.init 0 (i64.const 1) (f64.const 1) (i64.const 1)))) + "type mismatch") + +(assert_invalid + (module + (memory 1) + (data "\37") + (func (export "test") + (memory.init 0 (i64.const 1) (f64.const 1) (f64.const 1)))) + "type mismatch") + +(assert_invalid + (module + (memory 1) + (data "\37") + (func (export "test") + (memory.init 0 (f64.const 1) (i32.const 1) (i32.const 1)))) + "type mismatch") + +(assert_invalid + (module + (memory 1) + (data "\37") + (func (export "test") + (memory.init 0 (f64.const 1) (i32.const 1) (f32.const 1)))) + "type mismatch") + +(assert_invalid + (module + (memory 1) + (data "\37") + (func (export "test") + (memory.init 0 (f64.const 1) (i32.const 1) (i64.const 1)))) + "type mismatch") + +(assert_invalid + (module + (memory 1) + (data "\37") + (func (export "test") + (memory.init 0 (f64.const 1) (i32.const 1) (f64.const 1)))) + "type mismatch") + +(assert_invalid + (module + (memory 1) + (data "\37") + (func (export "test") + (memory.init 0 (f64.const 1) (f32.const 1) (i32.const 1)))) + "type mismatch") + +(assert_invalid + (module + (memory 1) + (data "\37") + (func (export "test") + (memory.init 0 (f64.const 1) (f32.const 1) (f32.const 1)))) + "type mismatch") + +(assert_invalid + (module + (memory 1) + (data "\37") + (func (export "test") + (memory.init 0 (f64.const 1) (f32.const 1) (i64.const 1)))) + "type mismatch") + +(assert_invalid + (module + (memory 1) + (data "\37") + (func (export "test") + (memory.init 0 (f64.const 1) (f32.const 1) (f64.const 1)))) + "type mismatch") + +(assert_invalid + (module + (memory 1) + (data "\37") + (func (export "test") + (memory.init 0 (f64.const 1) (i64.const 1) (i32.const 1)))) + "type mismatch") + +(assert_invalid + (module + (memory 1) + (data "\37") + (func (export "test") + (memory.init 0 (f64.const 1) (i64.const 1) (f32.const 1)))) + "type mismatch") + +(assert_invalid + (module + (memory 1) + (data "\37") + (func (export "test") + (memory.init 0 (f64.const 1) (i64.const 1) (i64.const 1)))) + "type mismatch") + +(assert_invalid + (module + (memory 1) + (data "\37") + (func (export "test") + (memory.init 0 (f64.const 1) (i64.const 1) (f64.const 1)))) + "type mismatch") + +(assert_invalid + (module + (memory 1) + (data "\37") + (func (export "test") + (memory.init 0 (f64.const 1) (f64.const 1) (i32.const 1)))) + "type mismatch") + +(assert_invalid + (module + (memory 1) + (data "\37") + (func (export "test") + (memory.init 0 (f64.const 1) (f64.const 1) (f32.const 1)))) + "type mismatch") + +(assert_invalid + (module + (memory 1) + (data "\37") + (func (export "test") + (memory.init 0 (f64.const 1) (f64.const 1) (i64.const 1)))) + "type mismatch") + +(assert_invalid + (module + (memory 1) + (data "\37") + (func (export "test") + (memory.init 0 (f64.const 1) (f64.const 1) (f64.const 1)))) + "type mismatch") + +(module + (memory 1 1 ) + (data "\42\42\42\42\42\42\42\42\42\42\42\42\42\42\42\42") + + (func (export "checkRange") (param $from i32) (param $to i32) (param $expected i32) (result i32) + (loop $cont + (if (i32.eq (local.get $from) (local.get $to)) + (then + (return (i32.const -1)))) + (if (i32.eq (i32.load8_u (local.get $from)) (local.get $expected)) + (then + (local.set $from (i32.add (local.get $from) (i32.const 1))) + (br $cont)))) + (return (local.get $from))) + + (func (export "run") (param $offs i32) (param $len i32) + (memory.init 0 (local.get $offs) (i32.const 0) (local.get $len)))) + +(assert_trap (invoke "run" (i32.const 65528) (i32.const 16)) + "out of bounds") + +(assert_return (invoke "checkRange" (i32.const 0) (i32.const 1) (i32.const 0)) + (i32.const -1)) +(module + (memory 1 1 ) + (data "\42\42\42\42\42\42\42\42\42\42\42\42\42\42\42\42") + + (func (export "checkRange") (param $from i32) (param $to i32) (param $expected i32) (result i32) + (loop $cont + (if (i32.eq (local.get $from) (local.get $to)) + (then + (return (i32.const -1)))) + (if (i32.eq (i32.load8_u (local.get $from)) (local.get $expected)) + (then + (local.set $from (i32.add (local.get $from) (i32.const 1))) + (br $cont)))) + (return (local.get $from))) + + (func (export "run") (param $offs i32) (param $len i32) + (memory.init 0 (local.get $offs) (i32.const 0) (local.get $len)))) + +(assert_trap (invoke "run" (i32.const 65527) (i32.const 16)) + "out of bounds") + +(assert_return (invoke "checkRange" (i32.const 0) (i32.const 1) (i32.const 0)) + (i32.const -1)) +(module + (memory 1 1 ) + (data "\42\42\42\42\42\42\42\42\42\42\42\42\42\42\42\42") + + (func (export "checkRange") (param $from i32) (param $to i32) (param $expected i32) (result i32) + (loop $cont + (if (i32.eq (local.get $from) (local.get $to)) + (then + (return (i32.const -1)))) + (if (i32.eq (i32.load8_u (local.get $from)) (local.get $expected)) + (then + (local.set $from (i32.add (local.get $from) (i32.const 1))) + (br $cont)))) + (return (local.get $from))) + + (func (export "run") (param $offs i32) (param $len i32) + (memory.init 0 (local.get $offs) (i32.const 0) (local.get $len)))) + +(assert_trap (invoke "run" (i32.const 65472) (i32.const 30)) + "out of bounds") + +(assert_return (invoke "checkRange" (i32.const 0) (i32.const 1) (i32.const 0)) + (i32.const -1)) +(module + (memory 1 1 ) + (data "\42\42\42\42\42\42\42\42\42\42\42\42\42\42\42\42") + + (func (export "checkRange") (param $from i32) (param $to i32) (param $expected i32) (result i32) + (loop $cont + (if (i32.eq (local.get $from) (local.get $to)) + (then + (return (i32.const -1)))) + (if (i32.eq (i32.load8_u (local.get $from)) (local.get $expected)) + (then + (local.set $from (i32.add (local.get $from) (i32.const 1))) + (br $cont)))) + (return (local.get $from))) + + (func (export "run") (param $offs i32) (param $len i32) + (memory.init 0 (local.get $offs) (i32.const 0) (local.get $len)))) + +(assert_trap (invoke "run" (i32.const 65473) (i32.const 31)) + "out of bounds") + +(assert_return (invoke "checkRange" (i32.const 0) (i32.const 1) (i32.const 0)) + (i32.const -1)) +(module + (memory 1 ) + (data "\42\42\42\42\42\42\42\42\42\42\42\42\42\42\42\42") + + (func (export "checkRange") (param $from i32) (param $to i32) (param $expected i32) (result i32) + (loop $cont + (if (i32.eq (local.get $from) (local.get $to)) + (then + (return (i32.const -1)))) + (if (i32.eq (i32.load8_u (local.get $from)) (local.get $expected)) + (then + (local.set $from (i32.add (local.get $from) (i32.const 1))) + (br $cont)))) + (return (local.get $from))) + + (func (export "run") (param $offs i32) (param $len i32) + (memory.init 0 (local.get $offs) (i32.const 0) (local.get $len)))) + +(assert_trap (invoke "run" (i32.const 65528) (i32.const 4294967040)) + "out of bounds") + +(assert_return (invoke "checkRange" (i32.const 0) (i32.const 1) (i32.const 0)) + (i32.const -1)) +(module + (memory 1 ) + (data "\42\42\42\42\42\42\42\42\42\42\42\42\42\42\42\42") + + (func (export "checkRange") (param $from i32) (param $to i32) (param $expected i32) (result i32) + (loop $cont + (if (i32.eq (local.get $from) (local.get $to)) + (then + (return (i32.const -1)))) + (if (i32.eq (i32.load8_u (local.get $from)) (local.get $expected)) + (then + (local.set $from (i32.add (local.get $from) (i32.const 1))) + (br $cont)))) + (return (local.get $from))) + + (func (export "run") (param $offs i32) (param $len i32) + (memory.init 0 (local.get $offs) (i32.const 0) (local.get $len)))) + +(assert_trap (invoke "run" (i32.const 0) (i32.const 4294967292)) + "out of bounds") + +(assert_return (invoke "checkRange" (i32.const 0) (i32.const 1) (i32.const 0)) + (i32.const -1)) diff --git a/test/core/ref_is_null.wast b/test/core/ref_is_null.wast index 3e9a678314..7a42ca7d5d 100644 --- a/test/core/ref_is_null.wast +++ b/test/core/ref_is_null.wast @@ -11,7 +11,8 @@ (table $t1 2 nullref) (table $t2 2 anyref) - (table $t3 2 funcref) (elem $t3 (i32.const 1) $dummy) + (table $t3 2 funcref) + (elem (table $t3) (i32.const 1) func $dummy) (func $dummy) (func (export "init") (param $r anyref) diff --git a/test/core/table_copy.wast b/test/core/table_copy.wast new file mode 100644 index 0000000000..d0aa77b205 --- /dev/null +++ b/test/core/table_copy.wast @@ -0,0 +1,1595 @@ +;; +;; Generated by ../meta/generate_table_copy.js +;; + +(module + (func (export "ef0") (result i32) (i32.const 0)) + (func (export "ef1") (result i32) (i32.const 1)) + (func (export "ef2") (result i32) (i32.const 2)) + (func (export "ef3") (result i32) (i32.const 3)) + (func (export "ef4") (result i32) (i32.const 4)) +) +(register "a") + +(module + (type (func (result i32))) ;; type #0 + (import "a" "ef0" (func (result i32))) ;; index 0 + (import "a" "ef1" (func (result i32))) + (import "a" "ef2" (func (result i32))) + (import "a" "ef3" (func (result i32))) + (import "a" "ef4" (func (result i32))) ;; index 4 + (table 30 30 funcref) + (elem (i32.const 2) 3 1 4 1) + (elem funcref + (ref.func 2) (ref.func 7) (ref.func 1) (ref.func 8)) + (elem (i32.const 12) 7 5 2 3 6) + (elem funcref + (ref.func 5) (ref.func 9) (ref.func 2) (ref.func 7) (ref.func 6)) + (func (result i32) (i32.const 5)) ;; index 5 + (func (result i32) (i32.const 6)) + (func (result i32) (i32.const 7)) + (func (result i32) (i32.const 8)) + (func (result i32) (i32.const 9)) ;; index 9 + (func (export "test") + (nop)) + (func (export "check") (param i32) (result i32) + (call_indirect (type 0) (local.get 0))) +) + +(invoke "test") +(assert_trap (invoke "check" (i32.const 0)) "uninitialized element") +(assert_trap (invoke "check" (i32.const 1)) "uninitialized element") +(assert_return (invoke "check" (i32.const 2)) (i32.const 3)) +(assert_return (invoke "check" (i32.const 3)) (i32.const 1)) +(assert_return (invoke "check" (i32.const 4)) (i32.const 4)) +(assert_return (invoke "check" (i32.const 5)) (i32.const 1)) +(assert_trap (invoke "check" (i32.const 6)) "uninitialized element") +(assert_trap (invoke "check" (i32.const 7)) "uninitialized element") +(assert_trap (invoke "check" (i32.const 8)) "uninitialized element") +(assert_trap (invoke "check" (i32.const 9)) "uninitialized element") +(assert_trap (invoke "check" (i32.const 10)) "uninitialized element") +(assert_trap (invoke "check" (i32.const 11)) "uninitialized element") +(assert_return (invoke "check" (i32.const 12)) (i32.const 7)) +(assert_return (invoke "check" (i32.const 13)) (i32.const 5)) +(assert_return (invoke "check" (i32.const 14)) (i32.const 2)) +(assert_return (invoke "check" (i32.const 15)) (i32.const 3)) +(assert_return (invoke "check" (i32.const 16)) (i32.const 6)) +(assert_trap (invoke "check" (i32.const 17)) "uninitialized element") +(assert_trap (invoke "check" (i32.const 18)) "uninitialized element") +(assert_trap (invoke "check" (i32.const 19)) "uninitialized element") +(assert_trap (invoke "check" (i32.const 20)) "uninitialized element") +(assert_trap (invoke "check" (i32.const 21)) "uninitialized element") +(assert_trap (invoke "check" (i32.const 22)) "uninitialized element") +(assert_trap (invoke "check" (i32.const 23)) "uninitialized element") +(assert_trap (invoke "check" (i32.const 24)) "uninitialized element") +(assert_trap (invoke "check" (i32.const 25)) "uninitialized element") +(assert_trap (invoke "check" (i32.const 26)) "uninitialized element") +(assert_trap (invoke "check" (i32.const 27)) "uninitialized element") +(assert_trap (invoke "check" (i32.const 28)) "uninitialized element") +(assert_trap (invoke "check" (i32.const 29)) "uninitialized element") + +(module + (type (func (result i32))) ;; type #0 + (import "a" "ef0" (func (result i32))) ;; index 0 + (import "a" "ef1" (func (result i32))) + (import "a" "ef2" (func (result i32))) + (import "a" "ef3" (func (result i32))) + (import "a" "ef4" (func (result i32))) ;; index 4 + (table 30 30 funcref) + (elem (i32.const 2) 3 1 4 1) + (elem funcref + (ref.func 2) (ref.func 7) (ref.func 1) (ref.func 8)) + (elem (i32.const 12) 7 5 2 3 6) + (elem funcref + (ref.func 5) (ref.func 9) (ref.func 2) (ref.func 7) (ref.func 6)) + (func (result i32) (i32.const 5)) ;; index 5 + (func (result i32) (i32.const 6)) + (func (result i32) (i32.const 7)) + (func (result i32) (i32.const 8)) + (func (result i32) (i32.const 9)) ;; index 9 + (func (export "test") + (table.copy (i32.const 13) (i32.const 2) (i32.const 3))) + (func (export "check") (param i32) (result i32) + (call_indirect (type 0) (local.get 0))) +) + +(invoke "test") +(assert_trap (invoke "check" (i32.const 0)) "uninitialized element") +(assert_trap (invoke "check" (i32.const 1)) "uninitialized element") +(assert_return (invoke "check" (i32.const 2)) (i32.const 3)) +(assert_return (invoke "check" (i32.const 3)) (i32.const 1)) +(assert_return (invoke "check" (i32.const 4)) (i32.const 4)) +(assert_return (invoke "check" (i32.const 5)) (i32.const 1)) +(assert_trap (invoke "check" (i32.const 6)) "uninitialized element") +(assert_trap (invoke "check" (i32.const 7)) "uninitialized element") +(assert_trap (invoke "check" (i32.const 8)) "uninitialized element") +(assert_trap (invoke "check" (i32.const 9)) "uninitialized element") +(assert_trap (invoke "check" (i32.const 10)) "uninitialized element") +(assert_trap (invoke "check" (i32.const 11)) "uninitialized element") +(assert_return (invoke "check" (i32.const 12)) (i32.const 7)) +(assert_return (invoke "check" (i32.const 13)) (i32.const 3)) +(assert_return (invoke "check" (i32.const 14)) (i32.const 1)) +(assert_return (invoke "check" (i32.const 15)) (i32.const 4)) +(assert_return (invoke "check" (i32.const 16)) (i32.const 6)) +(assert_trap (invoke "check" (i32.const 17)) "uninitialized element") +(assert_trap (invoke "check" (i32.const 18)) "uninitialized element") +(assert_trap (invoke "check" (i32.const 19)) "uninitialized element") +(assert_trap (invoke "check" (i32.const 20)) "uninitialized element") +(assert_trap (invoke "check" (i32.const 21)) "uninitialized element") +(assert_trap (invoke "check" (i32.const 22)) "uninitialized element") +(assert_trap (invoke "check" (i32.const 23)) "uninitialized element") +(assert_trap (invoke "check" (i32.const 24)) "uninitialized element") +(assert_trap (invoke "check" (i32.const 25)) "uninitialized element") +(assert_trap (invoke "check" (i32.const 26)) "uninitialized element") +(assert_trap (invoke "check" (i32.const 27)) "uninitialized element") +(assert_trap (invoke "check" (i32.const 28)) "uninitialized element") +(assert_trap (invoke "check" (i32.const 29)) "uninitialized element") + +(module + (type (func (result i32))) ;; type #0 + (import "a" "ef0" (func (result i32))) ;; index 0 + (import "a" "ef1" (func (result i32))) + (import "a" "ef2" (func (result i32))) + (import "a" "ef3" (func (result i32))) + (import "a" "ef4" (func (result i32))) ;; index 4 + (table 30 30 funcref) + (elem (i32.const 2) 3 1 4 1) + (elem funcref + (ref.func 2) (ref.func 7) (ref.func 1) (ref.func 8)) + (elem (i32.const 12) 7 5 2 3 6) + (elem funcref + (ref.func 5) (ref.func 9) (ref.func 2) (ref.func 7) (ref.func 6)) + (func (result i32) (i32.const 5)) ;; index 5 + (func (result i32) (i32.const 6)) + (func (result i32) (i32.const 7)) + (func (result i32) (i32.const 8)) + (func (result i32) (i32.const 9)) ;; index 9 + (func (export "test") + (table.copy (i32.const 25) (i32.const 15) (i32.const 2))) + (func (export "check") (param i32) (result i32) + (call_indirect (type 0) (local.get 0))) +) + +(invoke "test") +(assert_trap (invoke "check" (i32.const 0)) "uninitialized element") +(assert_trap (invoke "check" (i32.const 1)) "uninitialized element") +(assert_return (invoke "check" (i32.const 2)) (i32.const 3)) +(assert_return (invoke "check" (i32.const 3)) (i32.const 1)) +(assert_return (invoke "check" (i32.const 4)) (i32.const 4)) +(assert_return (invoke "check" (i32.const 5)) (i32.const 1)) +(assert_trap (invoke "check" (i32.const 6)) "uninitialized element") +(assert_trap (invoke "check" (i32.const 7)) "uninitialized element") +(assert_trap (invoke "check" (i32.const 8)) "uninitialized element") +(assert_trap (invoke "check" (i32.const 9)) "uninitialized element") +(assert_trap (invoke "check" (i32.const 10)) "uninitialized element") +(assert_trap (invoke "check" (i32.const 11)) "uninitialized element") +(assert_return (invoke "check" (i32.const 12)) (i32.const 7)) +(assert_return (invoke "check" (i32.const 13)) (i32.const 5)) +(assert_return (invoke "check" (i32.const 14)) (i32.const 2)) +(assert_return (invoke "check" (i32.const 15)) (i32.const 3)) +(assert_return (invoke "check" (i32.const 16)) (i32.const 6)) +(assert_trap (invoke "check" (i32.const 17)) "uninitialized element") +(assert_trap (invoke "check" (i32.const 18)) "uninitialized element") +(assert_trap (invoke "check" (i32.const 19)) "uninitialized element") +(assert_trap (invoke "check" (i32.const 20)) "uninitialized element") +(assert_trap (invoke "check" (i32.const 21)) "uninitialized element") +(assert_trap (invoke "check" (i32.const 22)) "uninitialized element") +(assert_trap (invoke "check" (i32.const 23)) "uninitialized element") +(assert_trap (invoke "check" (i32.const 24)) "uninitialized element") +(assert_return (invoke "check" (i32.const 25)) (i32.const 3)) +(assert_return (invoke "check" (i32.const 26)) (i32.const 6)) +(assert_trap (invoke "check" (i32.const 27)) "uninitialized element") +(assert_trap (invoke "check" (i32.const 28)) "uninitialized element") +(assert_trap (invoke "check" (i32.const 29)) "uninitialized element") + +(module + (type (func (result i32))) ;; type #0 + (import "a" "ef0" (func (result i32))) ;; index 0 + (import "a" "ef1" (func (result i32))) + (import "a" "ef2" (func (result i32))) + (import "a" "ef3" (func (result i32))) + (import "a" "ef4" (func (result i32))) ;; index 4 + (table 30 30 funcref) + (elem (i32.const 2) 3 1 4 1) + (elem funcref + (ref.func 2) (ref.func 7) (ref.func 1) (ref.func 8)) + (elem (i32.const 12) 7 5 2 3 6) + (elem funcref + (ref.func 5) (ref.func 9) (ref.func 2) (ref.func 7) (ref.func 6)) + (func (result i32) (i32.const 5)) ;; index 5 + (func (result i32) (i32.const 6)) + (func (result i32) (i32.const 7)) + (func (result i32) (i32.const 8)) + (func (result i32) (i32.const 9)) ;; index 9 + (func (export "test") + (table.copy (i32.const 13) (i32.const 25) (i32.const 3))) + (func (export "check") (param i32) (result i32) + (call_indirect (type 0) (local.get 0))) +) + +(invoke "test") +(assert_trap (invoke "check" (i32.const 0)) "uninitialized element") +(assert_trap (invoke "check" (i32.const 1)) "uninitialized element") +(assert_return (invoke "check" (i32.const 2)) (i32.const 3)) +(assert_return (invoke "check" (i32.const 3)) (i32.const 1)) +(assert_return (invoke "check" (i32.const 4)) (i32.const 4)) +(assert_return (invoke "check" (i32.const 5)) (i32.const 1)) +(assert_trap (invoke "check" (i32.const 6)) "uninitialized element") +(assert_trap (invoke "check" (i32.const 7)) "uninitialized element") +(assert_trap (invoke "check" (i32.const 8)) "uninitialized element") +(assert_trap (invoke "check" (i32.const 9)) "uninitialized element") +(assert_trap (invoke "check" (i32.const 10)) "uninitialized element") +(assert_trap (invoke "check" (i32.const 11)) "uninitialized element") +(assert_return (invoke "check" (i32.const 12)) (i32.const 7)) +(assert_trap (invoke "check" (i32.const 13)) "uninitialized element") +(assert_trap (invoke "check" (i32.const 14)) "uninitialized element") +(assert_trap (invoke "check" (i32.const 15)) "uninitialized element") +(assert_return (invoke "check" (i32.const 16)) (i32.const 6)) +(assert_trap (invoke "check" (i32.const 17)) "uninitialized element") +(assert_trap (invoke "check" (i32.const 18)) "uninitialized element") +(assert_trap (invoke "check" (i32.const 19)) "uninitialized element") +(assert_trap (invoke "check" (i32.const 20)) "uninitialized element") +(assert_trap (invoke "check" (i32.const 21)) "uninitialized element") +(assert_trap (invoke "check" (i32.const 22)) "uninitialized element") +(assert_trap (invoke "check" (i32.const 23)) "uninitialized element") +(assert_trap (invoke "check" (i32.const 24)) "uninitialized element") +(assert_trap (invoke "check" (i32.const 25)) "uninitialized element") +(assert_trap (invoke "check" (i32.const 26)) "uninitialized element") +(assert_trap (invoke "check" (i32.const 27)) "uninitialized element") +(assert_trap (invoke "check" (i32.const 28)) "uninitialized element") +(assert_trap (invoke "check" (i32.const 29)) "uninitialized element") + +(module + (type (func (result i32))) ;; type #0 + (import "a" "ef0" (func (result i32))) ;; index 0 + (import "a" "ef1" (func (result i32))) + (import "a" "ef2" (func (result i32))) + (import "a" "ef3" (func (result i32))) + (import "a" "ef4" (func (result i32))) ;; index 4 + (table 30 30 funcref) + (elem (i32.const 2) 3 1 4 1) + (elem funcref + (ref.func 2) (ref.func 7) (ref.func 1) (ref.func 8)) + (elem (i32.const 12) 7 5 2 3 6) + (elem funcref + (ref.func 5) (ref.func 9) (ref.func 2) (ref.func 7) (ref.func 6)) + (func (result i32) (i32.const 5)) ;; index 5 + (func (result i32) (i32.const 6)) + (func (result i32) (i32.const 7)) + (func (result i32) (i32.const 8)) + (func (result i32) (i32.const 9)) ;; index 9 + (func (export "test") + (table.copy (i32.const 20) (i32.const 22) (i32.const 4))) + (func (export "check") (param i32) (result i32) + (call_indirect (type 0) (local.get 0))) +) + +(invoke "test") +(assert_trap (invoke "check" (i32.const 0)) "uninitialized element") +(assert_trap (invoke "check" (i32.const 1)) "uninitialized element") +(assert_return (invoke "check" (i32.const 2)) (i32.const 3)) +(assert_return (invoke "check" (i32.const 3)) (i32.const 1)) +(assert_return (invoke "check" (i32.const 4)) (i32.const 4)) +(assert_return (invoke "check" (i32.const 5)) (i32.const 1)) +(assert_trap (invoke "check" (i32.const 6)) "uninitialized element") +(assert_trap (invoke "check" (i32.const 7)) "uninitialized element") +(assert_trap (invoke "check" (i32.const 8)) "uninitialized element") +(assert_trap (invoke "check" (i32.const 9)) "uninitialized element") +(assert_trap (invoke "check" (i32.const 10)) "uninitialized element") +(assert_trap (invoke "check" (i32.const 11)) "uninitialized element") +(assert_return (invoke "check" (i32.const 12)) (i32.const 7)) +(assert_return (invoke "check" (i32.const 13)) (i32.const 5)) +(assert_return (invoke "check" (i32.const 14)) (i32.const 2)) +(assert_return (invoke "check" (i32.const 15)) (i32.const 3)) +(assert_return (invoke "check" (i32.const 16)) (i32.const 6)) +(assert_trap (invoke "check" (i32.const 17)) "uninitialized element") +(assert_trap (invoke "check" (i32.const 18)) "uninitialized element") +(assert_trap (invoke "check" (i32.const 19)) "uninitialized element") +(assert_trap (invoke "check" (i32.const 20)) "uninitialized element") +(assert_trap (invoke "check" (i32.const 21)) "uninitialized element") +(assert_trap (invoke "check" (i32.const 22)) "uninitialized element") +(assert_trap (invoke "check" (i32.const 23)) "uninitialized element") +(assert_trap (invoke "check" (i32.const 24)) "uninitialized element") +(assert_trap (invoke "check" (i32.const 25)) "uninitialized element") +(assert_trap (invoke "check" (i32.const 26)) "uninitialized element") +(assert_trap (invoke "check" (i32.const 27)) "uninitialized element") +(assert_trap (invoke "check" (i32.const 28)) "uninitialized element") +(assert_trap (invoke "check" (i32.const 29)) "uninitialized element") + +(module + (type (func (result i32))) ;; type #0 + (import "a" "ef0" (func (result i32))) ;; index 0 + (import "a" "ef1" (func (result i32))) + (import "a" "ef2" (func (result i32))) + (import "a" "ef3" (func (result i32))) + (import "a" "ef4" (func (result i32))) ;; index 4 + (table 30 30 funcref) + (elem (i32.const 2) 3 1 4 1) + (elem funcref + (ref.func 2) (ref.func 7) (ref.func 1) (ref.func 8)) + (elem (i32.const 12) 7 5 2 3 6) + (elem funcref + (ref.func 5) (ref.func 9) (ref.func 2) (ref.func 7) (ref.func 6)) + (func (result i32) (i32.const 5)) ;; index 5 + (func (result i32) (i32.const 6)) + (func (result i32) (i32.const 7)) + (func (result i32) (i32.const 8)) + (func (result i32) (i32.const 9)) ;; index 9 + (func (export "test") + (table.copy (i32.const 25) (i32.const 1) (i32.const 3))) + (func (export "check") (param i32) (result i32) + (call_indirect (type 0) (local.get 0))) +) + +(invoke "test") +(assert_trap (invoke "check" (i32.const 0)) "uninitialized element") +(assert_trap (invoke "check" (i32.const 1)) "uninitialized element") +(assert_return (invoke "check" (i32.const 2)) (i32.const 3)) +(assert_return (invoke "check" (i32.const 3)) (i32.const 1)) +(assert_return (invoke "check" (i32.const 4)) (i32.const 4)) +(assert_return (invoke "check" (i32.const 5)) (i32.const 1)) +(assert_trap (invoke "check" (i32.const 6)) "uninitialized element") +(assert_trap (invoke "check" (i32.const 7)) "uninitialized element") +(assert_trap (invoke "check" (i32.const 8)) "uninitialized element") +(assert_trap (invoke "check" (i32.const 9)) "uninitialized element") +(assert_trap (invoke "check" (i32.const 10)) "uninitialized element") +(assert_trap (invoke "check" (i32.const 11)) "uninitialized element") +(assert_return (invoke "check" (i32.const 12)) (i32.const 7)) +(assert_return (invoke "check" (i32.const 13)) (i32.const 5)) +(assert_return (invoke "check" (i32.const 14)) (i32.const 2)) +(assert_return (invoke "check" (i32.const 15)) (i32.const 3)) +(assert_return (invoke "check" (i32.const 16)) (i32.const 6)) +(assert_trap (invoke "check" (i32.const 17)) "uninitialized element") +(assert_trap (invoke "check" (i32.const 18)) "uninitialized element") +(assert_trap (invoke "check" (i32.const 19)) "uninitialized element") +(assert_trap (invoke "check" (i32.const 20)) "uninitialized element") +(assert_trap (invoke "check" (i32.const 21)) "uninitialized element") +(assert_trap (invoke "check" (i32.const 22)) "uninitialized element") +(assert_trap (invoke "check" (i32.const 23)) "uninitialized element") +(assert_trap (invoke "check" (i32.const 24)) "uninitialized element") +(assert_trap (invoke "check" (i32.const 25)) "uninitialized element") +(assert_return (invoke "check" (i32.const 26)) (i32.const 3)) +(assert_return (invoke "check" (i32.const 27)) (i32.const 1)) +(assert_trap (invoke "check" (i32.const 28)) "uninitialized element") +(assert_trap (invoke "check" (i32.const 29)) "uninitialized element") + +(module + (type (func (result i32))) ;; type #0 + (import "a" "ef0" (func (result i32))) ;; index 0 + (import "a" "ef1" (func (result i32))) + (import "a" "ef2" (func (result i32))) + (import "a" "ef3" (func (result i32))) + (import "a" "ef4" (func (result i32))) ;; index 4 + (table 30 30 funcref) + (elem (i32.const 2) 3 1 4 1) + (elem funcref + (ref.func 2) (ref.func 7) (ref.func 1) (ref.func 8)) + (elem (i32.const 12) 7 5 2 3 6) + (elem funcref + (ref.func 5) (ref.func 9) (ref.func 2) (ref.func 7) (ref.func 6)) + (func (result i32) (i32.const 5)) ;; index 5 + (func (result i32) (i32.const 6)) + (func (result i32) (i32.const 7)) + (func (result i32) (i32.const 8)) + (func (result i32) (i32.const 9)) ;; index 9 + (func (export "test") + (table.copy (i32.const 10) (i32.const 12) (i32.const 7))) + (func (export "check") (param i32) (result i32) + (call_indirect (type 0) (local.get 0))) +) + +(invoke "test") +(assert_trap (invoke "check" (i32.const 0)) "uninitialized element") +(assert_trap (invoke "check" (i32.const 1)) "uninitialized element") +(assert_return (invoke "check" (i32.const 2)) (i32.const 3)) +(assert_return (invoke "check" (i32.const 3)) (i32.const 1)) +(assert_return (invoke "check" (i32.const 4)) (i32.const 4)) +(assert_return (invoke "check" (i32.const 5)) (i32.const 1)) +(assert_trap (invoke "check" (i32.const 6)) "uninitialized element") +(assert_trap (invoke "check" (i32.const 7)) "uninitialized element") +(assert_trap (invoke "check" (i32.const 8)) "uninitialized element") +(assert_trap (invoke "check" (i32.const 9)) "uninitialized element") +(assert_return (invoke "check" (i32.const 10)) (i32.const 7)) +(assert_return (invoke "check" (i32.const 11)) (i32.const 5)) +(assert_return (invoke "check" (i32.const 12)) (i32.const 2)) +(assert_return (invoke "check" (i32.const 13)) (i32.const 3)) +(assert_return (invoke "check" (i32.const 14)) (i32.const 6)) +(assert_trap (invoke "check" (i32.const 15)) "uninitialized element") +(assert_trap (invoke "check" (i32.const 16)) "uninitialized element") +(assert_trap (invoke "check" (i32.const 17)) "uninitialized element") +(assert_trap (invoke "check" (i32.const 18)) "uninitialized element") +(assert_trap (invoke "check" (i32.const 19)) "uninitialized element") +(assert_trap (invoke "check" (i32.const 20)) "uninitialized element") +(assert_trap (invoke "check" (i32.const 21)) "uninitialized element") +(assert_trap (invoke "check" (i32.const 22)) "uninitialized element") +(assert_trap (invoke "check" (i32.const 23)) "uninitialized element") +(assert_trap (invoke "check" (i32.const 24)) "uninitialized element") +(assert_trap (invoke "check" (i32.const 25)) "uninitialized element") +(assert_trap (invoke "check" (i32.const 26)) "uninitialized element") +(assert_trap (invoke "check" (i32.const 27)) "uninitialized element") +(assert_trap (invoke "check" (i32.const 28)) "uninitialized element") +(assert_trap (invoke "check" (i32.const 29)) "uninitialized element") + +(module + (type (func (result i32))) ;; type #0 + (import "a" "ef0" (func (result i32))) ;; index 0 + (import "a" "ef1" (func (result i32))) + (import "a" "ef2" (func (result i32))) + (import "a" "ef3" (func (result i32))) + (import "a" "ef4" (func (result i32))) ;; index 4 + (table 30 30 funcref) + (elem (i32.const 2) 3 1 4 1) + (elem funcref + (ref.func 2) (ref.func 7) (ref.func 1) (ref.func 8)) + (elem (i32.const 12) 7 5 2 3 6) + (elem funcref + (ref.func 5) (ref.func 9) (ref.func 2) (ref.func 7) (ref.func 6)) + (func (result i32) (i32.const 5)) ;; index 5 + (func (result i32) (i32.const 6)) + (func (result i32) (i32.const 7)) + (func (result i32) (i32.const 8)) + (func (result i32) (i32.const 9)) ;; index 9 + (func (export "test") + (table.copy (i32.const 12) (i32.const 10) (i32.const 7))) + (func (export "check") (param i32) (result i32) + (call_indirect (type 0) (local.get 0))) +) + +(invoke "test") +(assert_trap (invoke "check" (i32.const 0)) "uninitialized element") +(assert_trap (invoke "check" (i32.const 1)) "uninitialized element") +(assert_return (invoke "check" (i32.const 2)) (i32.const 3)) +(assert_return (invoke "check" (i32.const 3)) (i32.const 1)) +(assert_return (invoke "check" (i32.const 4)) (i32.const 4)) +(assert_return (invoke "check" (i32.const 5)) (i32.const 1)) +(assert_trap (invoke "check" (i32.const 6)) "uninitialized element") +(assert_trap (invoke "check" (i32.const 7)) "uninitialized element") +(assert_trap (invoke "check" (i32.const 8)) "uninitialized element") +(assert_trap (invoke "check" (i32.const 9)) "uninitialized element") +(assert_trap (invoke "check" (i32.const 10)) "uninitialized element") +(assert_trap (invoke "check" (i32.const 11)) "uninitialized element") +(assert_trap (invoke "check" (i32.const 12)) "uninitialized element") +(assert_trap (invoke "check" (i32.const 13)) "uninitialized element") +(assert_return (invoke "check" (i32.const 14)) (i32.const 7)) +(assert_return (invoke "check" (i32.const 15)) (i32.const 5)) +(assert_return (invoke "check" (i32.const 16)) (i32.const 2)) +(assert_return (invoke "check" (i32.const 17)) (i32.const 3)) +(assert_return (invoke "check" (i32.const 18)) (i32.const 6)) +(assert_trap (invoke "check" (i32.const 19)) "uninitialized element") +(assert_trap (invoke "check" (i32.const 20)) "uninitialized element") +(assert_trap (invoke "check" (i32.const 21)) "uninitialized element") +(assert_trap (invoke "check" (i32.const 22)) "uninitialized element") +(assert_trap (invoke "check" (i32.const 23)) "uninitialized element") +(assert_trap (invoke "check" (i32.const 24)) "uninitialized element") +(assert_trap (invoke "check" (i32.const 25)) "uninitialized element") +(assert_trap (invoke "check" (i32.const 26)) "uninitialized element") +(assert_trap (invoke "check" (i32.const 27)) "uninitialized element") +(assert_trap (invoke "check" (i32.const 28)) "uninitialized element") +(assert_trap (invoke "check" (i32.const 29)) "uninitialized element") + +(module + (table 30 30 funcref) + (elem (i32.const 2) 3 1 4 1) + (elem funcref + (ref.func 2) (ref.func 7) (ref.func 1) (ref.func 8)) + (elem (i32.const 12) 7 5 2 3 6) + (elem funcref + (ref.func 5) (ref.func 9) (ref.func 2) (ref.func 7) (ref.func 6)) + (func (result i32) (i32.const 0)) + (func (result i32) (i32.const 1)) + (func (result i32) (i32.const 2)) + (func (result i32) (i32.const 3)) + (func (result i32) (i32.const 4)) + (func (result i32) (i32.const 5)) + (func (result i32) (i32.const 6)) + (func (result i32) (i32.const 7)) + (func (result i32) (i32.const 8)) + (func (result i32) (i32.const 9)) + (func (export "test") + (table.copy (i32.const 28) (i32.const 1) (i32.const 3)) + )) + +(assert_trap (invoke "test") "out of bounds") + +(module + (table 30 30 funcref) + (elem (i32.const 2) 3 1 4 1) + (elem funcref + (ref.func 2) (ref.func 7) (ref.func 1) (ref.func 8)) + (elem (i32.const 12) 7 5 2 3 6) + (elem funcref + (ref.func 5) (ref.func 9) (ref.func 2) (ref.func 7) (ref.func 6)) + (func (result i32) (i32.const 0)) + (func (result i32) (i32.const 1)) + (func (result i32) (i32.const 2)) + (func (result i32) (i32.const 3)) + (func (result i32) (i32.const 4)) + (func (result i32) (i32.const 5)) + (func (result i32) (i32.const 6)) + (func (result i32) (i32.const 7)) + (func (result i32) (i32.const 8)) + (func (result i32) (i32.const 9)) + (func (export "test") + (table.copy (i32.const 0xFFFFFFFE) (i32.const 1) (i32.const 2)) + )) + +(assert_trap (invoke "test") "out of bounds") + +(module + (table 30 30 funcref) + (elem (i32.const 2) 3 1 4 1) + (elem funcref + (ref.func 2) (ref.func 7) (ref.func 1) (ref.func 8)) + (elem (i32.const 12) 7 5 2 3 6) + (elem funcref + (ref.func 5) (ref.func 9) (ref.func 2) (ref.func 7) (ref.func 6)) + (func (result i32) (i32.const 0)) + (func (result i32) (i32.const 1)) + (func (result i32) (i32.const 2)) + (func (result i32) (i32.const 3)) + (func (result i32) (i32.const 4)) + (func (result i32) (i32.const 5)) + (func (result i32) (i32.const 6)) + (func (result i32) (i32.const 7)) + (func (result i32) (i32.const 8)) + (func (result i32) (i32.const 9)) + (func (export "test") + (table.copy (i32.const 15) (i32.const 25) (i32.const 6)) + )) + +(assert_trap (invoke "test") "out of bounds") + +(module + (table 30 30 funcref) + (elem (i32.const 2) 3 1 4 1) + (elem funcref + (ref.func 2) (ref.func 7) (ref.func 1) (ref.func 8)) + (elem (i32.const 12) 7 5 2 3 6) + (elem funcref + (ref.func 5) (ref.func 9) (ref.func 2) (ref.func 7) (ref.func 6)) + (func (result i32) (i32.const 0)) + (func (result i32) (i32.const 1)) + (func (result i32) (i32.const 2)) + (func (result i32) (i32.const 3)) + (func (result i32) (i32.const 4)) + (func (result i32) (i32.const 5)) + (func (result i32) (i32.const 6)) + (func (result i32) (i32.const 7)) + (func (result i32) (i32.const 8)) + (func (result i32) (i32.const 9)) + (func (export "test") + (table.copy (i32.const 15) (i32.const 0xFFFFFFFE) (i32.const 2)) + )) + +(assert_trap (invoke "test") "out of bounds") + +(module + (table 30 30 funcref) + (elem (i32.const 2) 3 1 4 1) + (elem funcref + (ref.func 2) (ref.func 7) (ref.func 1) (ref.func 8)) + (elem (i32.const 12) 7 5 2 3 6) + (elem funcref + (ref.func 5) (ref.func 9) (ref.func 2) (ref.func 7) (ref.func 6)) + (func (result i32) (i32.const 0)) + (func (result i32) (i32.const 1)) + (func (result i32) (i32.const 2)) + (func (result i32) (i32.const 3)) + (func (result i32) (i32.const 4)) + (func (result i32) (i32.const 5)) + (func (result i32) (i32.const 6)) + (func (result i32) (i32.const 7)) + (func (result i32) (i32.const 8)) + (func (result i32) (i32.const 9)) + (func (export "test") + (table.copy (i32.const 15) (i32.const 25) (i32.const 0)) + )) + +(invoke "test") + +(module + (table 30 30 funcref) + (elem (i32.const 2) 3 1 4 1) + (elem funcref + (ref.func 2) (ref.func 7) (ref.func 1) (ref.func 8)) + (elem (i32.const 12) 7 5 2 3 6) + (elem funcref + (ref.func 5) (ref.func 9) (ref.func 2) (ref.func 7) (ref.func 6)) + (func (result i32) (i32.const 0)) + (func (result i32) (i32.const 1)) + (func (result i32) (i32.const 2)) + (func (result i32) (i32.const 3)) + (func (result i32) (i32.const 4)) + (func (result i32) (i32.const 5)) + (func (result i32) (i32.const 6)) + (func (result i32) (i32.const 7)) + (func (result i32) (i32.const 8)) + (func (result i32) (i32.const 9)) + (func (export "test") + (table.copy (i32.const 30) (i32.const 15) (i32.const 0)) + )) + +(invoke "test") + +(module + (table 30 30 funcref) + (elem (i32.const 2) 3 1 4 1) + (elem funcref + (ref.func 2) (ref.func 7) (ref.func 1) (ref.func 8)) + (elem (i32.const 12) 7 5 2 3 6) + (elem funcref + (ref.func 5) (ref.func 9) (ref.func 2) (ref.func 7) (ref.func 6)) + (func (result i32) (i32.const 0)) + (func (result i32) (i32.const 1)) + (func (result i32) (i32.const 2)) + (func (result i32) (i32.const 3)) + (func (result i32) (i32.const 4)) + (func (result i32) (i32.const 5)) + (func (result i32) (i32.const 6)) + (func (result i32) (i32.const 7)) + (func (result i32) (i32.const 8)) + (func (result i32) (i32.const 9)) + (func (export "test") + (table.copy (i32.const 31) (i32.const 15) (i32.const 0)) + )) + +(assert_trap (invoke "test") "out of bounds") + +(module + (table 30 30 funcref) + (elem (i32.const 2) 3 1 4 1) + (elem funcref + (ref.func 2) (ref.func 7) (ref.func 1) (ref.func 8)) + (elem (i32.const 12) 7 5 2 3 6) + (elem funcref + (ref.func 5) (ref.func 9) (ref.func 2) (ref.func 7) (ref.func 6)) + (func (result i32) (i32.const 0)) + (func (result i32) (i32.const 1)) + (func (result i32) (i32.const 2)) + (func (result i32) (i32.const 3)) + (func (result i32) (i32.const 4)) + (func (result i32) (i32.const 5)) + (func (result i32) (i32.const 6)) + (func (result i32) (i32.const 7)) + (func (result i32) (i32.const 8)) + (func (result i32) (i32.const 9)) + (func (export "test") + (table.copy (i32.const 15) (i32.const 30) (i32.const 0)) + )) + +(invoke "test") + +(module + (table 30 30 funcref) + (elem (i32.const 2) 3 1 4 1) + (elem funcref + (ref.func 2) (ref.func 7) (ref.func 1) (ref.func 8)) + (elem (i32.const 12) 7 5 2 3 6) + (elem funcref + (ref.func 5) (ref.func 9) (ref.func 2) (ref.func 7) (ref.func 6)) + (func (result i32) (i32.const 0)) + (func (result i32) (i32.const 1)) + (func (result i32) (i32.const 2)) + (func (result i32) (i32.const 3)) + (func (result i32) (i32.const 4)) + (func (result i32) (i32.const 5)) + (func (result i32) (i32.const 6)) + (func (result i32) (i32.const 7)) + (func (result i32) (i32.const 8)) + (func (result i32) (i32.const 9)) + (func (export "test") + (table.copy (i32.const 15) (i32.const 31) (i32.const 0)) + )) + +(assert_trap (invoke "test") "out of bounds") + +(module + (table 30 30 funcref) + (elem (i32.const 2) 3 1 4 1) + (elem funcref + (ref.func 2) (ref.func 7) (ref.func 1) (ref.func 8)) + (elem (i32.const 12) 7 5 2 3 6) + (elem funcref + (ref.func 5) (ref.func 9) (ref.func 2) (ref.func 7) (ref.func 6)) + (func (result i32) (i32.const 0)) + (func (result i32) (i32.const 1)) + (func (result i32) (i32.const 2)) + (func (result i32) (i32.const 3)) + (func (result i32) (i32.const 4)) + (func (result i32) (i32.const 5)) + (func (result i32) (i32.const 6)) + (func (result i32) (i32.const 7)) + (func (result i32) (i32.const 8)) + (func (result i32) (i32.const 9)) + (func (export "test") + (table.copy (i32.const 30) (i32.const 30) (i32.const 0)) + )) + +(invoke "test") + +(module + (table 30 30 funcref) + (elem (i32.const 2) 3 1 4 1) + (elem funcref + (ref.func 2) (ref.func 7) (ref.func 1) (ref.func 8)) + (elem (i32.const 12) 7 5 2 3 6) + (elem funcref + (ref.func 5) (ref.func 9) (ref.func 2) (ref.func 7) (ref.func 6)) + (func (result i32) (i32.const 0)) + (func (result i32) (i32.const 1)) + (func (result i32) (i32.const 2)) + (func (result i32) (i32.const 3)) + (func (result i32) (i32.const 4)) + (func (result i32) (i32.const 5)) + (func (result i32) (i32.const 6)) + (func (result i32) (i32.const 7)) + (func (result i32) (i32.const 8)) + (func (result i32) (i32.const 9)) + (func (export "test") + (table.copy (i32.const 31) (i32.const 31) (i32.const 0)) + )) + +(assert_trap (invoke "test") "out of bounds") + +(module + (type (func (result i32))) + (table 32 64 funcref) + (elem (i32.const 0) + $f0 $f1 $f2 $f3 $f4 $f5 $f6 $f7) + (func $f0 (export "f0") (result i32) (i32.const 0)) + (func $f1 (export "f1") (result i32) (i32.const 1)) + (func $f2 (export "f2") (result i32) (i32.const 2)) + (func $f3 (export "f3") (result i32) (i32.const 3)) + (func $f4 (export "f4") (result i32) (i32.const 4)) + (func $f5 (export "f5") (result i32) (i32.const 5)) + (func $f6 (export "f6") (result i32) (i32.const 6)) + (func $f7 (export "f7") (result i32) (i32.const 7)) + (func $f8 (export "f8") (result i32) (i32.const 8)) + (func $f9 (export "f9") (result i32) (i32.const 9)) + (func $f10 (export "f10") (result i32) (i32.const 10)) + (func $f11 (export "f11") (result i32) (i32.const 11)) + (func $f12 (export "f12") (result i32) (i32.const 12)) + (func $f13 (export "f13") (result i32) (i32.const 13)) + (func $f14 (export "f14") (result i32) (i32.const 14)) + (func $f15 (export "f15") (result i32) (i32.const 15)) + (func (export "test") (param $n i32) (result i32) + (call_indirect (type 0) (local.get $n))) + (func (export "run") (param $targetOffs i32) (param $srcOffs i32) (param $len i32) + (table.copy (local.get $targetOffs) (local.get $srcOffs) (local.get $len)))) + +(assert_trap (invoke "run" (i32.const 24) (i32.const 0) (i32.const 16)) + "out of bounds") +(assert_return (invoke "test" (i32.const 0)) (i32.const 0)) +(assert_return (invoke "test" (i32.const 1)) (i32.const 1)) +(assert_return (invoke "test" (i32.const 2)) (i32.const 2)) +(assert_return (invoke "test" (i32.const 3)) (i32.const 3)) +(assert_return (invoke "test" (i32.const 4)) (i32.const 4)) +(assert_return (invoke "test" (i32.const 5)) (i32.const 5)) +(assert_return (invoke "test" (i32.const 6)) (i32.const 6)) +(assert_return (invoke "test" (i32.const 7)) (i32.const 7)) +(assert_trap (invoke "test" (i32.const 8)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 9)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 10)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 11)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 12)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 13)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 14)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 15)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 16)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 17)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 18)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 19)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 20)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 21)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 22)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 23)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 24)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 25)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 26)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 27)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 28)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 29)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 30)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 31)) "uninitialized element") + +(module + (type (func (result i32))) + (table 32 64 funcref) + (elem (i32.const 0) + $f0 $f1 $f2 $f3 $f4 $f5 $f6 $f7 $f8) + (func $f0 (export "f0") (result i32) (i32.const 0)) + (func $f1 (export "f1") (result i32) (i32.const 1)) + (func $f2 (export "f2") (result i32) (i32.const 2)) + (func $f3 (export "f3") (result i32) (i32.const 3)) + (func $f4 (export "f4") (result i32) (i32.const 4)) + (func $f5 (export "f5") (result i32) (i32.const 5)) + (func $f6 (export "f6") (result i32) (i32.const 6)) + (func $f7 (export "f7") (result i32) (i32.const 7)) + (func $f8 (export "f8") (result i32) (i32.const 8)) + (func $f9 (export "f9") (result i32) (i32.const 9)) + (func $f10 (export "f10") (result i32) (i32.const 10)) + (func $f11 (export "f11") (result i32) (i32.const 11)) + (func $f12 (export "f12") (result i32) (i32.const 12)) + (func $f13 (export "f13") (result i32) (i32.const 13)) + (func $f14 (export "f14") (result i32) (i32.const 14)) + (func $f15 (export "f15") (result i32) (i32.const 15)) + (func (export "test") (param $n i32) (result i32) + (call_indirect (type 0) (local.get $n))) + (func (export "run") (param $targetOffs i32) (param $srcOffs i32) (param $len i32) + (table.copy (local.get $targetOffs) (local.get $srcOffs) (local.get $len)))) + +(assert_trap (invoke "run" (i32.const 23) (i32.const 0) (i32.const 15)) + "out of bounds") +(assert_return (invoke "test" (i32.const 0)) (i32.const 0)) +(assert_return (invoke "test" (i32.const 1)) (i32.const 1)) +(assert_return (invoke "test" (i32.const 2)) (i32.const 2)) +(assert_return (invoke "test" (i32.const 3)) (i32.const 3)) +(assert_return (invoke "test" (i32.const 4)) (i32.const 4)) +(assert_return (invoke "test" (i32.const 5)) (i32.const 5)) +(assert_return (invoke "test" (i32.const 6)) (i32.const 6)) +(assert_return (invoke "test" (i32.const 7)) (i32.const 7)) +(assert_return (invoke "test" (i32.const 8)) (i32.const 8)) +(assert_trap (invoke "test" (i32.const 9)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 10)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 11)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 12)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 13)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 14)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 15)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 16)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 17)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 18)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 19)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 20)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 21)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 22)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 23)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 24)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 25)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 26)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 27)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 28)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 29)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 30)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 31)) "uninitialized element") + +(module + (type (func (result i32))) + (table 32 64 funcref) + (elem (i32.const 24) + $f0 $f1 $f2 $f3 $f4 $f5 $f6 $f7) + (func $f0 (export "f0") (result i32) (i32.const 0)) + (func $f1 (export "f1") (result i32) (i32.const 1)) + (func $f2 (export "f2") (result i32) (i32.const 2)) + (func $f3 (export "f3") (result i32) (i32.const 3)) + (func $f4 (export "f4") (result i32) (i32.const 4)) + (func $f5 (export "f5") (result i32) (i32.const 5)) + (func $f6 (export "f6") (result i32) (i32.const 6)) + (func $f7 (export "f7") (result i32) (i32.const 7)) + (func $f8 (export "f8") (result i32) (i32.const 8)) + (func $f9 (export "f9") (result i32) (i32.const 9)) + (func $f10 (export "f10") (result i32) (i32.const 10)) + (func $f11 (export "f11") (result i32) (i32.const 11)) + (func $f12 (export "f12") (result i32) (i32.const 12)) + (func $f13 (export "f13") (result i32) (i32.const 13)) + (func $f14 (export "f14") (result i32) (i32.const 14)) + (func $f15 (export "f15") (result i32) (i32.const 15)) + (func (export "test") (param $n i32) (result i32) + (call_indirect (type 0) (local.get $n))) + (func (export "run") (param $targetOffs i32) (param $srcOffs i32) (param $len i32) + (table.copy (local.get $targetOffs) (local.get $srcOffs) (local.get $len)))) + +(assert_trap (invoke "run" (i32.const 0) (i32.const 24) (i32.const 16)) + "out of bounds") +(assert_trap (invoke "test" (i32.const 0)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 1)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 2)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 3)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 4)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 5)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 6)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 7)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 8)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 9)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 10)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 11)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 12)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 13)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 14)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 15)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 16)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 17)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 18)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 19)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 20)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 21)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 22)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 23)) "uninitialized element") +(assert_return (invoke "test" (i32.const 24)) (i32.const 0)) +(assert_return (invoke "test" (i32.const 25)) (i32.const 1)) +(assert_return (invoke "test" (i32.const 26)) (i32.const 2)) +(assert_return (invoke "test" (i32.const 27)) (i32.const 3)) +(assert_return (invoke "test" (i32.const 28)) (i32.const 4)) +(assert_return (invoke "test" (i32.const 29)) (i32.const 5)) +(assert_return (invoke "test" (i32.const 30)) (i32.const 6)) +(assert_return (invoke "test" (i32.const 31)) (i32.const 7)) + +(module + (type (func (result i32))) + (table 32 64 funcref) + (elem (i32.const 23) + $f0 $f1 $f2 $f3 $f4 $f5 $f6 $f7 $f8) + (func $f0 (export "f0") (result i32) (i32.const 0)) + (func $f1 (export "f1") (result i32) (i32.const 1)) + (func $f2 (export "f2") (result i32) (i32.const 2)) + (func $f3 (export "f3") (result i32) (i32.const 3)) + (func $f4 (export "f4") (result i32) (i32.const 4)) + (func $f5 (export "f5") (result i32) (i32.const 5)) + (func $f6 (export "f6") (result i32) (i32.const 6)) + (func $f7 (export "f7") (result i32) (i32.const 7)) + (func $f8 (export "f8") (result i32) (i32.const 8)) + (func $f9 (export "f9") (result i32) (i32.const 9)) + (func $f10 (export "f10") (result i32) (i32.const 10)) + (func $f11 (export "f11") (result i32) (i32.const 11)) + (func $f12 (export "f12") (result i32) (i32.const 12)) + (func $f13 (export "f13") (result i32) (i32.const 13)) + (func $f14 (export "f14") (result i32) (i32.const 14)) + (func $f15 (export "f15") (result i32) (i32.const 15)) + (func (export "test") (param $n i32) (result i32) + (call_indirect (type 0) (local.get $n))) + (func (export "run") (param $targetOffs i32) (param $srcOffs i32) (param $len i32) + (table.copy (local.get $targetOffs) (local.get $srcOffs) (local.get $len)))) + +(assert_trap (invoke "run" (i32.const 0) (i32.const 23) (i32.const 15)) + "out of bounds") +(assert_trap (invoke "test" (i32.const 0)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 1)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 2)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 3)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 4)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 5)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 6)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 7)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 8)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 9)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 10)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 11)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 12)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 13)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 14)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 15)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 16)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 17)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 18)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 19)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 20)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 21)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 22)) "uninitialized element") +(assert_return (invoke "test" (i32.const 23)) (i32.const 0)) +(assert_return (invoke "test" (i32.const 24)) (i32.const 1)) +(assert_return (invoke "test" (i32.const 25)) (i32.const 2)) +(assert_return (invoke "test" (i32.const 26)) (i32.const 3)) +(assert_return (invoke "test" (i32.const 27)) (i32.const 4)) +(assert_return (invoke "test" (i32.const 28)) (i32.const 5)) +(assert_return (invoke "test" (i32.const 29)) (i32.const 6)) +(assert_return (invoke "test" (i32.const 30)) (i32.const 7)) +(assert_return (invoke "test" (i32.const 31)) (i32.const 8)) + +(module + (type (func (result i32))) + (table 32 64 funcref) + (elem (i32.const 11) + $f0 $f1 $f2 $f3 $f4 $f5 $f6 $f7) + (func $f0 (export "f0") (result i32) (i32.const 0)) + (func $f1 (export "f1") (result i32) (i32.const 1)) + (func $f2 (export "f2") (result i32) (i32.const 2)) + (func $f3 (export "f3") (result i32) (i32.const 3)) + (func $f4 (export "f4") (result i32) (i32.const 4)) + (func $f5 (export "f5") (result i32) (i32.const 5)) + (func $f6 (export "f6") (result i32) (i32.const 6)) + (func $f7 (export "f7") (result i32) (i32.const 7)) + (func $f8 (export "f8") (result i32) (i32.const 8)) + (func $f9 (export "f9") (result i32) (i32.const 9)) + (func $f10 (export "f10") (result i32) (i32.const 10)) + (func $f11 (export "f11") (result i32) (i32.const 11)) + (func $f12 (export "f12") (result i32) (i32.const 12)) + (func $f13 (export "f13") (result i32) (i32.const 13)) + (func $f14 (export "f14") (result i32) (i32.const 14)) + (func $f15 (export "f15") (result i32) (i32.const 15)) + (func (export "test") (param $n i32) (result i32) + (call_indirect (type 0) (local.get $n))) + (func (export "run") (param $targetOffs i32) (param $srcOffs i32) (param $len i32) + (table.copy (local.get $targetOffs) (local.get $srcOffs) (local.get $len)))) + +(assert_trap (invoke "run" (i32.const 24) (i32.const 11) (i32.const 16)) + "out of bounds") +(assert_trap (invoke "test" (i32.const 0)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 1)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 2)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 3)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 4)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 5)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 6)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 7)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 8)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 9)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 10)) "uninitialized element") +(assert_return (invoke "test" (i32.const 11)) (i32.const 0)) +(assert_return (invoke "test" (i32.const 12)) (i32.const 1)) +(assert_return (invoke "test" (i32.const 13)) (i32.const 2)) +(assert_return (invoke "test" (i32.const 14)) (i32.const 3)) +(assert_return (invoke "test" (i32.const 15)) (i32.const 4)) +(assert_return (invoke "test" (i32.const 16)) (i32.const 5)) +(assert_return (invoke "test" (i32.const 17)) (i32.const 6)) +(assert_return (invoke "test" (i32.const 18)) (i32.const 7)) +(assert_trap (invoke "test" (i32.const 19)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 20)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 21)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 22)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 23)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 24)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 25)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 26)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 27)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 28)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 29)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 30)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 31)) "uninitialized element") + +(module + (type (func (result i32))) + (table 32 64 funcref) + (elem (i32.const 24) + $f0 $f1 $f2 $f3 $f4 $f5 $f6 $f7) + (func $f0 (export "f0") (result i32) (i32.const 0)) + (func $f1 (export "f1") (result i32) (i32.const 1)) + (func $f2 (export "f2") (result i32) (i32.const 2)) + (func $f3 (export "f3") (result i32) (i32.const 3)) + (func $f4 (export "f4") (result i32) (i32.const 4)) + (func $f5 (export "f5") (result i32) (i32.const 5)) + (func $f6 (export "f6") (result i32) (i32.const 6)) + (func $f7 (export "f7") (result i32) (i32.const 7)) + (func $f8 (export "f8") (result i32) (i32.const 8)) + (func $f9 (export "f9") (result i32) (i32.const 9)) + (func $f10 (export "f10") (result i32) (i32.const 10)) + (func $f11 (export "f11") (result i32) (i32.const 11)) + (func $f12 (export "f12") (result i32) (i32.const 12)) + (func $f13 (export "f13") (result i32) (i32.const 13)) + (func $f14 (export "f14") (result i32) (i32.const 14)) + (func $f15 (export "f15") (result i32) (i32.const 15)) + (func (export "test") (param $n i32) (result i32) + (call_indirect (type 0) (local.get $n))) + (func (export "run") (param $targetOffs i32) (param $srcOffs i32) (param $len i32) + (table.copy (local.get $targetOffs) (local.get $srcOffs) (local.get $len)))) + +(assert_trap (invoke "run" (i32.const 11) (i32.const 24) (i32.const 16)) + "out of bounds") +(assert_trap (invoke "test" (i32.const 0)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 1)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 2)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 3)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 4)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 5)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 6)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 7)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 8)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 9)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 10)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 11)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 12)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 13)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 14)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 15)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 16)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 17)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 18)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 19)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 20)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 21)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 22)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 23)) "uninitialized element") +(assert_return (invoke "test" (i32.const 24)) (i32.const 0)) +(assert_return (invoke "test" (i32.const 25)) (i32.const 1)) +(assert_return (invoke "test" (i32.const 26)) (i32.const 2)) +(assert_return (invoke "test" (i32.const 27)) (i32.const 3)) +(assert_return (invoke "test" (i32.const 28)) (i32.const 4)) +(assert_return (invoke "test" (i32.const 29)) (i32.const 5)) +(assert_return (invoke "test" (i32.const 30)) (i32.const 6)) +(assert_return (invoke "test" (i32.const 31)) (i32.const 7)) + +(module + (type (func (result i32))) + (table 32 64 funcref) + (elem (i32.const 21) + $f0 $f1 $f2 $f3 $f4 $f5 $f6 $f7) + (func $f0 (export "f0") (result i32) (i32.const 0)) + (func $f1 (export "f1") (result i32) (i32.const 1)) + (func $f2 (export "f2") (result i32) (i32.const 2)) + (func $f3 (export "f3") (result i32) (i32.const 3)) + (func $f4 (export "f4") (result i32) (i32.const 4)) + (func $f5 (export "f5") (result i32) (i32.const 5)) + (func $f6 (export "f6") (result i32) (i32.const 6)) + (func $f7 (export "f7") (result i32) (i32.const 7)) + (func $f8 (export "f8") (result i32) (i32.const 8)) + (func $f9 (export "f9") (result i32) (i32.const 9)) + (func $f10 (export "f10") (result i32) (i32.const 10)) + (func $f11 (export "f11") (result i32) (i32.const 11)) + (func $f12 (export "f12") (result i32) (i32.const 12)) + (func $f13 (export "f13") (result i32) (i32.const 13)) + (func $f14 (export "f14") (result i32) (i32.const 14)) + (func $f15 (export "f15") (result i32) (i32.const 15)) + (func (export "test") (param $n i32) (result i32) + (call_indirect (type 0) (local.get $n))) + (func (export "run") (param $targetOffs i32) (param $srcOffs i32) (param $len i32) + (table.copy (local.get $targetOffs) (local.get $srcOffs) (local.get $len)))) + +(assert_trap (invoke "run" (i32.const 24) (i32.const 21) (i32.const 16)) + "out of bounds") +(assert_trap (invoke "test" (i32.const 0)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 1)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 2)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 3)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 4)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 5)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 6)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 7)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 8)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 9)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 10)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 11)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 12)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 13)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 14)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 15)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 16)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 17)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 18)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 19)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 20)) "uninitialized element") +(assert_return (invoke "test" (i32.const 21)) (i32.const 0)) +(assert_return (invoke "test" (i32.const 22)) (i32.const 1)) +(assert_return (invoke "test" (i32.const 23)) (i32.const 2)) +(assert_return (invoke "test" (i32.const 24)) (i32.const 3)) +(assert_return (invoke "test" (i32.const 25)) (i32.const 4)) +(assert_return (invoke "test" (i32.const 26)) (i32.const 5)) +(assert_return (invoke "test" (i32.const 27)) (i32.const 6)) +(assert_return (invoke "test" (i32.const 28)) (i32.const 7)) +(assert_trap (invoke "test" (i32.const 29)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 30)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 31)) "uninitialized element") + +(module + (type (func (result i32))) + (table 32 64 funcref) + (elem (i32.const 24) + $f0 $f1 $f2 $f3 $f4 $f5 $f6 $f7) + (func $f0 (export "f0") (result i32) (i32.const 0)) + (func $f1 (export "f1") (result i32) (i32.const 1)) + (func $f2 (export "f2") (result i32) (i32.const 2)) + (func $f3 (export "f3") (result i32) (i32.const 3)) + (func $f4 (export "f4") (result i32) (i32.const 4)) + (func $f5 (export "f5") (result i32) (i32.const 5)) + (func $f6 (export "f6") (result i32) (i32.const 6)) + (func $f7 (export "f7") (result i32) (i32.const 7)) + (func $f8 (export "f8") (result i32) (i32.const 8)) + (func $f9 (export "f9") (result i32) (i32.const 9)) + (func $f10 (export "f10") (result i32) (i32.const 10)) + (func $f11 (export "f11") (result i32) (i32.const 11)) + (func $f12 (export "f12") (result i32) (i32.const 12)) + (func $f13 (export "f13") (result i32) (i32.const 13)) + (func $f14 (export "f14") (result i32) (i32.const 14)) + (func $f15 (export "f15") (result i32) (i32.const 15)) + (func (export "test") (param $n i32) (result i32) + (call_indirect (type 0) (local.get $n))) + (func (export "run") (param $targetOffs i32) (param $srcOffs i32) (param $len i32) + (table.copy (local.get $targetOffs) (local.get $srcOffs) (local.get $len)))) + +(assert_trap (invoke "run" (i32.const 21) (i32.const 24) (i32.const 16)) + "out of bounds") +(assert_trap (invoke "test" (i32.const 0)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 1)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 2)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 3)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 4)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 5)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 6)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 7)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 8)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 9)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 10)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 11)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 12)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 13)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 14)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 15)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 16)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 17)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 18)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 19)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 20)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 21)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 22)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 23)) "uninitialized element") +(assert_return (invoke "test" (i32.const 24)) (i32.const 0)) +(assert_return (invoke "test" (i32.const 25)) (i32.const 1)) +(assert_return (invoke "test" (i32.const 26)) (i32.const 2)) +(assert_return (invoke "test" (i32.const 27)) (i32.const 3)) +(assert_return (invoke "test" (i32.const 28)) (i32.const 4)) +(assert_return (invoke "test" (i32.const 29)) (i32.const 5)) +(assert_return (invoke "test" (i32.const 30)) (i32.const 6)) +(assert_return (invoke "test" (i32.const 31)) (i32.const 7)) + +(module + (type (func (result i32))) + (table 32 64 funcref) + (elem (i32.const 21) + $f0 $f1 $f2 $f3 $f4 $f5 $f6 $f7 $f8 $f9 $f10) + (func $f0 (export "f0") (result i32) (i32.const 0)) + (func $f1 (export "f1") (result i32) (i32.const 1)) + (func $f2 (export "f2") (result i32) (i32.const 2)) + (func $f3 (export "f3") (result i32) (i32.const 3)) + (func $f4 (export "f4") (result i32) (i32.const 4)) + (func $f5 (export "f5") (result i32) (i32.const 5)) + (func $f6 (export "f6") (result i32) (i32.const 6)) + (func $f7 (export "f7") (result i32) (i32.const 7)) + (func $f8 (export "f8") (result i32) (i32.const 8)) + (func $f9 (export "f9") (result i32) (i32.const 9)) + (func $f10 (export "f10") (result i32) (i32.const 10)) + (func $f11 (export "f11") (result i32) (i32.const 11)) + (func $f12 (export "f12") (result i32) (i32.const 12)) + (func $f13 (export "f13") (result i32) (i32.const 13)) + (func $f14 (export "f14") (result i32) (i32.const 14)) + (func $f15 (export "f15") (result i32) (i32.const 15)) + (func (export "test") (param $n i32) (result i32) + (call_indirect (type 0) (local.get $n))) + (func (export "run") (param $targetOffs i32) (param $srcOffs i32) (param $len i32) + (table.copy (local.get $targetOffs) (local.get $srcOffs) (local.get $len)))) + +(assert_trap (invoke "run" (i32.const 21) (i32.const 21) (i32.const 16)) + "out of bounds") +(assert_trap (invoke "test" (i32.const 0)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 1)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 2)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 3)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 4)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 5)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 6)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 7)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 8)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 9)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 10)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 11)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 12)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 13)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 14)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 15)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 16)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 17)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 18)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 19)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 20)) "uninitialized element") +(assert_return (invoke "test" (i32.const 21)) (i32.const 0)) +(assert_return (invoke "test" (i32.const 22)) (i32.const 1)) +(assert_return (invoke "test" (i32.const 23)) (i32.const 2)) +(assert_return (invoke "test" (i32.const 24)) (i32.const 3)) +(assert_return (invoke "test" (i32.const 25)) (i32.const 4)) +(assert_return (invoke "test" (i32.const 26)) (i32.const 5)) +(assert_return (invoke "test" (i32.const 27)) (i32.const 6)) +(assert_return (invoke "test" (i32.const 28)) (i32.const 7)) +(assert_return (invoke "test" (i32.const 29)) (i32.const 8)) +(assert_return (invoke "test" (i32.const 30)) (i32.const 9)) +(assert_return (invoke "test" (i32.const 31)) (i32.const 10)) + +(module + (type (func (result i32))) + (table 128 128 funcref) + (elem (i32.const 112) + $f0 $f1 $f2 $f3 $f4 $f5 $f6 $f7 $f8 $f9 $f10 $f11 $f12 $f13 $f14 $f15) + (func $f0 (export "f0") (result i32) (i32.const 0)) + (func $f1 (export "f1") (result i32) (i32.const 1)) + (func $f2 (export "f2") (result i32) (i32.const 2)) + (func $f3 (export "f3") (result i32) (i32.const 3)) + (func $f4 (export "f4") (result i32) (i32.const 4)) + (func $f5 (export "f5") (result i32) (i32.const 5)) + (func $f6 (export "f6") (result i32) (i32.const 6)) + (func $f7 (export "f7") (result i32) (i32.const 7)) + (func $f8 (export "f8") (result i32) (i32.const 8)) + (func $f9 (export "f9") (result i32) (i32.const 9)) + (func $f10 (export "f10") (result i32) (i32.const 10)) + (func $f11 (export "f11") (result i32) (i32.const 11)) + (func $f12 (export "f12") (result i32) (i32.const 12)) + (func $f13 (export "f13") (result i32) (i32.const 13)) + (func $f14 (export "f14") (result i32) (i32.const 14)) + (func $f15 (export "f15") (result i32) (i32.const 15)) + (func (export "test") (param $n i32) (result i32) + (call_indirect (type 0) (local.get $n))) + (func (export "run") (param $targetOffs i32) (param $srcOffs i32) (param $len i32) + (table.copy (local.get $targetOffs) (local.get $srcOffs) (local.get $len)))) + +(assert_trap (invoke "run" (i32.const 0) (i32.const 112) (i32.const 4294967264)) + "out of bounds") +(assert_trap (invoke "test" (i32.const 0)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 1)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 2)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 3)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 4)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 5)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 6)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 7)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 8)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 9)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 10)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 11)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 12)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 13)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 14)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 15)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 16)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 17)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 18)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 19)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 20)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 21)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 22)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 23)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 24)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 25)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 26)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 27)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 28)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 29)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 30)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 31)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 32)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 33)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 34)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 35)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 36)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 37)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 38)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 39)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 40)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 41)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 42)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 43)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 44)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 45)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 46)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 47)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 48)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 49)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 50)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 51)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 52)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 53)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 54)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 55)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 56)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 57)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 58)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 59)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 60)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 61)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 62)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 63)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 64)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 65)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 66)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 67)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 68)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 69)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 70)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 71)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 72)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 73)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 74)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 75)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 76)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 77)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 78)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 79)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 80)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 81)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 82)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 83)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 84)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 85)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 86)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 87)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 88)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 89)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 90)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 91)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 92)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 93)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 94)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 95)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 96)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 97)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 98)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 99)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 100)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 101)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 102)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 103)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 104)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 105)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 106)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 107)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 108)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 109)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 110)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 111)) "uninitialized element") +(assert_return (invoke "test" (i32.const 112)) (i32.const 0)) +(assert_return (invoke "test" (i32.const 113)) (i32.const 1)) +(assert_return (invoke "test" (i32.const 114)) (i32.const 2)) +(assert_return (invoke "test" (i32.const 115)) (i32.const 3)) +(assert_return (invoke "test" (i32.const 116)) (i32.const 4)) +(assert_return (invoke "test" (i32.const 117)) (i32.const 5)) +(assert_return (invoke "test" (i32.const 118)) (i32.const 6)) +(assert_return (invoke "test" (i32.const 119)) (i32.const 7)) +(assert_return (invoke "test" (i32.const 120)) (i32.const 8)) +(assert_return (invoke "test" (i32.const 121)) (i32.const 9)) +(assert_return (invoke "test" (i32.const 122)) (i32.const 10)) +(assert_return (invoke "test" (i32.const 123)) (i32.const 11)) +(assert_return (invoke "test" (i32.const 124)) (i32.const 12)) +(assert_return (invoke "test" (i32.const 125)) (i32.const 13)) +(assert_return (invoke "test" (i32.const 126)) (i32.const 14)) +(assert_return (invoke "test" (i32.const 127)) (i32.const 15)) + +(module + (type (func (result i32))) + (table 128 128 funcref) + (elem (i32.const 0) + $f0 $f1 $f2 $f3 $f4 $f5 $f6 $f7 $f8 $f9 $f10 $f11 $f12 $f13 $f14 $f15) + (func $f0 (export "f0") (result i32) (i32.const 0)) + (func $f1 (export "f1") (result i32) (i32.const 1)) + (func $f2 (export "f2") (result i32) (i32.const 2)) + (func $f3 (export "f3") (result i32) (i32.const 3)) + (func $f4 (export "f4") (result i32) (i32.const 4)) + (func $f5 (export "f5") (result i32) (i32.const 5)) + (func $f6 (export "f6") (result i32) (i32.const 6)) + (func $f7 (export "f7") (result i32) (i32.const 7)) + (func $f8 (export "f8") (result i32) (i32.const 8)) + (func $f9 (export "f9") (result i32) (i32.const 9)) + (func $f10 (export "f10") (result i32) (i32.const 10)) + (func $f11 (export "f11") (result i32) (i32.const 11)) + (func $f12 (export "f12") (result i32) (i32.const 12)) + (func $f13 (export "f13") (result i32) (i32.const 13)) + (func $f14 (export "f14") (result i32) (i32.const 14)) + (func $f15 (export "f15") (result i32) (i32.const 15)) + (func (export "test") (param $n i32) (result i32) + (call_indirect (type 0) (local.get $n))) + (func (export "run") (param $targetOffs i32) (param $srcOffs i32) (param $len i32) + (table.copy (local.get $targetOffs) (local.get $srcOffs) (local.get $len)))) + +(assert_trap (invoke "run" (i32.const 112) (i32.const 0) (i32.const 4294967264)) + "out of bounds") +(assert_return (invoke "test" (i32.const 0)) (i32.const 0)) +(assert_return (invoke "test" (i32.const 1)) (i32.const 1)) +(assert_return (invoke "test" (i32.const 2)) (i32.const 2)) +(assert_return (invoke "test" (i32.const 3)) (i32.const 3)) +(assert_return (invoke "test" (i32.const 4)) (i32.const 4)) +(assert_return (invoke "test" (i32.const 5)) (i32.const 5)) +(assert_return (invoke "test" (i32.const 6)) (i32.const 6)) +(assert_return (invoke "test" (i32.const 7)) (i32.const 7)) +(assert_return (invoke "test" (i32.const 8)) (i32.const 8)) +(assert_return (invoke "test" (i32.const 9)) (i32.const 9)) +(assert_return (invoke "test" (i32.const 10)) (i32.const 10)) +(assert_return (invoke "test" (i32.const 11)) (i32.const 11)) +(assert_return (invoke "test" (i32.const 12)) (i32.const 12)) +(assert_return (invoke "test" (i32.const 13)) (i32.const 13)) +(assert_return (invoke "test" (i32.const 14)) (i32.const 14)) +(assert_return (invoke "test" (i32.const 15)) (i32.const 15)) +(assert_trap (invoke "test" (i32.const 16)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 17)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 18)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 19)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 20)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 21)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 22)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 23)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 24)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 25)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 26)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 27)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 28)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 29)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 30)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 31)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 32)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 33)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 34)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 35)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 36)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 37)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 38)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 39)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 40)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 41)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 42)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 43)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 44)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 45)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 46)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 47)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 48)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 49)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 50)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 51)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 52)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 53)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 54)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 55)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 56)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 57)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 58)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 59)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 60)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 61)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 62)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 63)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 64)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 65)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 66)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 67)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 68)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 69)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 70)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 71)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 72)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 73)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 74)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 75)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 76)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 77)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 78)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 79)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 80)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 81)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 82)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 83)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 84)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 85)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 86)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 87)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 88)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 89)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 90)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 91)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 92)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 93)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 94)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 95)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 96)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 97)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 98)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 99)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 100)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 101)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 102)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 103)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 104)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 105)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 106)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 107)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 108)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 109)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 110)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 111)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 112)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 113)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 114)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 115)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 116)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 117)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 118)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 119)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 120)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 121)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 122)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 123)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 124)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 125)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 126)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 127)) "uninitialized element") diff --git a/test/core/table_fill.wast b/test/core/table_fill.wast index 8ec66b69c2..7aff20246c 100644 --- a/test/core/table_fill.wast +++ b/test/core/table_fill.wast @@ -51,8 +51,8 @@ "out of bounds" ) (assert_return (invoke "get" (i32.const 7)) (ref.null)) -(assert_return (invoke "get" (i32.const 8)) (ref.host 6)) -(assert_return (invoke "get" (i32.const 9)) (ref.host 6)) +(assert_return (invoke "get" (i32.const 8)) (ref.host 4)) +(assert_return (invoke "get" (i32.const 9)) (ref.null)) (assert_trap (invoke "fill" (i32.const 11) (ref.null) (i32.const 0)) diff --git a/test/core/table_get.wast b/test/core/table_get.wast index 02855a8311..c95fce7232 100644 --- a/test/core/table_get.wast +++ b/test/core/table_get.wast @@ -1,6 +1,7 @@ (module (table $t2 2 anyref) - (table $t3 3 funcref) (elem $t3 (i32.const 1) $dummy) + (table $t3 3 funcref) + (elem (table $t3) (i32.const 1) func $dummy) (func $dummy) (func (export "init") (param $r anyref) diff --git a/test/core/table_init.wast b/test/core/table_init.wast new file mode 100644 index 0000000000..80eaf065d8 --- /dev/null +++ b/test/core/table_init.wast @@ -0,0 +1,1752 @@ +;; +;; Generated by ../meta/generate_table_init.js +;; + +(module + (func (export "ef0") (result i32) (i32.const 0)) + (func (export "ef1") (result i32) (i32.const 1)) + (func (export "ef2") (result i32) (i32.const 2)) + (func (export "ef3") (result i32) (i32.const 3)) + (func (export "ef4") (result i32) (i32.const 4)) +) +(register "a") + +(module + (type (func (result i32))) ;; type #0 + (import "a" "ef0" (func (result i32))) ;; index 0 + (import "a" "ef1" (func (result i32))) + (import "a" "ef2" (func (result i32))) + (import "a" "ef3" (func (result i32))) + (import "a" "ef4" (func (result i32))) ;; index 4 + (table 30 30 funcref) + (elem (i32.const 2) 3 1 4 1) + (elem funcref + (ref.func 2) (ref.func 7) (ref.func 1) (ref.func 8)) + (elem (i32.const 12) 7 5 2 3 6) + (elem funcref + (ref.func 5) (ref.func 9) (ref.func 2) (ref.func 7) (ref.func 6)) + (func (result i32) (i32.const 5)) ;; index 5 + (func (result i32) (i32.const 6)) + (func (result i32) (i32.const 7)) + (func (result i32) (i32.const 8)) + (func (result i32) (i32.const 9)) ;; index 9 + (func (export "test") + (table.init 1 (i32.const 7) (i32.const 0) (i32.const 4))) + (func (export "check") (param i32) (result i32) + (call_indirect (type 0) (local.get 0))) +) + +(invoke "test") +(assert_trap (invoke "check" (i32.const 0)) "uninitialized element") +(assert_trap (invoke "check" (i32.const 1)) "uninitialized element") +(assert_return (invoke "check" (i32.const 2)) (i32.const 3)) +(assert_return (invoke "check" (i32.const 3)) (i32.const 1)) +(assert_return (invoke "check" (i32.const 4)) (i32.const 4)) +(assert_return (invoke "check" (i32.const 5)) (i32.const 1)) +(assert_trap (invoke "check" (i32.const 6)) "uninitialized element") +(assert_return (invoke "check" (i32.const 7)) (i32.const 2)) +(assert_return (invoke "check" (i32.const 8)) (i32.const 7)) +(assert_return (invoke "check" (i32.const 9)) (i32.const 1)) +(assert_return (invoke "check" (i32.const 10)) (i32.const 8)) +(assert_trap (invoke "check" (i32.const 11)) "uninitialized element") +(assert_return (invoke "check" (i32.const 12)) (i32.const 7)) +(assert_return (invoke "check" (i32.const 13)) (i32.const 5)) +(assert_return (invoke "check" (i32.const 14)) (i32.const 2)) +(assert_return (invoke "check" (i32.const 15)) (i32.const 3)) +(assert_return (invoke "check" (i32.const 16)) (i32.const 6)) +(assert_trap (invoke "check" (i32.const 17)) "uninitialized element") +(assert_trap (invoke "check" (i32.const 18)) "uninitialized element") +(assert_trap (invoke "check" (i32.const 19)) "uninitialized element") +(assert_trap (invoke "check" (i32.const 20)) "uninitialized element") +(assert_trap (invoke "check" (i32.const 21)) "uninitialized element") +(assert_trap (invoke "check" (i32.const 22)) "uninitialized element") +(assert_trap (invoke "check" (i32.const 23)) "uninitialized element") +(assert_trap (invoke "check" (i32.const 24)) "uninitialized element") +(assert_trap (invoke "check" (i32.const 25)) "uninitialized element") +(assert_trap (invoke "check" (i32.const 26)) "uninitialized element") +(assert_trap (invoke "check" (i32.const 27)) "uninitialized element") +(assert_trap (invoke "check" (i32.const 28)) "uninitialized element") +(assert_trap (invoke "check" (i32.const 29)) "uninitialized element") + +(module + (type (func (result i32))) ;; type #0 + (import "a" "ef0" (func (result i32))) ;; index 0 + (import "a" "ef1" (func (result i32))) + (import "a" "ef2" (func (result i32))) + (import "a" "ef3" (func (result i32))) + (import "a" "ef4" (func (result i32))) ;; index 4 + (table 30 30 funcref) + (elem (i32.const 2) 3 1 4 1) + (elem funcref + (ref.func 2) (ref.func 7) (ref.func 1) (ref.func 8)) + (elem (i32.const 12) 7 5 2 3 6) + (elem funcref + (ref.func 5) (ref.func 9) (ref.func 2) (ref.func 7) (ref.func 6)) + (func (result i32) (i32.const 5)) ;; index 5 + (func (result i32) (i32.const 6)) + (func (result i32) (i32.const 7)) + (func (result i32) (i32.const 8)) + (func (result i32) (i32.const 9)) ;; index 9 + (func (export "test") + (table.init 3 (i32.const 15) (i32.const 1) (i32.const 3))) + (func (export "check") (param i32) (result i32) + (call_indirect (type 0) (local.get 0))) +) + +(invoke "test") +(assert_trap (invoke "check" (i32.const 0)) "uninitialized element") +(assert_trap (invoke "check" (i32.const 1)) "uninitialized element") +(assert_return (invoke "check" (i32.const 2)) (i32.const 3)) +(assert_return (invoke "check" (i32.const 3)) (i32.const 1)) +(assert_return (invoke "check" (i32.const 4)) (i32.const 4)) +(assert_return (invoke "check" (i32.const 5)) (i32.const 1)) +(assert_trap (invoke "check" (i32.const 6)) "uninitialized element") +(assert_trap (invoke "check" (i32.const 7)) "uninitialized element") +(assert_trap (invoke "check" (i32.const 8)) "uninitialized element") +(assert_trap (invoke "check" (i32.const 9)) "uninitialized element") +(assert_trap (invoke "check" (i32.const 10)) "uninitialized element") +(assert_trap (invoke "check" (i32.const 11)) "uninitialized element") +(assert_return (invoke "check" (i32.const 12)) (i32.const 7)) +(assert_return (invoke "check" (i32.const 13)) (i32.const 5)) +(assert_return (invoke "check" (i32.const 14)) (i32.const 2)) +(assert_return (invoke "check" (i32.const 15)) (i32.const 9)) +(assert_return (invoke "check" (i32.const 16)) (i32.const 2)) +(assert_return (invoke "check" (i32.const 17)) (i32.const 7)) +(assert_trap (invoke "check" (i32.const 18)) "uninitialized element") +(assert_trap (invoke "check" (i32.const 19)) "uninitialized element") +(assert_trap (invoke "check" (i32.const 20)) "uninitialized element") +(assert_trap (invoke "check" (i32.const 21)) "uninitialized element") +(assert_trap (invoke "check" (i32.const 22)) "uninitialized element") +(assert_trap (invoke "check" (i32.const 23)) "uninitialized element") +(assert_trap (invoke "check" (i32.const 24)) "uninitialized element") +(assert_trap (invoke "check" (i32.const 25)) "uninitialized element") +(assert_trap (invoke "check" (i32.const 26)) "uninitialized element") +(assert_trap (invoke "check" (i32.const 27)) "uninitialized element") +(assert_trap (invoke "check" (i32.const 28)) "uninitialized element") +(assert_trap (invoke "check" (i32.const 29)) "uninitialized element") + +(module + (type (func (result i32))) ;; type #0 + (import "a" "ef0" (func (result i32))) ;; index 0 + (import "a" "ef1" (func (result i32))) + (import "a" "ef2" (func (result i32))) + (import "a" "ef3" (func (result i32))) + (import "a" "ef4" (func (result i32))) ;; index 4 + (table 30 30 funcref) + (elem (i32.const 2) 3 1 4 1) + (elem funcref + (ref.func 2) (ref.func 7) (ref.func 1) (ref.func 8)) + (elem (i32.const 12) 7 5 2 3 6) + (elem funcref + (ref.func 5) (ref.func 9) (ref.func 2) (ref.func 7) (ref.func 6)) + (func (result i32) (i32.const 5)) ;; index 5 + (func (result i32) (i32.const 6)) + (func (result i32) (i32.const 7)) + (func (result i32) (i32.const 8)) + (func (result i32) (i32.const 9)) ;; index 9 + (func (export "test") + (table.init 1 (i32.const 7) (i32.const 0) (i32.const 4)) + (elem.drop 1) + (table.init 3 (i32.const 15) (i32.const 1) (i32.const 3)) + (elem.drop 3) + (table.copy (i32.const 20) (i32.const 15) (i32.const 5)) + (table.copy (i32.const 21) (i32.const 29) (i32.const 1)) + (table.copy (i32.const 24) (i32.const 10) (i32.const 1)) + (table.copy (i32.const 13) (i32.const 11) (i32.const 4)) + (table.copy (i32.const 19) (i32.const 20) (i32.const 5))) + (func (export "check") (param i32) (result i32) + (call_indirect (type 0) (local.get 0))) +) + +(invoke "test") +(assert_trap (invoke "check" (i32.const 0)) "uninitialized element") +(assert_trap (invoke "check" (i32.const 1)) "uninitialized element") +(assert_return (invoke "check" (i32.const 2)) (i32.const 3)) +(assert_return (invoke "check" (i32.const 3)) (i32.const 1)) +(assert_return (invoke "check" (i32.const 4)) (i32.const 4)) +(assert_return (invoke "check" (i32.const 5)) (i32.const 1)) +(assert_trap (invoke "check" (i32.const 6)) "uninitialized element") +(assert_return (invoke "check" (i32.const 7)) (i32.const 2)) +(assert_return (invoke "check" (i32.const 8)) (i32.const 7)) +(assert_return (invoke "check" (i32.const 9)) (i32.const 1)) +(assert_return (invoke "check" (i32.const 10)) (i32.const 8)) +(assert_trap (invoke "check" (i32.const 11)) "uninitialized element") +(assert_return (invoke "check" (i32.const 12)) (i32.const 7)) +(assert_trap (invoke "check" (i32.const 13)) "uninitialized element") +(assert_return (invoke "check" (i32.const 14)) (i32.const 7)) +(assert_return (invoke "check" (i32.const 15)) (i32.const 5)) +(assert_return (invoke "check" (i32.const 16)) (i32.const 2)) +(assert_return (invoke "check" (i32.const 17)) (i32.const 7)) +(assert_trap (invoke "check" (i32.const 18)) "uninitialized element") +(assert_return (invoke "check" (i32.const 19)) (i32.const 9)) +(assert_trap (invoke "check" (i32.const 20)) "uninitialized element") +(assert_return (invoke "check" (i32.const 21)) (i32.const 7)) +(assert_trap (invoke "check" (i32.const 22)) "uninitialized element") +(assert_return (invoke "check" (i32.const 23)) (i32.const 8)) +(assert_return (invoke "check" (i32.const 24)) (i32.const 8)) +(assert_trap (invoke "check" (i32.const 25)) "uninitialized element") +(assert_trap (invoke "check" (i32.const 26)) "uninitialized element") +(assert_trap (invoke "check" (i32.const 27)) "uninitialized element") +(assert_trap (invoke "check" (i32.const 28)) "uninitialized element") +(assert_trap (invoke "check" (i32.const 29)) "uninitialized element") +(assert_invalid + (module + (func (export "test") + (elem.drop 0))) + "unknown table 0") + +(assert_invalid + (module + (func (export "test") + (table.init 0 (i32.const 12) (i32.const 1) (i32.const 1)))) + "unknown table 0") + +(assert_invalid + (module + (elem funcref (ref.func 0)) + (func (result i32) (i32.const 0)) + (func (export "test") + (elem.drop 4))) + "unknown table 0") + +(assert_invalid + (module + (elem funcref (ref.func 0)) + (func (result i32) (i32.const 0)) + (func (export "test") + (table.init 4 (i32.const 12) (i32.const 1) (i32.const 1)))) + "unknown table 0") + + +(module + (table 30 30 funcref) + (elem (i32.const 2) 3 1 4 1) + (elem funcref + (ref.func 2) (ref.func 7) (ref.func 1) (ref.func 8)) + (elem (i32.const 12) 7 5 2 3 6) + (elem funcref + (ref.func 5) (ref.func 9) (ref.func 2) (ref.func 7) (ref.func 6)) + (func (result i32) (i32.const 0)) + (func (result i32) (i32.const 1)) + (func (result i32) (i32.const 2)) + (func (result i32) (i32.const 3)) + (func (result i32) (i32.const 4)) + (func (result i32) (i32.const 5)) + (func (result i32) (i32.const 6)) + (func (result i32) (i32.const 7)) + (func (result i32) (i32.const 8)) + (func (result i32) (i32.const 9)) + (func (export "test") + (elem.drop 2) + )) +(invoke "test") + +(module + (table 30 30 funcref) + (elem (i32.const 2) 3 1 4 1) + (elem funcref + (ref.func 2) (ref.func 7) (ref.func 1) (ref.func 8)) + (elem (i32.const 12) 7 5 2 3 6) + (elem funcref + (ref.func 5) (ref.func 9) (ref.func 2) (ref.func 7) (ref.func 6)) + (func (result i32) (i32.const 0)) + (func (result i32) (i32.const 1)) + (func (result i32) (i32.const 2)) + (func (result i32) (i32.const 3)) + (func (result i32) (i32.const 4)) + (func (result i32) (i32.const 5)) + (func (result i32) (i32.const 6)) + (func (result i32) (i32.const 7)) + (func (result i32) (i32.const 8)) + (func (result i32) (i32.const 9)) + (func (export "test") + (table.init 2 (i32.const 12) (i32.const 1) (i32.const 1)) + )) +(assert_trap (invoke "test") "out of bounds") + +(module + (table 30 30 funcref) + (elem (i32.const 2) 3 1 4 1) + (elem funcref + (ref.func 2) (ref.func 7) (ref.func 1) (ref.func 8)) + (elem (i32.const 12) 7 5 2 3 6) + (elem funcref + (ref.func 5) (ref.func 9) (ref.func 2) (ref.func 7) (ref.func 6)) + (func (result i32) (i32.const 0)) + (func (result i32) (i32.const 1)) + (func (result i32) (i32.const 2)) + (func (result i32) (i32.const 3)) + (func (result i32) (i32.const 4)) + (func (result i32) (i32.const 5)) + (func (result i32) (i32.const 6)) + (func (result i32) (i32.const 7)) + (func (result i32) (i32.const 8)) + (func (result i32) (i32.const 9)) + (func (export "test") + (table.init 1 (i32.const 12) (i32.const 1) (i32.const 1)) + (table.init 1 (i32.const 21) (i32.const 1) (i32.const 1)))) +(invoke "test") + +(module + (table 30 30 funcref) + (elem (i32.const 2) 3 1 4 1) + (elem funcref + (ref.func 2) (ref.func 7) (ref.func 1) (ref.func 8)) + (elem (i32.const 12) 7 5 2 3 6) + (elem funcref + (ref.func 5) (ref.func 9) (ref.func 2) (ref.func 7) (ref.func 6)) + (func (result i32) (i32.const 0)) + (func (result i32) (i32.const 1)) + (func (result i32) (i32.const 2)) + (func (result i32) (i32.const 3)) + (func (result i32) (i32.const 4)) + (func (result i32) (i32.const 5)) + (func (result i32) (i32.const 6)) + (func (result i32) (i32.const 7)) + (func (result i32) (i32.const 8)) + (func (result i32) (i32.const 9)) + (func (export "test") + (elem.drop 1) + (elem.drop 1))) +(invoke "test") + +(module + (table 30 30 funcref) + (elem (i32.const 2) 3 1 4 1) + (elem funcref + (ref.func 2) (ref.func 7) (ref.func 1) (ref.func 8)) + (elem (i32.const 12) 7 5 2 3 6) + (elem funcref + (ref.func 5) (ref.func 9) (ref.func 2) (ref.func 7) (ref.func 6)) + (func (result i32) (i32.const 0)) + (func (result i32) (i32.const 1)) + (func (result i32) (i32.const 2)) + (func (result i32) (i32.const 3)) + (func (result i32) (i32.const 4)) + (func (result i32) (i32.const 5)) + (func (result i32) (i32.const 6)) + (func (result i32) (i32.const 7)) + (func (result i32) (i32.const 8)) + (func (result i32) (i32.const 9)) + (func (export "test") + (elem.drop 1) + (table.init 1 (i32.const 12) (i32.const 1) (i32.const 1)))) +(assert_trap (invoke "test") "out of bounds") + +(module + (table 30 30 funcref) + (elem (i32.const 2) 3 1 4 1) + (elem funcref + (ref.func 2) (ref.func 7) (ref.func 1) (ref.func 8)) + (elem (i32.const 12) 7 5 2 3 6) + (elem funcref + (ref.func 5) (ref.func 9) (ref.func 2) (ref.func 7) (ref.func 6)) + (func (result i32) (i32.const 0)) + (func (result i32) (i32.const 1)) + (func (result i32) (i32.const 2)) + (func (result i32) (i32.const 3)) + (func (result i32) (i32.const 4)) + (func (result i32) (i32.const 5)) + (func (result i32) (i32.const 6)) + (func (result i32) (i32.const 7)) + (func (result i32) (i32.const 8)) + (func (result i32) (i32.const 9)) + (func (export "test") + (table.init 1 (i32.const 12) (i32.const 0) (i32.const 5)) + )) +(assert_trap (invoke "test") "out of bounds") + +(module + (table 30 30 funcref) + (elem (i32.const 2) 3 1 4 1) + (elem funcref + (ref.func 2) (ref.func 7) (ref.func 1) (ref.func 8)) + (elem (i32.const 12) 7 5 2 3 6) + (elem funcref + (ref.func 5) (ref.func 9) (ref.func 2) (ref.func 7) (ref.func 6)) + (func (result i32) (i32.const 0)) + (func (result i32) (i32.const 1)) + (func (result i32) (i32.const 2)) + (func (result i32) (i32.const 3)) + (func (result i32) (i32.const 4)) + (func (result i32) (i32.const 5)) + (func (result i32) (i32.const 6)) + (func (result i32) (i32.const 7)) + (func (result i32) (i32.const 8)) + (func (result i32) (i32.const 9)) + (func (export "test") + (table.init 1 (i32.const 12) (i32.const 2) (i32.const 3)) + )) +(assert_trap (invoke "test") "out of bounds") + +(module + (table 30 30 funcref) + (elem (i32.const 2) 3 1 4 1) + (elem funcref + (ref.func 2) (ref.func 7) (ref.func 1) (ref.func 8)) + (elem (i32.const 12) 7 5 2 3 6) + (elem funcref + (ref.func 5) (ref.func 9) (ref.func 2) (ref.func 7) (ref.func 6)) + (func (result i32) (i32.const 0)) + (func (result i32) (i32.const 1)) + (func (result i32) (i32.const 2)) + (func (result i32) (i32.const 3)) + (func (result i32) (i32.const 4)) + (func (result i32) (i32.const 5)) + (func (result i32) (i32.const 6)) + (func (result i32) (i32.const 7)) + (func (result i32) (i32.const 8)) + (func (result i32) (i32.const 9)) + (func (export "test") + (table.init 1 (i32.const 28) (i32.const 1) (i32.const 3)) + )) +(assert_trap (invoke "test") "out of bounds") + +(module + (table 30 30 funcref) + (elem (i32.const 2) 3 1 4 1) + (elem funcref + (ref.func 2) (ref.func 7) (ref.func 1) (ref.func 8)) + (elem (i32.const 12) 7 5 2 3 6) + (elem funcref + (ref.func 5) (ref.func 9) (ref.func 2) (ref.func 7) (ref.func 6)) + (func (result i32) (i32.const 0)) + (func (result i32) (i32.const 1)) + (func (result i32) (i32.const 2)) + (func (result i32) (i32.const 3)) + (func (result i32) (i32.const 4)) + (func (result i32) (i32.const 5)) + (func (result i32) (i32.const 6)) + (func (result i32) (i32.const 7)) + (func (result i32) (i32.const 8)) + (func (result i32) (i32.const 9)) + (func (export "test") + (table.init 1 (i32.const 12) (i32.const 4) (i32.const 0)) + )) +(invoke "test") + +(module + (table 30 30 funcref) + (elem (i32.const 2) 3 1 4 1) + (elem funcref + (ref.func 2) (ref.func 7) (ref.func 1) (ref.func 8)) + (elem (i32.const 12) 7 5 2 3 6) + (elem funcref + (ref.func 5) (ref.func 9) (ref.func 2) (ref.func 7) (ref.func 6)) + (func (result i32) (i32.const 0)) + (func (result i32) (i32.const 1)) + (func (result i32) (i32.const 2)) + (func (result i32) (i32.const 3)) + (func (result i32) (i32.const 4)) + (func (result i32) (i32.const 5)) + (func (result i32) (i32.const 6)) + (func (result i32) (i32.const 7)) + (func (result i32) (i32.const 8)) + (func (result i32) (i32.const 9)) + (func (export "test") + (table.init 1 (i32.const 12) (i32.const 5) (i32.const 0)) + )) +(assert_trap (invoke "test") "out of bounds") + +(module + (table 30 30 funcref) + (elem (i32.const 2) 3 1 4 1) + (elem funcref + (ref.func 2) (ref.func 7) (ref.func 1) (ref.func 8)) + (elem (i32.const 12) 7 5 2 3 6) + (elem funcref + (ref.func 5) (ref.func 9) (ref.func 2) (ref.func 7) (ref.func 6)) + (func (result i32) (i32.const 0)) + (func (result i32) (i32.const 1)) + (func (result i32) (i32.const 2)) + (func (result i32) (i32.const 3)) + (func (result i32) (i32.const 4)) + (func (result i32) (i32.const 5)) + (func (result i32) (i32.const 6)) + (func (result i32) (i32.const 7)) + (func (result i32) (i32.const 8)) + (func (result i32) (i32.const 9)) + (func (export "test") + (table.init 1 (i32.const 30) (i32.const 2) (i32.const 0)) + )) +(invoke "test") + +(module + (table 30 30 funcref) + (elem (i32.const 2) 3 1 4 1) + (elem funcref + (ref.func 2) (ref.func 7) (ref.func 1) (ref.func 8)) + (elem (i32.const 12) 7 5 2 3 6) + (elem funcref + (ref.func 5) (ref.func 9) (ref.func 2) (ref.func 7) (ref.func 6)) + (func (result i32) (i32.const 0)) + (func (result i32) (i32.const 1)) + (func (result i32) (i32.const 2)) + (func (result i32) (i32.const 3)) + (func (result i32) (i32.const 4)) + (func (result i32) (i32.const 5)) + (func (result i32) (i32.const 6)) + (func (result i32) (i32.const 7)) + (func (result i32) (i32.const 8)) + (func (result i32) (i32.const 9)) + (func (export "test") + (table.init 1 (i32.const 31) (i32.const 2) (i32.const 0)) + )) +(assert_trap (invoke "test") "out of bounds") + +(module + (table 30 30 funcref) + (elem (i32.const 2) 3 1 4 1) + (elem funcref + (ref.func 2) (ref.func 7) (ref.func 1) (ref.func 8)) + (elem (i32.const 12) 7 5 2 3 6) + (elem funcref + (ref.func 5) (ref.func 9) (ref.func 2) (ref.func 7) (ref.func 6)) + (func (result i32) (i32.const 0)) + (func (result i32) (i32.const 1)) + (func (result i32) (i32.const 2)) + (func (result i32) (i32.const 3)) + (func (result i32) (i32.const 4)) + (func (result i32) (i32.const 5)) + (func (result i32) (i32.const 6)) + (func (result i32) (i32.const 7)) + (func (result i32) (i32.const 8)) + (func (result i32) (i32.const 9)) + (func (export "test") + (table.init 1 (i32.const 30) (i32.const 4) (i32.const 0)) + )) +(invoke "test") + +(module + (table 30 30 funcref) + (elem (i32.const 2) 3 1 4 1) + (elem funcref + (ref.func 2) (ref.func 7) (ref.func 1) (ref.func 8)) + (elem (i32.const 12) 7 5 2 3 6) + (elem funcref + (ref.func 5) (ref.func 9) (ref.func 2) (ref.func 7) (ref.func 6)) + (func (result i32) (i32.const 0)) + (func (result i32) (i32.const 1)) + (func (result i32) (i32.const 2)) + (func (result i32) (i32.const 3)) + (func (result i32) (i32.const 4)) + (func (result i32) (i32.const 5)) + (func (result i32) (i32.const 6)) + (func (result i32) (i32.const 7)) + (func (result i32) (i32.const 8)) + (func (result i32) (i32.const 9)) + (func (export "test") + (table.init 1 (i32.const 31) (i32.const 5) (i32.const 0)) + )) +(assert_trap (invoke "test") "out of bounds") + +(assert_invalid + (module + (table 10 funcref) + (elem funcref (ref.func $f0) (ref.func $f0) (ref.func $f0)) + (func $f0) + (func (export "test") + (table.init 0 (i32.const 1) (i32.const 1) (f32.const 1)))) + "type mismatch") + +(assert_invalid + (module + (table 10 funcref) + (elem funcref (ref.func $f0) (ref.func $f0) (ref.func $f0)) + (func $f0) + (func (export "test") + (table.init 0 (i32.const 1) (i32.const 1) (i64.const 1)))) + "type mismatch") + +(assert_invalid + (module + (table 10 funcref) + (elem funcref (ref.func $f0) (ref.func $f0) (ref.func $f0)) + (func $f0) + (func (export "test") + (table.init 0 (i32.const 1) (i32.const 1) (f64.const 1)))) + "type mismatch") + +(assert_invalid + (module + (table 10 funcref) + (elem funcref (ref.func $f0) (ref.func $f0) (ref.func $f0)) + (func $f0) + (func (export "test") + (table.init 0 (i32.const 1) (f32.const 1) (i32.const 1)))) + "type mismatch") + +(assert_invalid + (module + (table 10 funcref) + (elem funcref (ref.func $f0) (ref.func $f0) (ref.func $f0)) + (func $f0) + (func (export "test") + (table.init 0 (i32.const 1) (f32.const 1) (f32.const 1)))) + "type mismatch") + +(assert_invalid + (module + (table 10 funcref) + (elem funcref (ref.func $f0) (ref.func $f0) (ref.func $f0)) + (func $f0) + (func (export "test") + (table.init 0 (i32.const 1) (f32.const 1) (i64.const 1)))) + "type mismatch") + +(assert_invalid + (module + (table 10 funcref) + (elem funcref (ref.func $f0) (ref.func $f0) (ref.func $f0)) + (func $f0) + (func (export "test") + (table.init 0 (i32.const 1) (f32.const 1) (f64.const 1)))) + "type mismatch") + +(assert_invalid + (module + (table 10 funcref) + (elem funcref (ref.func $f0) (ref.func $f0) (ref.func $f0)) + (func $f0) + (func (export "test") + (table.init 0 (i32.const 1) (i64.const 1) (i32.const 1)))) + "type mismatch") + +(assert_invalid + (module + (table 10 funcref) + (elem funcref (ref.func $f0) (ref.func $f0) (ref.func $f0)) + (func $f0) + (func (export "test") + (table.init 0 (i32.const 1) (i64.const 1) (f32.const 1)))) + "type mismatch") + +(assert_invalid + (module + (table 10 funcref) + (elem funcref (ref.func $f0) (ref.func $f0) (ref.func $f0)) + (func $f0) + (func (export "test") + (table.init 0 (i32.const 1) (i64.const 1) (i64.const 1)))) + "type mismatch") + +(assert_invalid + (module + (table 10 funcref) + (elem funcref (ref.func $f0) (ref.func $f0) (ref.func $f0)) + (func $f0) + (func (export "test") + (table.init 0 (i32.const 1) (i64.const 1) (f64.const 1)))) + "type mismatch") + +(assert_invalid + (module + (table 10 funcref) + (elem funcref (ref.func $f0) (ref.func $f0) (ref.func $f0)) + (func $f0) + (func (export "test") + (table.init 0 (i32.const 1) (f64.const 1) (i32.const 1)))) + "type mismatch") + +(assert_invalid + (module + (table 10 funcref) + (elem funcref (ref.func $f0) (ref.func $f0) (ref.func $f0)) + (func $f0) + (func (export "test") + (table.init 0 (i32.const 1) (f64.const 1) (f32.const 1)))) + "type mismatch") + +(assert_invalid + (module + (table 10 funcref) + (elem funcref (ref.func $f0) (ref.func $f0) (ref.func $f0)) + (func $f0) + (func (export "test") + (table.init 0 (i32.const 1) (f64.const 1) (i64.const 1)))) + "type mismatch") + +(assert_invalid + (module + (table 10 funcref) + (elem funcref (ref.func $f0) (ref.func $f0) (ref.func $f0)) + (func $f0) + (func (export "test") + (table.init 0 (i32.const 1) (f64.const 1) (f64.const 1)))) + "type mismatch") + +(assert_invalid + (module + (table 10 funcref) + (elem funcref (ref.func $f0) (ref.func $f0) (ref.func $f0)) + (func $f0) + (func (export "test") + (table.init 0 (f32.const 1) (i32.const 1) (i32.const 1)))) + "type mismatch") + +(assert_invalid + (module + (table 10 funcref) + (elem funcref (ref.func $f0) (ref.func $f0) (ref.func $f0)) + (func $f0) + (func (export "test") + (table.init 0 (f32.const 1) (i32.const 1) (f32.const 1)))) + "type mismatch") + +(assert_invalid + (module + (table 10 funcref) + (elem funcref (ref.func $f0) (ref.func $f0) (ref.func $f0)) + (func $f0) + (func (export "test") + (table.init 0 (f32.const 1) (i32.const 1) (i64.const 1)))) + "type mismatch") + +(assert_invalid + (module + (table 10 funcref) + (elem funcref (ref.func $f0) (ref.func $f0) (ref.func $f0)) + (func $f0) + (func (export "test") + (table.init 0 (f32.const 1) (i32.const 1) (f64.const 1)))) + "type mismatch") + +(assert_invalid + (module + (table 10 funcref) + (elem funcref (ref.func $f0) (ref.func $f0) (ref.func $f0)) + (func $f0) + (func (export "test") + (table.init 0 (f32.const 1) (f32.const 1) (i32.const 1)))) + "type mismatch") + +(assert_invalid + (module + (table 10 funcref) + (elem funcref (ref.func $f0) (ref.func $f0) (ref.func $f0)) + (func $f0) + (func (export "test") + (table.init 0 (f32.const 1) (f32.const 1) (f32.const 1)))) + "type mismatch") + +(assert_invalid + (module + (table 10 funcref) + (elem funcref (ref.func $f0) (ref.func $f0) (ref.func $f0)) + (func $f0) + (func (export "test") + (table.init 0 (f32.const 1) (f32.const 1) (i64.const 1)))) + "type mismatch") + +(assert_invalid + (module + (table 10 funcref) + (elem funcref (ref.func $f0) (ref.func $f0) (ref.func $f0)) + (func $f0) + (func (export "test") + (table.init 0 (f32.const 1) (f32.const 1) (f64.const 1)))) + "type mismatch") + +(assert_invalid + (module + (table 10 funcref) + (elem funcref (ref.func $f0) (ref.func $f0) (ref.func $f0)) + (func $f0) + (func (export "test") + (table.init 0 (f32.const 1) (i64.const 1) (i32.const 1)))) + "type mismatch") + +(assert_invalid + (module + (table 10 funcref) + (elem funcref (ref.func $f0) (ref.func $f0) (ref.func $f0)) + (func $f0) + (func (export "test") + (table.init 0 (f32.const 1) (i64.const 1) (f32.const 1)))) + "type mismatch") + +(assert_invalid + (module + (table 10 funcref) + (elem funcref (ref.func $f0) (ref.func $f0) (ref.func $f0)) + (func $f0) + (func (export "test") + (table.init 0 (f32.const 1) (i64.const 1) (i64.const 1)))) + "type mismatch") + +(assert_invalid + (module + (table 10 funcref) + (elem funcref (ref.func $f0) (ref.func $f0) (ref.func $f0)) + (func $f0) + (func (export "test") + (table.init 0 (f32.const 1) (i64.const 1) (f64.const 1)))) + "type mismatch") + +(assert_invalid + (module + (table 10 funcref) + (elem funcref (ref.func $f0) (ref.func $f0) (ref.func $f0)) + (func $f0) + (func (export "test") + (table.init 0 (f32.const 1) (f64.const 1) (i32.const 1)))) + "type mismatch") + +(assert_invalid + (module + (table 10 funcref) + (elem funcref (ref.func $f0) (ref.func $f0) (ref.func $f0)) + (func $f0) + (func (export "test") + (table.init 0 (f32.const 1) (f64.const 1) (f32.const 1)))) + "type mismatch") + +(assert_invalid + (module + (table 10 funcref) + (elem funcref (ref.func $f0) (ref.func $f0) (ref.func $f0)) + (func $f0) + (func (export "test") + (table.init 0 (f32.const 1) (f64.const 1) (i64.const 1)))) + "type mismatch") + +(assert_invalid + (module + (table 10 funcref) + (elem funcref (ref.func $f0) (ref.func $f0) (ref.func $f0)) + (func $f0) + (func (export "test") + (table.init 0 (f32.const 1) (f64.const 1) (f64.const 1)))) + "type mismatch") + +(assert_invalid + (module + (table 10 funcref) + (elem funcref (ref.func $f0) (ref.func $f0) (ref.func $f0)) + (func $f0) + (func (export "test") + (table.init 0 (i64.const 1) (i32.const 1) (i32.const 1)))) + "type mismatch") + +(assert_invalid + (module + (table 10 funcref) + (elem funcref (ref.func $f0) (ref.func $f0) (ref.func $f0)) + (func $f0) + (func (export "test") + (table.init 0 (i64.const 1) (i32.const 1) (f32.const 1)))) + "type mismatch") + +(assert_invalid + (module + (table 10 funcref) + (elem funcref (ref.func $f0) (ref.func $f0) (ref.func $f0)) + (func $f0) + (func (export "test") + (table.init 0 (i64.const 1) (i32.const 1) (i64.const 1)))) + "type mismatch") + +(assert_invalid + (module + (table 10 funcref) + (elem funcref (ref.func $f0) (ref.func $f0) (ref.func $f0)) + (func $f0) + (func (export "test") + (table.init 0 (i64.const 1) (i32.const 1) (f64.const 1)))) + "type mismatch") + +(assert_invalid + (module + (table 10 funcref) + (elem funcref (ref.func $f0) (ref.func $f0) (ref.func $f0)) + (func $f0) + (func (export "test") + (table.init 0 (i64.const 1) (f32.const 1) (i32.const 1)))) + "type mismatch") + +(assert_invalid + (module + (table 10 funcref) + (elem funcref (ref.func $f0) (ref.func $f0) (ref.func $f0)) + (func $f0) + (func (export "test") + (table.init 0 (i64.const 1) (f32.const 1) (f32.const 1)))) + "type mismatch") + +(assert_invalid + (module + (table 10 funcref) + (elem funcref (ref.func $f0) (ref.func $f0) (ref.func $f0)) + (func $f0) + (func (export "test") + (table.init 0 (i64.const 1) (f32.const 1) (i64.const 1)))) + "type mismatch") + +(assert_invalid + (module + (table 10 funcref) + (elem funcref (ref.func $f0) (ref.func $f0) (ref.func $f0)) + (func $f0) + (func (export "test") + (table.init 0 (i64.const 1) (f32.const 1) (f64.const 1)))) + "type mismatch") + +(assert_invalid + (module + (table 10 funcref) + (elem funcref (ref.func $f0) (ref.func $f0) (ref.func $f0)) + (func $f0) + (func (export "test") + (table.init 0 (i64.const 1) (i64.const 1) (i32.const 1)))) + "type mismatch") + +(assert_invalid + (module + (table 10 funcref) + (elem funcref (ref.func $f0) (ref.func $f0) (ref.func $f0)) + (func $f0) + (func (export "test") + (table.init 0 (i64.const 1) (i64.const 1) (f32.const 1)))) + "type mismatch") + +(assert_invalid + (module + (table 10 funcref) + (elem funcref (ref.func $f0) (ref.func $f0) (ref.func $f0)) + (func $f0) + (func (export "test") + (table.init 0 (i64.const 1) (i64.const 1) (i64.const 1)))) + "type mismatch") + +(assert_invalid + (module + (table 10 funcref) + (elem funcref (ref.func $f0) (ref.func $f0) (ref.func $f0)) + (func $f0) + (func (export "test") + (table.init 0 (i64.const 1) (i64.const 1) (f64.const 1)))) + "type mismatch") + +(assert_invalid + (module + (table 10 funcref) + (elem funcref (ref.func $f0) (ref.func $f0) (ref.func $f0)) + (func $f0) + (func (export "test") + (table.init 0 (i64.const 1) (f64.const 1) (i32.const 1)))) + "type mismatch") + +(assert_invalid + (module + (table 10 funcref) + (elem funcref (ref.func $f0) (ref.func $f0) (ref.func $f0)) + (func $f0) + (func (export "test") + (table.init 0 (i64.const 1) (f64.const 1) (f32.const 1)))) + "type mismatch") + +(assert_invalid + (module + (table 10 funcref) + (elem funcref (ref.func $f0) (ref.func $f0) (ref.func $f0)) + (func $f0) + (func (export "test") + (table.init 0 (i64.const 1) (f64.const 1) (i64.const 1)))) + "type mismatch") + +(assert_invalid + (module + (table 10 funcref) + (elem funcref (ref.func $f0) (ref.func $f0) (ref.func $f0)) + (func $f0) + (func (export "test") + (table.init 0 (i64.const 1) (f64.const 1) (f64.const 1)))) + "type mismatch") + +(assert_invalid + (module + (table 10 funcref) + (elem funcref (ref.func $f0) (ref.func $f0) (ref.func $f0)) + (func $f0) + (func (export "test") + (table.init 0 (f64.const 1) (i32.const 1) (i32.const 1)))) + "type mismatch") + +(assert_invalid + (module + (table 10 funcref) + (elem funcref (ref.func $f0) (ref.func $f0) (ref.func $f0)) + (func $f0) + (func (export "test") + (table.init 0 (f64.const 1) (i32.const 1) (f32.const 1)))) + "type mismatch") + +(assert_invalid + (module + (table 10 funcref) + (elem funcref (ref.func $f0) (ref.func $f0) (ref.func $f0)) + (func $f0) + (func (export "test") + (table.init 0 (f64.const 1) (i32.const 1) (i64.const 1)))) + "type mismatch") + +(assert_invalid + (module + (table 10 funcref) + (elem funcref (ref.func $f0) (ref.func $f0) (ref.func $f0)) + (func $f0) + (func (export "test") + (table.init 0 (f64.const 1) (i32.const 1) (f64.const 1)))) + "type mismatch") + +(assert_invalid + (module + (table 10 funcref) + (elem funcref (ref.func $f0) (ref.func $f0) (ref.func $f0)) + (func $f0) + (func (export "test") + (table.init 0 (f64.const 1) (f32.const 1) (i32.const 1)))) + "type mismatch") + +(assert_invalid + (module + (table 10 funcref) + (elem funcref (ref.func $f0) (ref.func $f0) (ref.func $f0)) + (func $f0) + (func (export "test") + (table.init 0 (f64.const 1) (f32.const 1) (f32.const 1)))) + "type mismatch") + +(assert_invalid + (module + (table 10 funcref) + (elem funcref (ref.func $f0) (ref.func $f0) (ref.func $f0)) + (func $f0) + (func (export "test") + (table.init 0 (f64.const 1) (f32.const 1) (i64.const 1)))) + "type mismatch") + +(assert_invalid + (module + (table 10 funcref) + (elem funcref (ref.func $f0) (ref.func $f0) (ref.func $f0)) + (func $f0) + (func (export "test") + (table.init 0 (f64.const 1) (f32.const 1) (f64.const 1)))) + "type mismatch") + +(assert_invalid + (module + (table 10 funcref) + (elem funcref (ref.func $f0) (ref.func $f0) (ref.func $f0)) + (func $f0) + (func (export "test") + (table.init 0 (f64.const 1) (i64.const 1) (i32.const 1)))) + "type mismatch") + +(assert_invalid + (module + (table 10 funcref) + (elem funcref (ref.func $f0) (ref.func $f0) (ref.func $f0)) + (func $f0) + (func (export "test") + (table.init 0 (f64.const 1) (i64.const 1) (f32.const 1)))) + "type mismatch") + +(assert_invalid + (module + (table 10 funcref) + (elem funcref (ref.func $f0) (ref.func $f0) (ref.func $f0)) + (func $f0) + (func (export "test") + (table.init 0 (f64.const 1) (i64.const 1) (i64.const 1)))) + "type mismatch") + +(assert_invalid + (module + (table 10 funcref) + (elem funcref (ref.func $f0) (ref.func $f0) (ref.func $f0)) + (func $f0) + (func (export "test") + (table.init 0 (f64.const 1) (i64.const 1) (f64.const 1)))) + "type mismatch") + +(assert_invalid + (module + (table 10 funcref) + (elem funcref (ref.func $f0) (ref.func $f0) (ref.func $f0)) + (func $f0) + (func (export "test") + (table.init 0 (f64.const 1) (f64.const 1) (i32.const 1)))) + "type mismatch") + +(assert_invalid + (module + (table 10 funcref) + (elem funcref (ref.func $f0) (ref.func $f0) (ref.func $f0)) + (func $f0) + (func (export "test") + (table.init 0 (f64.const 1) (f64.const 1) (f32.const 1)))) + "type mismatch") + +(assert_invalid + (module + (table 10 funcref) + (elem funcref (ref.func $f0) (ref.func $f0) (ref.func $f0)) + (func $f0) + (func (export "test") + (table.init 0 (f64.const 1) (f64.const 1) (i64.const 1)))) + "type mismatch") + +(assert_invalid + (module + (table 10 funcref) + (elem funcref (ref.func $f0) (ref.func $f0) (ref.func $f0)) + (func $f0) + (func (export "test") + (table.init 0 (f64.const 1) (f64.const 1) (f64.const 1)))) + "type mismatch") + +(module + (type (func (result i32))) + (table 32 64 funcref) + (elem funcref + (ref.func $f0) (ref.func $f1) (ref.func $f2) (ref.func $f3) + (ref.func $f4) (ref.func $f5) (ref.func $f6) (ref.func $f7) + (ref.func $f8) (ref.func $f9) (ref.func $f10) (ref.func $f11) + (ref.func $f12) (ref.func $f13) (ref.func $f14) (ref.func $f15)) + (func $f0 (export "f0") (result i32) (i32.const 0)) + (func $f1 (export "f1") (result i32) (i32.const 1)) + (func $f2 (export "f2") (result i32) (i32.const 2)) + (func $f3 (export "f3") (result i32) (i32.const 3)) + (func $f4 (export "f4") (result i32) (i32.const 4)) + (func $f5 (export "f5") (result i32) (i32.const 5)) + (func $f6 (export "f6") (result i32) (i32.const 6)) + (func $f7 (export "f7") (result i32) (i32.const 7)) + (func $f8 (export "f8") (result i32) (i32.const 8)) + (func $f9 (export "f9") (result i32) (i32.const 9)) + (func $f10 (export "f10") (result i32) (i32.const 10)) + (func $f11 (export "f11") (result i32) (i32.const 11)) + (func $f12 (export "f12") (result i32) (i32.const 12)) + (func $f13 (export "f13") (result i32) (i32.const 13)) + (func $f14 (export "f14") (result i32) (i32.const 14)) + (func $f15 (export "f15") (result i32) (i32.const 15)) + (func (export "test") (param $n i32) (result i32) + (call_indirect (type 0) (local.get $n))) + (func (export "run") (param $offs i32) (param $len i32) + (table.init 0 (local.get $offs) (i32.const 0) (local.get $len)))) +(assert_trap (invoke "run" (i32.const 24) (i32.const 16)) "out of bounds") +(assert_trap (invoke "test" (i32.const 0)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 1)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 2)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 3)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 4)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 5)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 6)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 7)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 8)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 9)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 10)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 11)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 12)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 13)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 14)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 15)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 16)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 17)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 18)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 19)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 20)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 21)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 22)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 23)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 24)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 25)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 26)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 27)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 28)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 29)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 30)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 31)) "uninitialized element") + +(module + (type (func (result i32))) + (table 32 64 funcref) + (elem funcref + (ref.func $f0) (ref.func $f1) (ref.func $f2) (ref.func $f3) + (ref.func $f4) (ref.func $f5) (ref.func $f6) (ref.func $f7) + (ref.func $f8) (ref.func $f9) (ref.func $f10) (ref.func $f11) + (ref.func $f12) (ref.func $f13) (ref.func $f14) (ref.func $f15)) + (func $f0 (export "f0") (result i32) (i32.const 0)) + (func $f1 (export "f1") (result i32) (i32.const 1)) + (func $f2 (export "f2") (result i32) (i32.const 2)) + (func $f3 (export "f3") (result i32) (i32.const 3)) + (func $f4 (export "f4") (result i32) (i32.const 4)) + (func $f5 (export "f5") (result i32) (i32.const 5)) + (func $f6 (export "f6") (result i32) (i32.const 6)) + (func $f7 (export "f7") (result i32) (i32.const 7)) + (func $f8 (export "f8") (result i32) (i32.const 8)) + (func $f9 (export "f9") (result i32) (i32.const 9)) + (func $f10 (export "f10") (result i32) (i32.const 10)) + (func $f11 (export "f11") (result i32) (i32.const 11)) + (func $f12 (export "f12") (result i32) (i32.const 12)) + (func $f13 (export "f13") (result i32) (i32.const 13)) + (func $f14 (export "f14") (result i32) (i32.const 14)) + (func $f15 (export "f15") (result i32) (i32.const 15)) + (func (export "test") (param $n i32) (result i32) + (call_indirect (type 0) (local.get $n))) + (func (export "run") (param $offs i32) (param $len i32) + (table.init 0 (local.get $offs) (i32.const 0) (local.get $len)))) +(assert_trap (invoke "run" (i32.const 25) (i32.const 16)) "out of bounds") +(assert_trap (invoke "test" (i32.const 0)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 1)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 2)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 3)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 4)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 5)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 6)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 7)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 8)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 9)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 10)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 11)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 12)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 13)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 14)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 15)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 16)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 17)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 18)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 19)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 20)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 21)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 22)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 23)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 24)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 25)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 26)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 27)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 28)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 29)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 30)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 31)) "uninitialized element") + +(module + (type (func (result i32))) + (table 160 320 funcref) + (elem funcref + (ref.func $f0) (ref.func $f1) (ref.func $f2) (ref.func $f3) + (ref.func $f4) (ref.func $f5) (ref.func $f6) (ref.func $f7) + (ref.func $f8) (ref.func $f9) (ref.func $f10) (ref.func $f11) + (ref.func $f12) (ref.func $f13) (ref.func $f14) (ref.func $f15)) + (func $f0 (export "f0") (result i32) (i32.const 0)) + (func $f1 (export "f1") (result i32) (i32.const 1)) + (func $f2 (export "f2") (result i32) (i32.const 2)) + (func $f3 (export "f3") (result i32) (i32.const 3)) + (func $f4 (export "f4") (result i32) (i32.const 4)) + (func $f5 (export "f5") (result i32) (i32.const 5)) + (func $f6 (export "f6") (result i32) (i32.const 6)) + (func $f7 (export "f7") (result i32) (i32.const 7)) + (func $f8 (export "f8") (result i32) (i32.const 8)) + (func $f9 (export "f9") (result i32) (i32.const 9)) + (func $f10 (export "f10") (result i32) (i32.const 10)) + (func $f11 (export "f11") (result i32) (i32.const 11)) + (func $f12 (export "f12") (result i32) (i32.const 12)) + (func $f13 (export "f13") (result i32) (i32.const 13)) + (func $f14 (export "f14") (result i32) (i32.const 14)) + (func $f15 (export "f15") (result i32) (i32.const 15)) + (func (export "test") (param $n i32) (result i32) + (call_indirect (type 0) (local.get $n))) + (func (export "run") (param $offs i32) (param $len i32) + (table.init 0 (local.get $offs) (i32.const 0) (local.get $len)))) +(assert_trap (invoke "run" (i32.const 96) (i32.const 32)) "out of bounds") +(assert_trap (invoke "test" (i32.const 0)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 1)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 2)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 3)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 4)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 5)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 6)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 7)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 8)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 9)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 10)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 11)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 12)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 13)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 14)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 15)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 16)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 17)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 18)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 19)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 20)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 21)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 22)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 23)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 24)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 25)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 26)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 27)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 28)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 29)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 30)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 31)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 32)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 33)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 34)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 35)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 36)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 37)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 38)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 39)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 40)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 41)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 42)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 43)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 44)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 45)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 46)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 47)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 48)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 49)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 50)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 51)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 52)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 53)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 54)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 55)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 56)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 57)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 58)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 59)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 60)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 61)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 62)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 63)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 64)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 65)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 66)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 67)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 68)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 69)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 70)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 71)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 72)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 73)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 74)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 75)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 76)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 77)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 78)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 79)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 80)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 81)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 82)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 83)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 84)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 85)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 86)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 87)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 88)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 89)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 90)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 91)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 92)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 93)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 94)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 95)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 96)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 97)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 98)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 99)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 100)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 101)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 102)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 103)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 104)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 105)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 106)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 107)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 108)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 109)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 110)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 111)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 112)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 113)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 114)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 115)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 116)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 117)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 118)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 119)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 120)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 121)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 122)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 123)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 124)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 125)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 126)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 127)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 128)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 129)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 130)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 131)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 132)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 133)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 134)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 135)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 136)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 137)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 138)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 139)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 140)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 141)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 142)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 143)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 144)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 145)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 146)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 147)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 148)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 149)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 150)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 151)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 152)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 153)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 154)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 155)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 156)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 157)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 158)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 159)) "uninitialized element") + +(module + (type (func (result i32))) + (table 160 320 funcref) + (elem funcref + (ref.func $f0) (ref.func $f1) (ref.func $f2) (ref.func $f3) + (ref.func $f4) (ref.func $f5) (ref.func $f6) (ref.func $f7) + (ref.func $f8) (ref.func $f9) (ref.func $f10) (ref.func $f11) + (ref.func $f12) (ref.func $f13) (ref.func $f14) (ref.func $f15)) + (func $f0 (export "f0") (result i32) (i32.const 0)) + (func $f1 (export "f1") (result i32) (i32.const 1)) + (func $f2 (export "f2") (result i32) (i32.const 2)) + (func $f3 (export "f3") (result i32) (i32.const 3)) + (func $f4 (export "f4") (result i32) (i32.const 4)) + (func $f5 (export "f5") (result i32) (i32.const 5)) + (func $f6 (export "f6") (result i32) (i32.const 6)) + (func $f7 (export "f7") (result i32) (i32.const 7)) + (func $f8 (export "f8") (result i32) (i32.const 8)) + (func $f9 (export "f9") (result i32) (i32.const 9)) + (func $f10 (export "f10") (result i32) (i32.const 10)) + (func $f11 (export "f11") (result i32) (i32.const 11)) + (func $f12 (export "f12") (result i32) (i32.const 12)) + (func $f13 (export "f13") (result i32) (i32.const 13)) + (func $f14 (export "f14") (result i32) (i32.const 14)) + (func $f15 (export "f15") (result i32) (i32.const 15)) + (func (export "test") (param $n i32) (result i32) + (call_indirect (type 0) (local.get $n))) + (func (export "run") (param $offs i32) (param $len i32) + (table.init 0 (local.get $offs) (i32.const 0) (local.get $len)))) +(assert_trap (invoke "run" (i32.const 97) (i32.const 31)) "out of bounds") +(assert_trap (invoke "test" (i32.const 0)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 1)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 2)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 3)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 4)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 5)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 6)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 7)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 8)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 9)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 10)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 11)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 12)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 13)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 14)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 15)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 16)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 17)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 18)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 19)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 20)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 21)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 22)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 23)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 24)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 25)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 26)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 27)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 28)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 29)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 30)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 31)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 32)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 33)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 34)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 35)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 36)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 37)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 38)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 39)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 40)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 41)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 42)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 43)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 44)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 45)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 46)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 47)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 48)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 49)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 50)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 51)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 52)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 53)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 54)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 55)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 56)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 57)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 58)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 59)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 60)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 61)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 62)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 63)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 64)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 65)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 66)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 67)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 68)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 69)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 70)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 71)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 72)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 73)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 74)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 75)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 76)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 77)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 78)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 79)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 80)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 81)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 82)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 83)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 84)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 85)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 86)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 87)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 88)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 89)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 90)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 91)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 92)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 93)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 94)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 95)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 96)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 97)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 98)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 99)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 100)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 101)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 102)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 103)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 104)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 105)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 106)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 107)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 108)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 109)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 110)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 111)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 112)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 113)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 114)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 115)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 116)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 117)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 118)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 119)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 120)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 121)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 122)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 123)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 124)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 125)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 126)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 127)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 128)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 129)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 130)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 131)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 132)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 133)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 134)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 135)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 136)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 137)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 138)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 139)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 140)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 141)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 142)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 143)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 144)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 145)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 146)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 147)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 148)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 149)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 150)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 151)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 152)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 153)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 154)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 155)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 156)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 157)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 158)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 159)) "uninitialized element") + +(module + (type (func (result i32))) + (table 64 64 funcref) + (elem funcref + (ref.func $f0) (ref.func $f1) (ref.func $f2) (ref.func $f3) + (ref.func $f4) (ref.func $f5) (ref.func $f6) (ref.func $f7) + (ref.func $f8) (ref.func $f9) (ref.func $f10) (ref.func $f11) + (ref.func $f12) (ref.func $f13) (ref.func $f14) (ref.func $f15)) + (func $f0 (export "f0") (result i32) (i32.const 0)) + (func $f1 (export "f1") (result i32) (i32.const 1)) + (func $f2 (export "f2") (result i32) (i32.const 2)) + (func $f3 (export "f3") (result i32) (i32.const 3)) + (func $f4 (export "f4") (result i32) (i32.const 4)) + (func $f5 (export "f5") (result i32) (i32.const 5)) + (func $f6 (export "f6") (result i32) (i32.const 6)) + (func $f7 (export "f7") (result i32) (i32.const 7)) + (func $f8 (export "f8") (result i32) (i32.const 8)) + (func $f9 (export "f9") (result i32) (i32.const 9)) + (func $f10 (export "f10") (result i32) (i32.const 10)) + (func $f11 (export "f11") (result i32) (i32.const 11)) + (func $f12 (export "f12") (result i32) (i32.const 12)) + (func $f13 (export "f13") (result i32) (i32.const 13)) + (func $f14 (export "f14") (result i32) (i32.const 14)) + (func $f15 (export "f15") (result i32) (i32.const 15)) + (func (export "test") (param $n i32) (result i32) + (call_indirect (type 0) (local.get $n))) + (func (export "run") (param $offs i32) (param $len i32) + (table.init 0 (local.get $offs) (i32.const 0) (local.get $len)))) +(assert_trap (invoke "run" (i32.const 48) (i32.const 4294967280)) "out of bounds") +(assert_trap (invoke "test" (i32.const 0)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 1)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 2)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 3)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 4)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 5)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 6)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 7)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 8)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 9)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 10)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 11)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 12)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 13)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 14)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 15)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 16)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 17)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 18)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 19)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 20)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 21)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 22)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 23)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 24)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 25)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 26)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 27)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 28)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 29)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 30)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 31)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 32)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 33)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 34)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 35)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 36)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 37)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 38)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 39)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 40)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 41)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 42)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 43)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 44)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 45)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 46)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 47)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 48)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 49)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 50)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 51)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 52)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 53)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 54)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 55)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 56)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 57)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 58)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 59)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 60)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 61)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 62)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 63)) "uninitialized element") + +(module + (type (func (result i32))) + (table 16 16 funcref) + (elem funcref + (ref.func $f0) (ref.func $f1) (ref.func $f2) (ref.func $f3) + (ref.func $f4) (ref.func $f5) (ref.func $f6) (ref.func $f7) + (ref.func $f8) (ref.func $f9) (ref.func $f10) (ref.func $f11) + (ref.func $f12) (ref.func $f13) (ref.func $f14) (ref.func $f15)) + (func $f0 (export "f0") (result i32) (i32.const 0)) + (func $f1 (export "f1") (result i32) (i32.const 1)) + (func $f2 (export "f2") (result i32) (i32.const 2)) + (func $f3 (export "f3") (result i32) (i32.const 3)) + (func $f4 (export "f4") (result i32) (i32.const 4)) + (func $f5 (export "f5") (result i32) (i32.const 5)) + (func $f6 (export "f6") (result i32) (i32.const 6)) + (func $f7 (export "f7") (result i32) (i32.const 7)) + (func $f8 (export "f8") (result i32) (i32.const 8)) + (func $f9 (export "f9") (result i32) (i32.const 9)) + (func $f10 (export "f10") (result i32) (i32.const 10)) + (func $f11 (export "f11") (result i32) (i32.const 11)) + (func $f12 (export "f12") (result i32) (i32.const 12)) + (func $f13 (export "f13") (result i32) (i32.const 13)) + (func $f14 (export "f14") (result i32) (i32.const 14)) + (func $f15 (export "f15") (result i32) (i32.const 15)) + (func (export "test") (param $n i32) (result i32) + (call_indirect (type 0) (local.get $n))) + (func (export "run") (param $offs i32) (param $len i32) + (table.init 0 (local.get $offs) (i32.const 8) (local.get $len)))) +(assert_trap (invoke "run" (i32.const 0) (i32.const 4294967292)) "out of bounds") +(assert_trap (invoke "test" (i32.const 0)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 1)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 2)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 3)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 4)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 5)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 6)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 7)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 8)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 9)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 10)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 11)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 12)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 13)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 14)) "uninitialized element") +(assert_trap (invoke "test" (i32.const 15)) "uninitialized element") diff --git a/test/core/table_set.wast b/test/core/table_set.wast index 5d2a6a2688..848830e2fb 100644 --- a/test/core/table_set.wast +++ b/test/core/table_set.wast @@ -1,6 +1,7 @@ (module (table $t2 1 anyref) - (table $t3 2 funcref) (elem $t3 (i32.const 1) $dummy) + (table $t3 2 funcref) + (elem (table $t3) (i32.const 1) func $dummy) (func $dummy) (func (export "get-anyref") (param $i i32) (result anyref) diff --git a/test/meta/Makefile b/test/meta/Makefile new file mode 100644 index 0000000000..7f9e680552 --- /dev/null +++ b/test/meta/Makefile @@ -0,0 +1,32 @@ +SHARED_MEM=false + +# SpiderMonkey shell +JSSHELL=~/m-i/js/src/build-debug/dist/bin/js -e 'const WITH_SHARED_MEMORY=$(SHARED_MEM);' -f common.js + +# Node.js +#JSSHELL=./noderun.sh $(SHARED_MEM) + +TARGETDIR=../core + +.PHONY: all + +all: $(TARGETDIR)/memory_copy.wast \ + $(TARGETDIR)/memory_init.wast \ + $(TARGETDIR)/memory_fill.wast \ + $(TARGETDIR)/table_copy.wast \ + $(TARGETDIR)/table_init.wast + +$(TARGETDIR)/memory_copy.wast: generate_memory_copy.js common.js Makefile + $(JSSHELL) $< > $@ + +$(TARGETDIR)/memory_init.wast: generate_memory_init.js common.js Makefile + $(JSSHELL) $< > $@ + +$(TARGETDIR)/memory_fill.wast: generate_memory_fill.js common.js Makefile + $(JSSHELL) $< > $@ + +$(TARGETDIR)/table_copy.wast: generate_table_copy.js common.js Makefile + $(JSSHELL) $< > $@ + +$(TARGETDIR)/table_init.wast: generate_table_init.js common.js Makefile + $(JSSHELL) $< > $@ diff --git a/test/meta/README.md b/test/meta/README.md new file mode 100644 index 0000000000..aeaf790251 --- /dev/null +++ b/test/meta/README.md @@ -0,0 +1 @@ +These programs generate test cases. See Makefile for details. diff --git a/test/meta/common.js b/test/meta/common.js new file mode 100644 index 0000000000..16d80726a6 --- /dev/null +++ b/test/meta/common.js @@ -0,0 +1,28 @@ +const PAGESIZE = 65536; + +function print_origin(origin) { + print(";;"); + print(";; Generated by ../meta/" + origin); + print(";;"); +} + +function checkRangeCode() { + return ` + (func (export "checkRange") (param $from i32) (param $to i32) (param $expected i32) (result i32) + (loop $cont + (if (i32.eq (local.get $from) (local.get $to)) + (then + (return (i32.const -1)))) + (if (i32.eq (i32.load8_u (local.get $from)) (local.get $expected)) + (then + (local.set $from (i32.add (local.get $from) (i32.const 1))) + (br $cont)))) + (return (local.get $from))) +`; +} + +function checkRange(from, to, expected) { + print( +`(assert_return (invoke "checkRange" (i32.const ${from}) (i32.const ${to}) (i32.const ${expected})) + (i32.const -1))`); +} diff --git a/test/meta/generate_memory_copy.js b/test/meta/generate_memory_copy.js new file mode 100644 index 0000000000..e5b7c0c997 --- /dev/null +++ b/test/meta/generate_memory_copy.js @@ -0,0 +1,768 @@ +// This program generates .wast code that contains all the spec tests for +// memory.copy. See `Makefile`. + +print_origin("generate_memory_copy.js"); + +// In-bounds tests. + +function mem_test(instruction, expected_result_vector) { + print( +` +(module + (memory (export "memory0") 1 1) + (data (i32.const 2) "\\03\\01\\04\\01") + (data (i32.const 12) "\\07\\05\\02\\03\\06") + (func (export "test") + ${instruction}) + (func (export "load8_u") (param i32) (result i32) + (i32.load8_u (local.get 0)))) + +(invoke "test") +`); + for (let i = 0; i < expected_result_vector.length; i++) { + print(`(assert_return (invoke "load8_u" (i32.const ${i})) (i32.const ${expected_result_vector[i]}))`); + } +} + +const e = 0; + +// This just gives the initial state of the memory, with its active +// initialisers applied. +mem_test("(nop)", + [e,e,3,1,4, 1,e,e,e,e, e,e,7,5,2, 3,6,e,e,e, e,e,e,e,e, e,e,e,e,e]); + +// Copy non-zero over non-zero +mem_test("(memory.copy (i32.const 13) (i32.const 2) (i32.const 3))", + [e,e,3,1,4, 1,e,e,e,e, e,e,7,3,1, 4,6,e,e,e, e,e,e,e,e, e,e,e,e,e]); + +// Copy non-zero over zero +mem_test("(memory.copy (i32.const 25) (i32.const 15) (i32.const 2))", + [e,e,3,1,4, 1,e,e,e,e, e,e,7,5,2, 3,6,e,e,e, e,e,e,e,e, 3,6,e,e,e]); + +// Copy zero over non-zero +mem_test("(memory.copy (i32.const 13) (i32.const 25) (i32.const 3))", + [e,e,3,1,4, 1,e,e,e,e, e,e,7,e,e, e,6,e,e,e, e,e,e,e,e, e,e,e,e,e]); + +// Copy zero over zero +mem_test("(memory.copy (i32.const 20) (i32.const 22) (i32.const 4))", + [e,e,3,1,4, 1,e,e,e,e, e,e,7,5,2, 3,6,e,e,e, e,e,e,e,e, e,e,e,e,e]); + +// Copy zero and non-zero entries, non overlapping +mem_test("(memory.copy (i32.const 25) (i32.const 1) (i32.const 3))", + [e,e,3,1,4, 1,e,e,e,e, e,e,7,5,2, 3,6,e,e,e, e,e,e,e,e, e,3,1,e,e]); + +// Copy zero and non-zero entries, overlapping, backwards +mem_test("(memory.copy (i32.const 10) (i32.const 12) (i32.const 7))", + [e,e,3,1,4, 1,e,e,e,e, 7,5,2,3,6, e,e,e,e,e, e,e,e,e,e, e,e,e,e,e]); + +// Copy zero and non-zero entries, overlapping, forwards +mem_test("(memory.copy (i32.const 12) (i32.const 10) (i32.const 7))", + [e,e,3,1,4, 1,e,e,e,e, e,e,e,e,7, 5,2,3,6,e, e,e,e,e,e, e,e,e,e,e]); + +// Out-of-bounds tests. +// +// The operation is out of bounds of the memory for the source or target, but +// must perform the operation up to the appropriate bound. Major cases: +// +// - non-overlapping regions +// - overlapping regions with src >= dest +// - overlapping regions with src == dest +// - overlapping regions with src < dest +// - arithmetic overflow on src addresses +// - arithmetic overflow on target addresses +// +// for each of those, +// +// - src address oob +// - target address oob +// - both oob + +function initializers(count, startingAt) { + let s = ""; + for ( let i=0, j=startingAt; i < count; i++, j++ ) + s += "\\" + (i + 256).toString(16).substring(1); + return s; +} + +function mem_copy(min, max, shared, srcOffs, targetOffs, len) { + let copyDown = srcOffs < targetOffs; + let memLength = min * PAGESIZE; + let targetAvail = memLength - targetOffs; + let srcAvail = memLength - srcOffs; + let targetLim = targetOffs + Math.min(len, targetAvail, srcAvail); + let srcLim = srcOffs + Math.min(len, targetAvail, srcAvail); + + print( +` +(module + (memory (export "mem") ${min} ${max} ${shared}) + (data (i32.const ${srcOffs}) "${initializers(srcLim - srcOffs, 0)}") + (func (export "run") (param $targetOffs i32) (param $srcOffs i32) (param $len i32) + (memory.copy (local.get $targetOffs) (local.get $srcOffs) (local.get $len))) + (func (export "load8_u") (param i32) (result i32) + (i32.load8_u (local.get 0)))) + +(assert_trap (invoke "run" (i32.const ${targetOffs}) (i32.const ${srcOffs}) (i32.const ${len})) + "out of bounds") +`); + + let immediateOOB = copyDown && (srcOffs + len > memLength || targetOffs + len > memLength); + + var s = 0; + var i = 0; + let k = 0; + for (i=0; i < memLength; i++ ) { + if (i >= srcOffs && i < srcLim) { + print(`(assert_return (invoke "load8_u" (i32.const ${i})) (i32.const ${(s++) & 0xFF}))`); + continue; + } + // Only spot-check for zero, or we'll be here all night. + if (++k == 199) { + print(`(assert_return (invoke "load8_u" (i32.const ${i})) (i32.const 0))`); + k = 0; + } + } +} + +// OOB target address, nonoverlapping +mem_copy(1, 1, "", 0, PAGESIZE-20, 40); +mem_copy(1, 1, "", 0, PAGESIZE-21, 39); +if (WITH_SHARED_MEMORY) { + mem_copy(2, 4, "shared", 0, 2*PAGESIZE-20, 40); + mem_copy(2, 4, "shared", 0, 2*PAGESIZE-21, 39); +} + +// OOB source address, nonoverlapping +mem_copy(1, 1, "", PAGESIZE-20, 0, 40); +mem_copy(1, 1, "", PAGESIZE-21, 0, 39); +if (WITH_SHARED_MEMORY) { + mem_copy(2, 4, "shared", 2*PAGESIZE-20, 0, 40); + mem_copy(2, 4, "shared", 2*PAGESIZE-21, 0, 39); +} + +// OOB target address, overlapping, src < target +mem_copy(1, 1, "", PAGESIZE-50, PAGESIZE-20, 40); + +// OOB source address, overlapping, target < src +mem_copy(1, 1, "", PAGESIZE-20, PAGESIZE-50, 40); + +// OOB both, overlapping, including target == src +mem_copy(1, 1, "", PAGESIZE-30, PAGESIZE-20, 40); +mem_copy(1, 1, "", PAGESIZE-20, PAGESIZE-30, 40); +mem_copy(1, 1, "", PAGESIZE-20, PAGESIZE-20, 40); + +// Arithmetic overflow on source address. +mem_copy(1, "", "", PAGESIZE-20, 0, 0xFFFFF000); + +// Arithmetic overflow on target adddress is an overlapping case. +mem_copy(1, 1, "", PAGESIZE-0x1000, PAGESIZE-20, 0xFFFFFF00); + +// Sundry compilation failures. + +// Module doesn't have a memory. +print( +` +(assert_invalid + (module + (func (export "testfn") + (memory.copy (i32.const 10) (i32.const 20) (i32.const 30)))) + "unknown memory 0") +`); + +// Invalid argument types. TODO: We can add anyref, funcref, etc here. +{ + const tys = ['i32', 'f32', 'i64', 'f64']; + for (let ty1 of tys) { + for (let ty2 of tys) { + for (let ty3 of tys) { + if (ty1 == 'i32' && ty2 == 'i32' && ty3 == 'i32') + continue; // this is the only valid case + print( +`(assert_invalid + (module + (memory 1 1) + (func (export "testfn") + (memory.copy (${ty1}.const 10) (${ty2}.const 20) (${ty3}.const 30)))) + "type mismatch") +`); + }}} +} + +// Both ranges valid. Copy 5 bytes backwards by 1 (overlapping). +// result = 0x00--(09) 0x55--(11) 0x00--(pagesize-20) +print( +` +(module + (memory 1 1) + (func (export "test") + (memory.fill (i32.const 10) (i32.const 0x55) (i32.const 10)) + (memory.copy (i32.const 9) (i32.const 10) (i32.const 5))) + ${checkRangeCode()}) +(invoke "test") +`); +checkRange(0, 0+9, 0x00); +checkRange(9, 9+11, 0x55); +checkRange(9+11, 0x10000, 0x00); + +// Both ranges valid. Copy 5 bytes forwards by 1 (overlapping). +// result = 0x00--(10) 0x55--(11) 0x00--(pagesize-19) +print( +` +(module + (memory 1 1) + (func (export "test") + (memory.fill (i32.const 10) (i32.const 0x55) (i32.const 10)) + (memory.copy (i32.const 16) (i32.const 15) (i32.const 5))) + ${checkRangeCode()}) +(invoke "test") +`); +checkRange(0, 0+10, 0x00); +checkRange(10, 10+11, 0x55); +checkRange(10+11, 0x10000, 0x00); + +// Destination range invalid +print( +` +(module + (memory 1 1) + (func (export "test") + (memory.copy (i32.const 0xFF00) (i32.const 0x8000) (i32.const 257)))) +(assert_trap (invoke "test") "out of bounds") +`); + +// Destination wraparound the end of 32-bit offset space +print( +`(module + (memory 1 1) + (func (export "test") + (memory.copy (i32.const 0xFFFFFF00) (i32.const 0x4000) (i32.const 257)))) +(assert_trap (invoke "test") "out of bounds") +`); + +// Source range invalid +print( +`(module + (memory 1 1) + (func (export "test") + (memory.copy (i32.const 0x8000) (i32.const 0xFF00) (i32.const 257)))) +(assert_trap (invoke "test") "out of bounds") +`); + +// Source wraparound the end of 32-bit offset space +print( +`(module + (memory 1 1) + (func (export "test") + (memory.copy (i32.const 0x4000) (i32.const 0xFFFFFF00) (i32.const 257)))) +(assert_trap (invoke "test") "out of bounds") +`); + +// Zero len with both offsets in-bounds is a no-op +print( +`(module + (memory 1 1) + (func (export "test") + (memory.fill (i32.const 0x0000) (i32.const 0x55) (i32.const 0x8000)) + (memory.fill (i32.const 0x8000) (i32.const 0xAA) (i32.const 0x8000)) + (memory.copy (i32.const 0x9000) (i32.const 0x7000) (i32.const 0))) + ${checkRangeCode()}) +(invoke "test") +`); +checkRange(0x00000, 0x08000, 0x55); +checkRange(0x08000, 0x10000, 0xAA); + +// Zero len with dest offset out-of-bounds at the end of memory is allowed +print( +`(module + (memory 1 1) + (func (export "test") + (memory.copy (i32.const 0x10000) (i32.const 0x7000) (i32.const 0)))) +(invoke "test") +`); + +// Zero len with dest offset out-of-bounds past the end of memory is not allowed +print( +`(module + (memory 1 1) + (func (export "test") + (memory.copy (i32.const 0x20000) (i32.const 0x7000) (i32.const 0)))) +(assert_trap (invoke "test") "out of bounds") +`); + +// Zero len with src offset out-of-bounds at the end of memory is allowed +print( +`(module + (memory 1 1) + (func (export "test") + (memory.copy (i32.const 0x9000) (i32.const 0x10000) (i32.const 0)))) +(invoke "test") +`); + +// Zero len with src offset out-of-bounds past the end of memory is not allowed +print( +`(module + (memory 1 1) + (func (export "test") + (memory.copy (i32.const 0x9000) (i32.const 0x20000) (i32.const 0)))) +(assert_trap (invoke "test") "out of bounds") +`); + +// Zero len with both dest and src offsets out-of-bounds at the end of memory is allowed +print( +`(module + (memory 1 1) + (func (export "test") + (memory.copy (i32.const 0x10000) (i32.const 0x10000) (i32.const 0)))) +(invoke "test") +`); + +// Zero len with both dest and src offsets out-of-bounds past the end of memory is not allowed +print( +`(module + (memory 1 1) + (func (export "test") + (memory.copy (i32.const 0x20000) (i32.const 0x20000) (i32.const 0)))) +(assert_trap (invoke "test") "out of bounds") +`); + +// 100 random fills followed by 100 random copies, in a single-page buffer, +// followed by verification of the (now heavily mashed-around) buffer. +print( +`(module + (memory 1 1) + (func (export "test") + (memory.fill (i32.const 17767) (i32.const 1) (i32.const 1344)) + (memory.fill (i32.const 39017) (i32.const 2) (i32.const 1055)) + (memory.fill (i32.const 56401) (i32.const 3) (i32.const 988)) + (memory.fill (i32.const 37962) (i32.const 4) (i32.const 322)) + (memory.fill (i32.const 7977) (i32.const 5) (i32.const 1994)) + (memory.fill (i32.const 22714) (i32.const 6) (i32.const 3036)) + (memory.fill (i32.const 16882) (i32.const 7) (i32.const 2372)) + (memory.fill (i32.const 43491) (i32.const 8) (i32.const 835)) + (memory.fill (i32.const 124) (i32.const 9) (i32.const 1393)) + (memory.fill (i32.const 2132) (i32.const 10) (i32.const 2758)) + (memory.fill (i32.const 8987) (i32.const 11) (i32.const 3098)) + (memory.fill (i32.const 52711) (i32.const 12) (i32.const 741)) + (memory.fill (i32.const 3958) (i32.const 13) (i32.const 2823)) + (memory.fill (i32.const 49715) (i32.const 14) (i32.const 1280)) + (memory.fill (i32.const 50377) (i32.const 15) (i32.const 1466)) + (memory.fill (i32.const 20493) (i32.const 16) (i32.const 3158)) + (memory.fill (i32.const 47665) (i32.const 17) (i32.const 544)) + (memory.fill (i32.const 12451) (i32.const 18) (i32.const 2669)) + (memory.fill (i32.const 24869) (i32.const 19) (i32.const 2651)) + (memory.fill (i32.const 45317) (i32.const 20) (i32.const 1570)) + (memory.fill (i32.const 43096) (i32.const 21) (i32.const 1691)) + (memory.fill (i32.const 33886) (i32.const 22) (i32.const 646)) + (memory.fill (i32.const 48555) (i32.const 23) (i32.const 1858)) + (memory.fill (i32.const 53453) (i32.const 24) (i32.const 2657)) + (memory.fill (i32.const 30363) (i32.const 25) (i32.const 981)) + (memory.fill (i32.const 9300) (i32.const 26) (i32.const 1807)) + (memory.fill (i32.const 50190) (i32.const 27) (i32.const 487)) + (memory.fill (i32.const 62753) (i32.const 28) (i32.const 530)) + (memory.fill (i32.const 36316) (i32.const 29) (i32.const 943)) + (memory.fill (i32.const 6768) (i32.const 30) (i32.const 381)) + (memory.fill (i32.const 51262) (i32.const 31) (i32.const 3089)) + (memory.fill (i32.const 49729) (i32.const 32) (i32.const 658)) + (memory.fill (i32.const 44540) (i32.const 33) (i32.const 1702)) + (memory.fill (i32.const 33342) (i32.const 34) (i32.const 1092)) + (memory.fill (i32.const 50814) (i32.const 35) (i32.const 1410)) + (memory.fill (i32.const 47594) (i32.const 36) (i32.const 2204)) + (memory.fill (i32.const 54123) (i32.const 37) (i32.const 2394)) + (memory.fill (i32.const 55183) (i32.const 38) (i32.const 250)) + (memory.fill (i32.const 22620) (i32.const 39) (i32.const 2097)) + (memory.fill (i32.const 17132) (i32.const 40) (i32.const 3264)) + (memory.fill (i32.const 54331) (i32.const 41) (i32.const 3299)) + (memory.fill (i32.const 39474) (i32.const 42) (i32.const 2796)) + (memory.fill (i32.const 36156) (i32.const 43) (i32.const 2070)) + (memory.fill (i32.const 35308) (i32.const 44) (i32.const 2763)) + (memory.fill (i32.const 32731) (i32.const 45) (i32.const 312)) + (memory.fill (i32.const 63746) (i32.const 46) (i32.const 192)) + (memory.fill (i32.const 30974) (i32.const 47) (i32.const 596)) + (memory.fill (i32.const 16635) (i32.const 48) (i32.const 501)) + (memory.fill (i32.const 57002) (i32.const 49) (i32.const 686)) + (memory.fill (i32.const 34299) (i32.const 50) (i32.const 385)) + (memory.fill (i32.const 60881) (i32.const 51) (i32.const 903)) + (memory.fill (i32.const 61445) (i32.const 52) (i32.const 2390)) + (memory.fill (i32.const 46972) (i32.const 53) (i32.const 1441)) + (memory.fill (i32.const 25973) (i32.const 54) (i32.const 3162)) + (memory.fill (i32.const 5566) (i32.const 55) (i32.const 2135)) + (memory.fill (i32.const 35977) (i32.const 56) (i32.const 519)) + (memory.fill (i32.const 44892) (i32.const 57) (i32.const 3280)) + (memory.fill (i32.const 46760) (i32.const 58) (i32.const 1678)) + (memory.fill (i32.const 46607) (i32.const 59) (i32.const 3168)) + (memory.fill (i32.const 22449) (i32.const 60) (i32.const 1441)) + (memory.fill (i32.const 58609) (i32.const 61) (i32.const 663)) + (memory.fill (i32.const 32261) (i32.const 62) (i32.const 1671)) + (memory.fill (i32.const 3063) (i32.const 63) (i32.const 721)) + (memory.fill (i32.const 34025) (i32.const 64) (i32.const 84)) + (memory.fill (i32.const 33338) (i32.const 65) (i32.const 2029)) + (memory.fill (i32.const 36810) (i32.const 66) (i32.const 29)) + (memory.fill (i32.const 19147) (i32.const 67) (i32.const 3034)) + (memory.fill (i32.const 12616) (i32.const 68) (i32.const 1043)) + (memory.fill (i32.const 18276) (i32.const 69) (i32.const 3324)) + (memory.fill (i32.const 4639) (i32.const 70) (i32.const 1091)) + (memory.fill (i32.const 16158) (i32.const 71) (i32.const 1997)) + (memory.fill (i32.const 18204) (i32.const 72) (i32.const 2259)) + (memory.fill (i32.const 50532) (i32.const 73) (i32.const 3189)) + (memory.fill (i32.const 11028) (i32.const 74) (i32.const 1968)) + (memory.fill (i32.const 15962) (i32.const 75) (i32.const 1455)) + (memory.fill (i32.const 45406) (i32.const 76) (i32.const 1177)) + (memory.fill (i32.const 54137) (i32.const 77) (i32.const 1568)) + (memory.fill (i32.const 33083) (i32.const 78) (i32.const 1642)) + (memory.fill (i32.const 61028) (i32.const 79) (i32.const 3284)) + (memory.fill (i32.const 51729) (i32.const 80) (i32.const 223)) + (memory.fill (i32.const 4361) (i32.const 81) (i32.const 2171)) + (memory.fill (i32.const 57514) (i32.const 82) (i32.const 1322)) + (memory.fill (i32.const 55724) (i32.const 83) (i32.const 2648)) + (memory.fill (i32.const 24091) (i32.const 84) (i32.const 1045)) + (memory.fill (i32.const 43183) (i32.const 85) (i32.const 3097)) + (memory.fill (i32.const 32307) (i32.const 86) (i32.const 2796)) + (memory.fill (i32.const 3811) (i32.const 87) (i32.const 2010)) + (memory.fill (i32.const 54856) (i32.const 88) (i32.const 0)) + (memory.fill (i32.const 49941) (i32.const 89) (i32.const 2069)) + (memory.fill (i32.const 20411) (i32.const 90) (i32.const 2896)) + (memory.fill (i32.const 33826) (i32.const 91) (i32.const 192)) + (memory.fill (i32.const 9402) (i32.const 92) (i32.const 2195)) + (memory.fill (i32.const 12413) (i32.const 93) (i32.const 24)) + (memory.fill (i32.const 14091) (i32.const 94) (i32.const 577)) + (memory.fill (i32.const 44058) (i32.const 95) (i32.const 2089)) + (memory.fill (i32.const 36735) (i32.const 96) (i32.const 3436)) + (memory.fill (i32.const 23288) (i32.const 97) (i32.const 2765)) + (memory.fill (i32.const 6392) (i32.const 98) (i32.const 830)) + (memory.fill (i32.const 33307) (i32.const 99) (i32.const 1938)) + (memory.fill (i32.const 21941) (i32.const 100) (i32.const 2750)) + (memory.copy (i32.const 59214) (i32.const 54248) (i32.const 2098)) + (memory.copy (i32.const 63026) (i32.const 39224) (i32.const 230)) + (memory.copy (i32.const 51833) (i32.const 23629) (i32.const 2300)) + (memory.copy (i32.const 6708) (i32.const 23996) (i32.const 639)) + (memory.copy (i32.const 6990) (i32.const 33399) (i32.const 1097)) + (memory.copy (i32.const 19403) (i32.const 10348) (i32.const 3197)) + (memory.copy (i32.const 27308) (i32.const 54406) (i32.const 100)) + (memory.copy (i32.const 27221) (i32.const 43682) (i32.const 1717)) + (memory.copy (i32.const 60528) (i32.const 8629) (i32.const 119)) + (memory.copy (i32.const 5947) (i32.const 2308) (i32.const 658)) + (memory.copy (i32.const 4787) (i32.const 51631) (i32.const 2269)) + (memory.copy (i32.const 12617) (i32.const 19197) (i32.const 833)) + (memory.copy (i32.const 11854) (i32.const 46505) (i32.const 3300)) + (memory.copy (i32.const 11376) (i32.const 45012) (i32.const 2281)) + (memory.copy (i32.const 34186) (i32.const 6697) (i32.const 2572)) + (memory.copy (i32.const 4936) (i32.const 1690) (i32.const 1328)) + (memory.copy (i32.const 63164) (i32.const 7637) (i32.const 1670)) + (memory.copy (i32.const 44568) (i32.const 18344) (i32.const 33)) + (memory.copy (i32.const 43918) (i32.const 22348) (i32.const 1427)) + (memory.copy (i32.const 46637) (i32.const 49819) (i32.const 1434)) + (memory.copy (i32.const 63684) (i32.const 8755) (i32.const 834)) + (memory.copy (i32.const 33485) (i32.const 20131) (i32.const 3317)) + (memory.copy (i32.const 40575) (i32.const 54317) (i32.const 3201)) + (memory.copy (i32.const 25812) (i32.const 59254) (i32.const 2452)) + (memory.copy (i32.const 19678) (i32.const 56882) (i32.const 346)) + (memory.copy (i32.const 15852) (i32.const 35914) (i32.const 2430)) + (memory.copy (i32.const 11824) (i32.const 35574) (i32.const 300)) + (memory.copy (i32.const 59427) (i32.const 13957) (i32.const 3153)) + (memory.copy (i32.const 34299) (i32.const 60594) (i32.const 1281)) + (memory.copy (i32.const 8964) (i32.const 12276) (i32.const 943)) + (memory.copy (i32.const 2827) (i32.const 10425) (i32.const 1887)) + (memory.copy (i32.const 43194) (i32.const 43910) (i32.const 738)) + (memory.copy (i32.const 63038) (i32.const 18949) (i32.const 122)) + (memory.copy (i32.const 24044) (i32.const 44761) (i32.const 1755)) + (memory.copy (i32.const 22608) (i32.const 14755) (i32.const 702)) + (memory.copy (i32.const 11284) (i32.const 26579) (i32.const 1830)) + (memory.copy (i32.const 23092) (i32.const 20471) (i32.const 1064)) + (memory.copy (i32.const 57248) (i32.const 54770) (i32.const 2631)) + (memory.copy (i32.const 25492) (i32.const 1025) (i32.const 3113)) + (memory.copy (i32.const 49588) (i32.const 44220) (i32.const 975)) + (memory.copy (i32.const 28280) (i32.const 41722) (i32.const 2336)) + (memory.copy (i32.const 61289) (i32.const 230) (i32.const 2872)) + (memory.copy (i32.const 22480) (i32.const 52506) (i32.const 2197)) + (memory.copy (i32.const 40553) (i32.const 9578) (i32.const 1958)) + (memory.copy (i32.const 29004) (i32.const 20862) (i32.const 2186)) + (memory.copy (i32.const 53029) (i32.const 43955) (i32.const 1037)) + (memory.copy (i32.const 25476) (i32.const 35667) (i32.const 1650)) + (memory.copy (i32.const 58516) (i32.const 45819) (i32.const 1986)) + (memory.copy (i32.const 38297) (i32.const 5776) (i32.const 1955)) + (memory.copy (i32.const 28503) (i32.const 55364) (i32.const 2368)) + (memory.copy (i32.const 62619) (i32.const 18108) (i32.const 1356)) + (memory.copy (i32.const 50149) (i32.const 13861) (i32.const 382)) + (memory.copy (i32.const 16904) (i32.const 36341) (i32.const 1900)) + (memory.copy (i32.const 48098) (i32.const 11358) (i32.const 2807)) + (memory.copy (i32.const 28512) (i32.const 40362) (i32.const 323)) + (memory.copy (i32.const 35506) (i32.const 27856) (i32.const 1670)) + (memory.copy (i32.const 62970) (i32.const 53332) (i32.const 1341)) + (memory.copy (i32.const 14133) (i32.const 46312) (i32.const 644)) + (memory.copy (i32.const 29030) (i32.const 19074) (i32.const 496)) + (memory.copy (i32.const 44952) (i32.const 47577) (i32.const 2784)) + (memory.copy (i32.const 39559) (i32.const 44661) (i32.const 1350)) + (memory.copy (i32.const 10352) (i32.const 29274) (i32.const 1475)) + (memory.copy (i32.const 46911) (i32.const 46178) (i32.const 1467)) + (memory.copy (i32.const 4905) (i32.const 28740) (i32.const 1895)) + (memory.copy (i32.const 38012) (i32.const 57253) (i32.const 1751)) + (memory.copy (i32.const 26446) (i32.const 27223) (i32.const 1127)) + (memory.copy (i32.const 58835) (i32.const 24657) (i32.const 1063)) + (memory.copy (i32.const 61356) (i32.const 38790) (i32.const 766)) + (memory.copy (i32.const 44160) (i32.const 2284) (i32.const 1520)) + (memory.copy (i32.const 32740) (i32.const 47237) (i32.const 3014)) + (memory.copy (i32.const 11148) (i32.const 21260) (i32.const 1011)) + (memory.copy (i32.const 7665) (i32.const 31612) (i32.const 3034)) + (memory.copy (i32.const 18044) (i32.const 12987) (i32.const 3320)) + (memory.copy (i32.const 57306) (i32.const 55905) (i32.const 308)) + (memory.copy (i32.const 24675) (i32.const 16815) (i32.const 1155)) + (memory.copy (i32.const 19900) (i32.const 10115) (i32.const 722)) + (memory.copy (i32.const 2921) (i32.const 5935) (i32.const 2370)) + (memory.copy (i32.const 32255) (i32.const 50095) (i32.const 2926)) + (memory.copy (i32.const 15126) (i32.const 17299) (i32.const 2607)) + (memory.copy (i32.const 45575) (i32.const 28447) (i32.const 2045)) + (memory.copy (i32.const 55149) (i32.const 36113) (i32.const 2596)) + (memory.copy (i32.const 28461) (i32.const 54157) (i32.const 1168)) + (memory.copy (i32.const 47951) (i32.const 53385) (i32.const 3137)) + (memory.copy (i32.const 30646) (i32.const 45155) (i32.const 2649)) + (memory.copy (i32.const 5057) (i32.const 4295) (i32.const 52)) + (memory.copy (i32.const 6692) (i32.const 24195) (i32.const 441)) + (memory.copy (i32.const 32984) (i32.const 27117) (i32.const 3445)) + (memory.copy (i32.const 32530) (i32.const 59372) (i32.const 2785)) + (memory.copy (i32.const 34361) (i32.const 8962) (i32.const 2406)) + (memory.copy (i32.const 17893) (i32.const 54538) (i32.const 3381)) + (memory.copy (i32.const 22685) (i32.const 44151) (i32.const 136)) + (memory.copy (i32.const 59089) (i32.const 7077) (i32.const 1045)) + (memory.copy (i32.const 42945) (i32.const 55028) (i32.const 2389)) + (memory.copy (i32.const 44693) (i32.const 20138) (i32.const 877)) + (memory.copy (i32.const 36810) (i32.const 25196) (i32.const 3447)) + (memory.copy (i32.const 45742) (i32.const 31888) (i32.const 854)) + (memory.copy (i32.const 24236) (i32.const 31866) (i32.const 1377)) + (memory.copy (i32.const 33778) (i32.const 692) (i32.const 1594)) + (memory.copy (i32.const 60618) (i32.const 18585) (i32.const 2987)) + (memory.copy (i32.const 50370) (i32.const 41271) (i32.const 1406)) + ) + ${checkRangeCode()}) +(invoke "test") +`); +checkRange(0, 124, 0); +checkRange(124, 1517, 9); +checkRange(1517, 2132, 0); +checkRange(2132, 2827, 10); +checkRange(2827, 2921, 92); +checkRange(2921, 3538, 83); +checkRange(3538, 3786, 77); +checkRange(3786, 4042, 97); +checkRange(4042, 4651, 99); +checkRange(4651, 5057, 0); +checkRange(5057, 5109, 99); +checkRange(5109, 5291, 0); +checkRange(5291, 5524, 72); +checkRange(5524, 5691, 92); +checkRange(5691, 6552, 83); +checkRange(6552, 7133, 77); +checkRange(7133, 7665, 99); +checkRange(7665, 8314, 0); +checkRange(8314, 8360, 62); +checkRange(8360, 8793, 86); +checkRange(8793, 8979, 83); +checkRange(8979, 9373, 79); +checkRange(9373, 9518, 95); +checkRange(9518, 9934, 59); +checkRange(9934, 10087, 77); +checkRange(10087, 10206, 5); +checkRange(10206, 10230, 77); +checkRange(10230, 10249, 41); +checkRange(10249, 11148, 83); +checkRange(11148, 11356, 74); +checkRange(11356, 11380, 93); +checkRange(11380, 11939, 74); +checkRange(11939, 12159, 68); +checkRange(12159, 12575, 83); +checkRange(12575, 12969, 79); +checkRange(12969, 13114, 95); +checkRange(13114, 14133, 59); +checkRange(14133, 14404, 76); +checkRange(14404, 14428, 57); +checkRange(14428, 14458, 59); +checkRange(14458, 14580, 32); +checkRange(14580, 14777, 89); +checkRange(14777, 15124, 59); +checkRange(15124, 15126, 36); +checkRange(15126, 15192, 100); +checkRange(15192, 15871, 96); +checkRange(15871, 15998, 95); +checkRange(15998, 17017, 59); +checkRange(17017, 17288, 76); +checkRange(17288, 17312, 57); +checkRange(17312, 17342, 59); +checkRange(17342, 17464, 32); +checkRange(17464, 17661, 89); +checkRange(17661, 17727, 59); +checkRange(17727, 17733, 5); +checkRange(17733, 17893, 96); +checkRange(17893, 18553, 77); +checkRange(18553, 18744, 42); +checkRange(18744, 18801, 76); +checkRange(18801, 18825, 57); +checkRange(18825, 18876, 59); +checkRange(18876, 18885, 77); +checkRange(18885, 18904, 41); +checkRange(18904, 19567, 83); +checkRange(19567, 20403, 96); +checkRange(20403, 21274, 77); +checkRange(21274, 21364, 100); +checkRange(21364, 21468, 74); +checkRange(21468, 21492, 93); +checkRange(21492, 22051, 74); +checkRange(22051, 22480, 68); +checkRange(22480, 22685, 100); +checkRange(22685, 22694, 68); +checkRange(22694, 22821, 10); +checkRange(22821, 22869, 100); +checkRange(22869, 24107, 97); +checkRange(24107, 24111, 37); +checkRange(24111, 24236, 77); +checkRange(24236, 24348, 72); +checkRange(24348, 24515, 92); +checkRange(24515, 24900, 83); +checkRange(24900, 25136, 95); +checkRange(25136, 25182, 85); +checkRange(25182, 25426, 68); +checkRange(25426, 25613, 89); +checkRange(25613, 25830, 96); +checkRange(25830, 26446, 100); +checkRange(26446, 26517, 10); +checkRange(26517, 27468, 92); +checkRange(27468, 27503, 95); +checkRange(27503, 27573, 77); +checkRange(27573, 28245, 92); +checkRange(28245, 28280, 95); +checkRange(28280, 29502, 77); +checkRange(29502, 29629, 42); +checkRange(29629, 30387, 83); +checkRange(30387, 30646, 77); +checkRange(30646, 31066, 92); +checkRange(31066, 31131, 77); +checkRange(31131, 31322, 42); +checkRange(31322, 31379, 76); +checkRange(31379, 31403, 57); +checkRange(31403, 31454, 59); +checkRange(31454, 31463, 77); +checkRange(31463, 31482, 41); +checkRange(31482, 31649, 83); +checkRange(31649, 31978, 72); +checkRange(31978, 32145, 92); +checkRange(32145, 32530, 83); +checkRange(32530, 32766, 95); +checkRange(32766, 32812, 85); +checkRange(32812, 33056, 68); +checkRange(33056, 33660, 89); +checkRange(33660, 33752, 59); +checkRange(33752, 33775, 36); +checkRange(33775, 33778, 32); +checkRange(33778, 34603, 9); +checkRange(34603, 35218, 0); +checkRange(35218, 35372, 10); +checkRange(35372, 35486, 77); +checkRange(35486, 35605, 5); +checkRange(35605, 35629, 77); +checkRange(35629, 35648, 41); +checkRange(35648, 36547, 83); +checkRange(36547, 36755, 74); +checkRange(36755, 36767, 93); +checkRange(36767, 36810, 83); +checkRange(36810, 36839, 100); +checkRange(36839, 37444, 96); +checkRange(37444, 38060, 100); +checkRange(38060, 38131, 10); +checkRange(38131, 39082, 92); +checkRange(39082, 39117, 95); +checkRange(39117, 39187, 77); +checkRange(39187, 39859, 92); +checkRange(39859, 39894, 95); +checkRange(39894, 40257, 77); +checkRange(40257, 40344, 89); +checkRange(40344, 40371, 59); +checkRange(40371, 40804, 77); +checkRange(40804, 40909, 5); +checkRange(40909, 42259, 92); +checkRange(42259, 42511, 77); +checkRange(42511, 42945, 83); +checkRange(42945, 43115, 77); +checkRange(43115, 43306, 42); +checkRange(43306, 43363, 76); +checkRange(43363, 43387, 57); +checkRange(43387, 43438, 59); +checkRange(43438, 43447, 77); +checkRange(43447, 43466, 41); +checkRange(43466, 44129, 83); +checkRange(44129, 44958, 96); +checkRange(44958, 45570, 77); +checkRange(45570, 45575, 92); +checkRange(45575, 45640, 77); +checkRange(45640, 45742, 42); +checkRange(45742, 45832, 72); +checkRange(45832, 45999, 92); +checkRange(45999, 46384, 83); +checkRange(46384, 46596, 95); +checkRange(46596, 46654, 92); +checkRange(46654, 47515, 83); +checkRange(47515, 47620, 77); +checkRange(47620, 47817, 79); +checkRange(47817, 47951, 95); +checkRange(47951, 48632, 100); +checkRange(48632, 48699, 97); +checkRange(48699, 48703, 37); +checkRange(48703, 49764, 77); +checkRange(49764, 49955, 42); +checkRange(49955, 50012, 76); +checkRange(50012, 50036, 57); +checkRange(50036, 50087, 59); +checkRange(50087, 50096, 77); +checkRange(50096, 50115, 41); +checkRange(50115, 50370, 83); +checkRange(50370, 51358, 92); +checkRange(51358, 51610, 77); +checkRange(51610, 51776, 83); +checkRange(51776, 51833, 89); +checkRange(51833, 52895, 100); +checkRange(52895, 53029, 97); +checkRange(53029, 53244, 68); +checkRange(53244, 54066, 100); +checkRange(54066, 54133, 97); +checkRange(54133, 54137, 37); +checkRange(54137, 55198, 77); +checkRange(55198, 55389, 42); +checkRange(55389, 55446, 76); +checkRange(55446, 55470, 57); +checkRange(55470, 55521, 59); +checkRange(55521, 55530, 77); +checkRange(55530, 55549, 41); +checkRange(55549, 56212, 83); +checkRange(56212, 57048, 96); +checkRange(57048, 58183, 77); +checkRange(58183, 58202, 41); +checkRange(58202, 58516, 83); +checkRange(58516, 58835, 95); +checkRange(58835, 58855, 77); +checkRange(58855, 59089, 95); +checkRange(59089, 59145, 77); +checkRange(59145, 59677, 99); +checkRange(59677, 60134, 0); +checkRange(60134, 60502, 89); +checkRange(60502, 60594, 59); +checkRange(60594, 60617, 36); +checkRange(60617, 60618, 32); +checkRange(60618, 60777, 42); +checkRange(60777, 60834, 76); +checkRange(60834, 60858, 57); +checkRange(60858, 60909, 59); +checkRange(60909, 60918, 77); +checkRange(60918, 60937, 41); +checkRange(60937, 61600, 83); +checkRange(61600, 62436, 96); +checkRange(62436, 63307, 77); +checkRange(63307, 63397, 100); +checkRange(63397, 63501, 74); +checkRange(63501, 63525, 93); +checkRange(63525, 63605, 74); +checkRange(63605, 63704, 100); +checkRange(63704, 63771, 97); +checkRange(63771, 63775, 37); +checkRange(63775, 64311, 77); +checkRange(64311, 64331, 26); +checkRange(64331, 64518, 92); +checkRange(64518, 64827, 11); +checkRange(64827, 64834, 26); +checkRange(64834, 65536, 0); diff --git a/test/meta/generate_memory_fill.js b/test/meta/generate_memory_fill.js new file mode 100644 index 0000000000..0dba569e9b --- /dev/null +++ b/test/meta/generate_memory_fill.js @@ -0,0 +1,157 @@ +// This program generates .wast code that contains all the spec tests for +// memory.fill. See `Makefile`. + +print_origin("generate_memory_fill.js"); + +let PREAMBLE = + `(memory 1 1) + ${checkRangeCode()}`; + +// Range valid +print( +` +(module + ${PREAMBLE} + (func (export "test") + (memory.fill (i32.const 0xFF00) (i32.const 0x55) (i32.const 256)))) +(invoke "test") +`); +checkRange(0x00000, 0x0FF00, 0x00) +checkRange(0x0FF00, 0x10000, 0x55) + +// Range invalid +print( +`(module + ${PREAMBLE} + (func (export "test") + (memory.fill (i32.const 0xFF00) (i32.const 0x55) (i32.const 257)))) +(assert_trap (invoke "test") "out of bounds memory access") +`); + +// Wraparound the end of 32-bit offset space +print( +`(module + ${PREAMBLE} + (func (export "test") + (memory.fill (i32.const 0xFFFFFF00) (i32.const 0x55) (i32.const 257)))) +(assert_trap (invoke "test") "out of bounds memory access") +`); + +// Zero len with offset in-bounds is a no-op +print( +`(module + ${PREAMBLE} + (func (export "test") + (memory.fill (i32.const 0x12) (i32.const 0x55) (i32.const 0)))) +(invoke "test") +`); +checkRange(0x00000, 0x10000, 0x00); + +// Zero len with offset out-of-bounds at the end of memory is allowed +print( +`(module + ${PREAMBLE} + (func (export "test") + (memory.fill (i32.const 0x10000) (i32.const 0x55) (i32.const 0)))) +(invoke "test") +`); + +// Zero len with offset out-of-bounds past the end of memory is not allowed +print( +`(module + ${PREAMBLE} + (func (export "test") + (memory.fill (i32.const 0x20000) (i32.const 0x55) (i32.const 0)))) +(assert_trap (invoke "test") "out of bounds") +`); + +// Very large range +print( +`(module + ${PREAMBLE} + (func (export "test") + (memory.fill (i32.const 0x1) (i32.const 0xAA) (i32.const 0xFFFE)))) +(invoke "test") +`); +checkRange(0x00000, 0x00001, 0x00); +checkRange(0x00001, 0x0FFFF, 0xAA); +checkRange(0x0FFFF, 0x10000, 0x00); + +// Sequencing +print( +` +(module + ${PREAMBLE} + (func (export "test") + (memory.fill (i32.const 0x12) (i32.const 0x55) (i32.const 10)) + (memory.fill (i32.const 0x15) (i32.const 0xAA) (i32.const 4)))) +(invoke "test") +`); +checkRange(0x0, 0x12+0, 0x00); +checkRange(0x12+0, 0x12+3, 0x55); +checkRange(0x12+3, 0x12+7, 0xAA); +checkRange(0x12+7, 0x12+10, 0x55); +checkRange(0x12+10, 0x10000, 0x00); + +// Sundry compilation failures. + +// Module doesn't have a memory. +print( +`(assert_invalid + (module + (func (export "testfn") + (memory.fill (i32.const 10) (i32.const 20) (i32.const 30)))) + "unknown memory 0") +`); + +// Invalid argument types. TODO: We can add anyref, funcref, etc here. +{ + const tys = ['i32', 'f32', 'i64', 'f64']; + for (let ty1 of tys) { + for (let ty2 of tys) { + for (let ty3 of tys) { + if (ty1 == 'i32' && ty2 == 'i32' && ty3 == 'i32') + continue; // this is the only valid case + print( +`(assert_invalid + (module + (memory 1 1) + (func (export "testfn") + (memory.fill (${ty1}.const 10) (${ty2}.const 20) (${ty3}.const 30)))) + "type mismatch") +`); + }}} +} + +// memory.fill: out of bounds, and should not perform a partial fill. +// +// Arithmetic overflow of memory offset + len should not affect the behavior, we +// should still fill up to the limit. + +function mem_fill(min, max, shared, backup, write=backup*2) { + print( +`(module + (memory ${min} ${max} ${shared}) + ${checkRangeCode()} + (func (export "run") (param $offs i32) (param $val i32) (param $len i32) + (memory.fill (local.get $offs) (local.get $val) (local.get $len)))) +`); + // A fill past the end should throw *and* not have performed a partial fill + let offs = min*PAGESIZE - backup; + let val = 37; + print( +`(assert_trap (invoke "run" (i32.const ${offs}) (i32.const ${val}) (i32.const ${write})) + "out of bounds") +`); + checkRange(0, min, 0); +} + +mem_fill(1, 1, "", 256); +mem_fill(1, 1, "", 257); +mem_fill(1, 1, "", 257, 0xFFFFFFFF); // offs + len overflows 32-bit + +if (WITH_SHARED_MEMORY) { + mem_fill(2, 4, "shared", 256); + mem_fill(2, 4, "shared", 257); + mem_fill(2, 4, "shared", 257, 0xFFFFFFFF); // offs + len overflows 32-bit +} diff --git a/test/meta/generate_memory_init.js b/test/meta/generate_memory_init.js new file mode 100644 index 0000000000..0b5d7f6505 --- /dev/null +++ b/test/meta/generate_memory_init.js @@ -0,0 +1,294 @@ +// This program generates .wast code that contains all the spec tests for +// memory.init and data.drop. See `Makefile`. + +print_origin("generate_memory_init.js"); + +// In-bounds tests. + +function mem_test(instruction, expected_result_vector) { + print( +` +(module + (memory (export "memory0") 1 1) + (data (i32.const 2) "\\03\\01\\04\\01") + (data "\\02\\07\\01\\08") + (data (i32.const 12) "\\07\\05\\02\\03\\06") + (data "\\05\\09\\02\\07\\06") + (func (export "test") + ${instruction}) + (func (export "load8_u") (param i32) (result i32) + (i32.load8_u (local.get 0)))) + +(invoke "test") +`); + for (let i = 0; i < expected_result_vector.length; i++) { + print(`(assert_return (invoke "load8_u" (i32.const ${i})) (i32.const ${expected_result_vector[i]}))`); + } +} + +const e = 0; + +// This just gives the initial state of the memory, with its active +// initialisers applied. +mem_test("(nop)", + [e,e,3,1,4, 1,e,e,e,e, e,e,7,5,2, 3,6,e,e,e, e,e,e,e,e, e,e,e,e,e]); + +// Passive init that overwrites all-zero entries +mem_test("(memory.init 1 (i32.const 7) (i32.const 0) (i32.const 4))", + [e,e,3,1,4, 1,e,2,7,1, 8,e,7,5,2, 3,6,e,e,e, e,e,e,e,e, e,e,e,e,e]); + +// Passive init that overwrites existing active-init-created entries +mem_test("(memory.init 3 (i32.const 15) (i32.const 1) (i32.const 3))", + [e,e,3,1,4, 1,e,e,e,e, e,e,7,5,2, 9,2,7,e,e, e,e,e,e,e, e,e,e,e,e]); + +// Perform active and passive initialisation and then multiple copies +mem_test(`(memory.init 1 (i32.const 7) (i32.const 0) (i32.const 4)) + (data.drop 1) + (memory.init 3 (i32.const 15) (i32.const 1) (i32.const 3)) + (data.drop 3) + (memory.copy (i32.const 20) (i32.const 15) (i32.const 5)) + (memory.copy (i32.const 21) (i32.const 29) (i32.const 1)) + (memory.copy (i32.const 24) (i32.const 10) (i32.const 1)) + (memory.copy (i32.const 13) (i32.const 11) (i32.const 4)) + (memory.copy (i32.const 19) (i32.const 20) (i32.const 5))`, + [e,e,3,1,4, 1,e,2,7,1, 8,e,7,e,7, 5,2,7,e,9, e,7,e,8,8, e,e,e,e,e]); + +// Miscellaneous + +let PREAMBLE = + `(memory 1) + (data "\\37")`; + +// drop with no memory +print( +`(assert_invalid + (module + (func (export "test") + (data.drop 0))) + "unknown memory 0") +`); + +// drop with data seg ix out of range +print( +`(assert_invalid + (module + ${PREAMBLE} + (func (export "test") + (data.drop 4))) + "unknown data segment") +`); + +// drop, then drop +print( +`(module + ${PREAMBLE} + (func (export "test") + (data.drop 0) + (data.drop 0))) +(invoke "test") +`); + +// drop, then init +print( +`(module + ${PREAMBLE} + (func (export "test") + (data.drop 0) + (memory.init 0 (i32.const 1234) (i32.const 1) (i32.const 1)))) +(assert_trap (invoke "test") "out of bounds") +`); + +// init with data seg ix indicating an active segment +print( +`(module + (memory 1) + (data (i32.const 0) "\\37") + (func (export "test") + (memory.init 0 (i32.const 1234) (i32.const 1) (i32.const 1)))) +(assert_trap (invoke "test") "out of bounds") +`); + +// init with no memory +print( +`(assert_invalid + (module + (func (export "test") + (memory.init 1 (i32.const 1234) (i32.const 1) (i32.const 1)))) + "unknown memory 0") +`); + +// init with data seg ix out of range +print( +`(assert_invalid + (module + ${PREAMBLE} + (func (export "test") + (memory.init 1 (i32.const 1234) (i32.const 1) (i32.const 1)))) + "unknown data segment 1") +`); + +// init, using a data seg ix more than once is OK +print( +`(module + ${PREAMBLE} + (func (export "test") + (memory.init 0 (i32.const 1) (i32.const 0) (i32.const 1)) + (memory.init 0 (i32.const 1) (i32.const 0) (i32.const 1)))) +(invoke "test") +`); + +// init: seg ix is valid passive, but length to copy > len of seg +print( +`(module + ${PREAMBLE} + (func (export "test") + (memory.init 0 (i32.const 1234) (i32.const 0) (i32.const 5)))) +(assert_trap (invoke "test") "out of bounds") +`); + +// init: seg ix is valid passive, but implies copying beyond end of seg +print( +`(module + ${PREAMBLE} + (func (export "test") + (memory.init 0 (i32.const 1234) (i32.const 2) (i32.const 3)))) +(assert_trap (invoke "test") "out of bounds") +`); + +// init: seg ix is valid passive, but implies copying beyond end of dst +print( +`(module + ${PREAMBLE} + (func (export "test") + (memory.init 0 (i32.const 0xFFFE) (i32.const 1) (i32.const 3)))) +(assert_trap (invoke "test") "out of bounds") +`); + +// init: seg ix is valid passive, src offset past the end, zero len is invalid +print( +`(module + ${PREAMBLE} + (func (export "test") + (memory.init 0 (i32.const 1234) (i32.const 4) (i32.const 0)))) +(assert_trap (invoke "test") "out of bounds") +`); + +// init: seg ix is valid passive, zero len, src offset at the end +print( +`(module + ${PREAMBLE} + (func (export "test") + (memory.init 0 (i32.const 1234) (i32.const 1) (i32.const 0)))) +(invoke "test") +`); + +// init: seg ix is valid passive, dst offset past the end, zero len is invalid +print( +`(module + ${PREAMBLE} + (func (export "test") + (memory.init 0 (i32.const 0x10001) (i32.const 0) (i32.const 0)))) +(assert_trap (invoke "test") "out of bounds") +`); + +// init: seg ix is valid passive, zero len, but dst offset at the end +print( +`(module + ${PREAMBLE} + (func (export "test") + (memory.init 0 (i32.const 0x10000) (i32.const 0) (i32.const 0)))) +(invoke "test") +`); + +// init: seg ix is valid passive, zero len, dst and src offsets at the end +print( +`(module + ${PREAMBLE} + (func (export "test") + (memory.init 0 (i32.const 0x10000) (i32.const 1) (i32.const 0)))) +(invoke "test") +`); + +// init: seg ix is valid passive, src and dst offset past the end, zero len is +// invalid +print( +`(module + ${PREAMBLE} + (func (export "test") + (memory.init 0 (i32.const 0x10001) (i32.const 4) (i32.const 0)))) +(assert_trap (invoke "test") "out of bounds") +`); + +// invalid argument types. TODO: can add anyfunc etc here. +{ + const tys = ['i32', 'f32', 'i64', 'f64']; + + for (let ty1 of tys) { + for (let ty2 of tys) { + for (let ty3 of tys) { + if (ty1 == 'i32' && ty2 == 'i32' && ty3 == 'i32') + continue; // this is the only valid case + print( +`(assert_invalid + (module + ${PREAMBLE} + (func (export "test") + (memory.init 0 (${ty1}.const 1) (${ty2}.const 1) (${ty3}.const 1)))) + "type mismatch") +`); + }}} +} + +// memory.init: out of bounds of the memory or the segment, but should perform +// the operation up to the appropriate bound. +// +// Arithmetic overflow of memoffset + len or of bufferoffset + len should not +// affect the behavior. + +// Note, the length of the data segment is 16. +const mem_init_len = 16; + +function mem_init(min, max, shared, backup, write) { + print( +`(module + (memory ${min} ${max} ${shared}) + (data "\\42\\42\\42\\42\\42\\42\\42\\42\\42\\42\\42\\42\\42\\42\\42\\42") + ${checkRangeCode()} + (func (export "run") (param $offs i32) (param $len i32) + (memory.init 0 (local.get $offs) (i32.const 0) (local.get $len)))) +`); + // A fill writing past the end of the memory should throw *and* have filled + // all the way up to the end. + // + // A fill reading past the end of the segment should throw *and* have filled + // memory with as much data as was available. + let offs = min*PAGESIZE - backup; + print( +`(assert_trap (invoke "run" (i32.const ${offs}) (i32.const ${write})) + "out of bounds") +`); + checkRange(0, min, 0); +} + +// We exceed the bounds of the memory but not of the data segment +mem_init(1, 1, "", Math.floor(mem_init_len/2), mem_init_len); +mem_init(1, 1, "", Math.floor(mem_init_len/2)+1, mem_init_len); +if (WITH_SHARED_MEMORY) { + mem_init(2, 4, "shared", Math.floor(mem_init_len/2), mem_init_len); + mem_init(2, 4, "shared", Math.floor(mem_init_len/2)+1, mem_init_len); +} + +// We exceed the bounds of the data segment but not the memory +mem_init(1, 1, "", mem_init_len*4, mem_init_len*2-2); +mem_init(1, 1, "", mem_init_len*4-1, mem_init_len*2-1); +if (WITH_SHARED_MEMORY) { + mem_init(2, 4, "shared", mem_init_len*4, mem_init_len*2-2); + mem_init(2, 4, "shared", mem_init_len*4-1, mem_init_len*2-1); +} + +// We arithmetically overflow the memory limit but not the segment limit +mem_init(1, "", "", Math.floor(mem_init_len/2), 0xFFFFFF00); + +// We arithmetically overflow the segment limit but not the memory limit +mem_init(1, "", "", PAGESIZE, 0xFFFFFFFC); + diff --git a/test/meta/generate_table_copy.js b/test/meta/generate_table_copy.js new file mode 100644 index 0000000000..867189445e --- /dev/null +++ b/test/meta/generate_table_copy.js @@ -0,0 +1,317 @@ +// This program generates .wast code that contains all the spec tests for +// table.copy. See `Makefile`. + +print_origin("generate_table_copy.js"); + +// This module "a" exports 5 functions ... + +function emit_a() { + print( +` +(module + (func (export "ef0") (result i32) (i32.const 0)) + (func (export "ef1") (result i32) (i32.const 1)) + (func (export "ef2") (result i32) (i32.const 2)) + (func (export "ef3") (result i32) (i32.const 3)) + (func (export "ef4") (result i32) (i32.const 4)) +) +(register "a")`); +} + +// ... and this one imports those 5 functions. It adds 5 of its own, creates a +// 30 element table using both active and passive initialisers, with a mixture +// of the imported and local functions. |test| is exported. It uses the +// supplied |insn| to modify the table somehow. |check| will then indirect-call +// the table entry number specified as a parameter. That will either return a +// value 0 to 9 indicating the function called, or will throw an exception if +// the table entry is empty. + +function emit_b(insn) { + print( +` +(module + (type (func (result i32))) ;; type #0 + (import "a" "ef0" (func (result i32))) ;; index 0 + (import "a" "ef1" (func (result i32))) + (import "a" "ef2" (func (result i32))) + (import "a" "ef3" (func (result i32))) + (import "a" "ef4" (func (result i32))) ;; index 4 + (table 30 30 funcref) + (elem (i32.const 2) 3 1 4 1) + (elem funcref + (ref.func 2) (ref.func 7) (ref.func 1) (ref.func 8)) + (elem (i32.const 12) 7 5 2 3 6) + (elem funcref + (ref.func 5) (ref.func 9) (ref.func 2) (ref.func 7) (ref.func 6)) + (func (result i32) (i32.const 5)) ;; index 5 + (func (result i32) (i32.const 6)) + (func (result i32) (i32.const 7)) + (func (result i32) (i32.const 8)) + (func (result i32) (i32.const 9)) ;; index 9 + (func (export "test") + ${insn}) + (func (export "check") (param i32) (result i32) + (call_indirect (type 0) (local.get 0))) +) +`); +} + +// This is the test driver. It constructs the abovementioned module, using the +// given |instruction| to modify the table, and then probes the table by making +// indirect calls, one for each element of |expected_result_vector|. The +// results are compared to those in the vector. + +function tab_test(instruction, expected_result_vector) { + emit_b(instruction); + print(`(invoke "test")`); + for (let i = 0; i < expected_result_vector.length; i++) { + let expected = expected_result_vector[i]; + if (expected === undefined) { + print(`(assert_trap (invoke "check" (i32.const ${i})) "uninitialized element")`); + } else { + print(`(assert_return (invoke "check" (i32.const ${i})) (i32.const ${expected}))`); + } + } +} + +emit_a(); + +// Using 'e' for empty (undefined) spaces in the table, to make it easier +// to count through the vector entries when debugging. +let e = undefined; + +// This just gives the initial state of the table, with its active +// initialisers applied +tab_test("(nop)", + [e,e,3,1,4, 1,e,e,e,e, e,e,7,5,2, 3,6,e,e,e, e,e,e,e,e, e,e,e,e,e]); + +// Copy non-null over non-null +tab_test("(table.copy (i32.const 13) (i32.const 2) (i32.const 3))", + [e,e,3,1,4, 1,e,e,e,e, e,e,7,3,1, 4,6,e,e,e, e,e,e,e,e, e,e,e,e,e]); + +// Copy non-null over null +tab_test("(table.copy (i32.const 25) (i32.const 15) (i32.const 2))", + [e,e,3,1,4, 1,e,e,e,e, e,e,7,5,2, 3,6,e,e,e, e,e,e,e,e, 3,6,e,e,e]); + +// Copy null over non-null +tab_test("(table.copy (i32.const 13) (i32.const 25) (i32.const 3))", + [e,e,3,1,4, 1,e,e,e,e, e,e,7,e,e, e,6,e,e,e, e,e,e,e,e, e,e,e,e,e]); + +// Copy null over null +tab_test("(table.copy (i32.const 20) (i32.const 22) (i32.const 4))", + [e,e,3,1,4, 1,e,e,e,e, e,e,7,5,2, 3,6,e,e,e, e,e,e,e,e, e,e,e,e,e]); + +// Copy null and non-null entries, non overlapping +tab_test("(table.copy (i32.const 25) (i32.const 1) (i32.const 3))", + [e,e,3,1,4, 1,e,e,e,e, e,e,7,5,2, 3,6,e,e,e, e,e,e,e,e, e,3,1,e,e]); + +// Copy null and non-null entries, overlapping, backwards +tab_test("(table.copy (i32.const 10) (i32.const 12) (i32.const 7))", + [e,e,3,1,4, 1,e,e,e,e, 7,5,2,3,6, e,e,e,e,e, e,e,e,e,e, e,e,e,e,e]); + +// Copy null and non-null entries, overlapping, forwards +tab_test("(table.copy (i32.const 12) (i32.const 10) (i32.const 7))", + [e,e,3,1,4, 1,e,e,e,e, e,e,e,e,7, 5,2,3,6,e, e,e,e,e,e, e,e,e,e,e]); + +// Out-of-bounds checks. + +function do_test(insn1, insn2, errText) +{ + print(` +(module + (table 30 30 funcref) + (elem (i32.const 2) 3 1 4 1) + (elem funcref + (ref.func 2) (ref.func 7) (ref.func 1) (ref.func 8)) + (elem (i32.const 12) 7 5 2 3 6) + (elem funcref + (ref.func 5) (ref.func 9) (ref.func 2) (ref.func 7) (ref.func 6)) + (func (result i32) (i32.const 0)) + (func (result i32) (i32.const 1)) + (func (result i32) (i32.const 2)) + (func (result i32) (i32.const 3)) + (func (result i32) (i32.const 4)) + (func (result i32) (i32.const 5)) + (func (result i32) (i32.const 6)) + (func (result i32) (i32.const 7)) + (func (result i32) (i32.const 8)) + (func (result i32) (i32.const 9)) + (func (export "test") + ${insn1} + ${insn2})) +`); + + if (errText !== undefined) { + print(`(assert_trap (invoke "test") "${errText}")`); + } else { + print(`(invoke "test")`); + } +} + +function tab_test2(insn1, insn2, errKind, errText) { + do_test(insn1, insn2, errKind, errText); +} + +function tab_test_nofail(insn1, insn2) { + do_test(insn1, insn2, undefined, undefined); +} + +// Here we test the boundary-failure cases. The table's valid indices are 0..29 +// inclusive. + +// copy: dst range invalid +tab_test2("(table.copy (i32.const 28) (i32.const 1) (i32.const 3))", + "", + "out of bounds"); + +// copy: dst wraparound end of 32 bit offset space +tab_test2("(table.copy (i32.const 0xFFFFFFFE) (i32.const 1) (i32.const 2))", + "", + "out of bounds"); + +// copy: src range invalid +tab_test2("(table.copy (i32.const 15) (i32.const 25) (i32.const 6))", + "", + "out of bounds"); + +// copy: src wraparound end of 32 bit offset space +tab_test2("(table.copy (i32.const 15) (i32.const 0xFFFFFFFE) (i32.const 2))", + "", + "out of bounds"); + +// copy: zero length with both offsets in-bounds is OK +tab_test_nofail( + "(table.copy (i32.const 15) (i32.const 25) (i32.const 0))", + ""); + +// copy: zero length with dst offset out of bounds at the end of the table is allowed +tab_test2("(table.copy (i32.const 30) (i32.const 15) (i32.const 0))", + "", + undefined); + +// copy: zero length with dst offset out of bounds past the end of the table is not allowed +tab_test2("(table.copy (i32.const 31) (i32.const 15) (i32.const 0))", + "", + "out of bounds"); + +// copy: zero length with src offset out of bounds at the end of the table is allowed +tab_test2("(table.copy (i32.const 15) (i32.const 30) (i32.const 0))", + "", + undefined); + +// copy: zero length with src offset out of bounds past the end of the table is not allowed +tab_test2("(table.copy (i32.const 15) (i32.const 31) (i32.const 0))", + "", + "out of bounds"); + +// copy: zero length with both dst and src offset out of bounds at the end of the table is allowed +tab_test2("(table.copy (i32.const 30) (i32.const 30) (i32.const 0))", + "", + undefined); + +// copy: zero length with both dst and src offset out of bounds past the end of the table is not allowed +tab_test2("(table.copy (i32.const 31) (i32.const 31) (i32.const 0))", + "", + "out of bounds"); + +// table.copy: out of bounds of the table for the source or target, but should +// perform the operation up to the appropriate bound. Major cases: +// +// - non-overlapping regions +// - overlapping regions with src > dest +// - overlapping regions with src == dest +// - overlapping regions with src < dest +// - arithmetic overflow on src addresses +// - arithmetic overflow on target addresses +// +// for each of those, +// +// - src address oob +// - target address oob +// - both oob + +const tbl_copy_len = 16; + +function tbl_copy(min, max, srcOffs, targetOffs, len) { + let copyDown = srcOffs < targetOffs; + let tblLength = min; + + let targetAvail = tblLength - targetOffs; + let srcAvail = tblLength - srcOffs; + let targetLim = targetOffs + Math.min(len, targetAvail, srcAvail); + let srcLim = srcOffs + Math.min(len, targetAvail, srcAvail); + + print( + ` +(module + (type (func (result i32))) + (table ${min} ${max} funcref) + (elem (i32.const ${srcOffs}) + ${(function () { + var s = ""; + for (let i=srcOffs, j=0; i < srcLim; i++, j++) + s += " $f" + j; + return s; + })()}) + (func $f0 (export "f0") (result i32) (i32.const 0)) + (func $f1 (export "f1") (result i32) (i32.const 1)) + (func $f2 (export "f2") (result i32) (i32.const 2)) + (func $f3 (export "f3") (result i32) (i32.const 3)) + (func $f4 (export "f4") (result i32) (i32.const 4)) + (func $f5 (export "f5") (result i32) (i32.const 5)) + (func $f6 (export "f6") (result i32) (i32.const 6)) + (func $f7 (export "f7") (result i32) (i32.const 7)) + (func $f8 (export "f8") (result i32) (i32.const 8)) + (func $f9 (export "f9") (result i32) (i32.const 9)) + (func $f10 (export "f10") (result i32) (i32.const 10)) + (func $f11 (export "f11") (result i32) (i32.const 11)) + (func $f12 (export "f12") (result i32) (i32.const 12)) + (func $f13 (export "f13") (result i32) (i32.const 13)) + (func $f14 (export "f14") (result i32) (i32.const 14)) + (func $f15 (export "f15") (result i32) (i32.const 15)) + (func (export "test") (param $n i32) (result i32) + (call_indirect (type 0) (local.get $n))) + (func (export "run") (param $targetOffs i32) (param $srcOffs i32) (param $len i32) + (table.copy (local.get $targetOffs) (local.get $srcOffs) (local.get $len)))) +`); + + let immediateOOB = copyDown && (srcOffs + len > tblLength || targetOffs + len > tblLength); + + print(`(assert_trap (invoke "run" (i32.const ${targetOffs}) (i32.const ${srcOffs}) (i32.const ${len})) + "out of bounds")`); + + var s = 0; + var i = 0; + for (i=0; i < tblLength; i++ ) { + if (i >= srcOffs && i < srcLim) { + print(`(assert_return (invoke "test" (i32.const ${i})) (i32.const ${s++}))`); + continue; + } + print(`(assert_trap (invoke "test" (i32.const ${i})) "uninitialized element")`); + } +} + +// OOB target address, nonoverlapping +tbl_copy(tbl_copy_len*2, tbl_copy_len*4, 0, Math.floor(1.5*tbl_copy_len), tbl_copy_len); +tbl_copy(tbl_copy_len*2, tbl_copy_len*4, 0, Math.floor(1.5*tbl_copy_len)-1, tbl_copy_len-1); + +// OOB source address, nonoverlapping +tbl_copy(tbl_copy_len*2, tbl_copy_len*4, Math.floor(1.5*tbl_copy_len), 0, tbl_copy_len); +tbl_copy(tbl_copy_len*2, tbl_copy_len*4, Math.floor(1.5*tbl_copy_len)-1, 0, tbl_copy_len-1); + +// OOB target address, overlapping, src < target +tbl_copy(tbl_copy_len*2, tbl_copy_len*4, tbl_copy_len-5, Math.floor(1.5*tbl_copy_len), tbl_copy_len); + +// OOB source address, overlapping, target < src +tbl_copy(tbl_copy_len*2, tbl_copy_len*4, Math.floor(1.5*tbl_copy_len), tbl_copy_len-5, tbl_copy_len); + +// OOB both, overlapping, including src == target +tbl_copy(tbl_copy_len*2, tbl_copy_len*4, tbl_copy_len+5, Math.floor(1.5*tbl_copy_len), tbl_copy_len); +tbl_copy(tbl_copy_len*2, tbl_copy_len*4, Math.floor(1.5*tbl_copy_len), tbl_copy_len+5, tbl_copy_len); +tbl_copy(tbl_copy_len*2, tbl_copy_len*4, tbl_copy_len+5, tbl_copy_len+5, tbl_copy_len); + +// Arithmetic overflow on source address. +tbl_copy(tbl_copy_len*8, tbl_copy_len*8, tbl_copy_len*7, 0, 0xFFFFFFE0); + +// Arithmetic overflow on target adddress is an overlapping case. +tbl_copy(tbl_copy_len*8, tbl_copy_len*8, 0, tbl_copy_len*7, 0xFFFFFFE0); diff --git a/test/meta/generate_table_init.js b/test/meta/generate_table_init.js new file mode 100644 index 0000000000..9329d937d7 --- /dev/null +++ b/test/meta/generate_table_init.js @@ -0,0 +1,338 @@ +// This program generates .wast code that contains all the spec tests for +// table.init and elem.drop. See `Makefile`. + +print_origin("generate_table_init.js"); + +// This module "a" exports 5 functions ... + +function emit_a() { + print( +` +(module + (func (export "ef0") (result i32) (i32.const 0)) + (func (export "ef1") (result i32) (i32.const 1)) + (func (export "ef2") (result i32) (i32.const 2)) + (func (export "ef3") (result i32) (i32.const 3)) + (func (export "ef4") (result i32) (i32.const 4)) +) +(register "a")`); +} + +// ... and this one imports those 5 functions. It adds 5 of its own, creates a +// 30 element table using both active and passive initialisers, with a mixture +// of the imported and local functions. |test| is exported. It uses the +// supplied |insn| to modify the table somehow. |check| will then indirect-call +// the table entry number specified as a parameter. That will either return a +// value 0 to 9 indicating the function called, or will throw an exception if +// the table entry is empty. + +function emit_b(insn) { + print( +` +(module + (type (func (result i32))) ;; type #0 + (import "a" "ef0" (func (result i32))) ;; index 0 + (import "a" "ef1" (func (result i32))) + (import "a" "ef2" (func (result i32))) + (import "a" "ef3" (func (result i32))) + (import "a" "ef4" (func (result i32))) ;; index 4 + (table 30 30 funcref) + (elem (i32.const 2) 3 1 4 1) + (elem funcref + (ref.func 2) (ref.func 7) (ref.func 1) (ref.func 8)) + (elem (i32.const 12) 7 5 2 3 6) + (elem funcref + (ref.func 5) (ref.func 9) (ref.func 2) (ref.func 7) (ref.func 6)) + (func (result i32) (i32.const 5)) ;; index 5 + (func (result i32) (i32.const 6)) + (func (result i32) (i32.const 7)) + (func (result i32) (i32.const 8)) + (func (result i32) (i32.const 9)) ;; index 9 + (func (export "test") + ${insn}) + (func (export "check") (param i32) (result i32) + (call_indirect (type 0) (local.get 0))) +) +`); +} + +// This is the test driver. It constructs the abovementioned module, using the +// given |instruction| to modify the table, and then probes the table by making +// indirect calls, one for each element of |expected_result_vector|. The +// results are compared to those in the vector. + +function tab_test(instruction, expected_result_vector) { + emit_b(instruction); + print(`(invoke "test")`); + for (let i = 0; i < expected_result_vector.length; i++) { + let expected = expected_result_vector[i]; + if (expected === undefined) { + print(`(assert_trap (invoke "check" (i32.const ${i})) "uninitialized element")`); + } else { + print(`(assert_return (invoke "check" (i32.const ${i})) (i32.const ${expected}))`); + } + } +} + +emit_a(); + +// Using 'e' for empty (undefined) spaces in the table, to make it easier +// to count through the vector entries when debugging. +let e = undefined; + +// Passive init that overwrites all-null entries +tab_test("(table.init 1 (i32.const 7) (i32.const 0) (i32.const 4))", + [e,e,3,1,4, 1,e,2,7,1, 8,e,7,5,2, 3,6,e,e,e, e,e,e,e,e, e,e,e,e,e]); + +// Passive init that overwrites existing active-init-created entries +tab_test("(table.init 3 (i32.const 15) (i32.const 1) (i32.const 3))", + [e,e,3,1,4, 1,e,e,e,e, e,e,7,5,2, 9,2,7,e,e, e,e,e,e,e, e,e,e,e,e]); + +// Perform active and passive initialisation and then multiple copies +tab_test(`(table.init 1 (i32.const 7) (i32.const 0) (i32.const 4)) + (elem.drop 1) + (table.init 3 (i32.const 15) (i32.const 1) (i32.const 3)) + (elem.drop 3) + (table.copy (i32.const 20) (i32.const 15) (i32.const 5)) + (table.copy (i32.const 21) (i32.const 29) (i32.const 1)) + (table.copy (i32.const 24) (i32.const 10) (i32.const 1)) + (table.copy (i32.const 13) (i32.const 11) (i32.const 4)) + (table.copy (i32.const 19) (i32.const 20) (i32.const 5))`, + [e,e,3,1,4, 1,e,2,7,1, 8,e,7,e,7, 5,2,7,e,9, e,7,e,8,8, e,e,e,e,e]); + + +// elem.drop requires a table, minimally +print( +`(assert_invalid + (module + (func (export "test") + (elem.drop 0))) + "unknown table 0") +`); + +// table.init requires a table, minimally +print( +`(assert_invalid + (module + (func (export "test") + (table.init 0 (i32.const 12) (i32.const 1) (i32.const 1)))) + "unknown table 0") +`); + +// elem.drop with elem seg ix out of range +print( +`(assert_invalid + (module + (elem funcref (ref.func 0)) + (func (result i32) (i32.const 0)) + (func (export "test") + (elem.drop 4))) + "unknown table 0") +`); + +// init with elem seg ix out of range +print( +`(assert_invalid + (module + (elem funcref (ref.func 0)) + (func (result i32) (i32.const 0)) + (func (export "test") + (table.init 4 (i32.const 12) (i32.const 1) (i32.const 1)))) + "unknown table 0") +`); + +function do_test(insn1, insn2, errText) +{ + print(` +(module + (table 30 30 funcref) + (elem (i32.const 2) 3 1 4 1) + (elem funcref + (ref.func 2) (ref.func 7) (ref.func 1) (ref.func 8)) + (elem (i32.const 12) 7 5 2 3 6) + (elem funcref + (ref.func 5) (ref.func 9) (ref.func 2) (ref.func 7) (ref.func 6)) + (func (result i32) (i32.const 0)) + (func (result i32) (i32.const 1)) + (func (result i32) (i32.const 2)) + (func (result i32) (i32.const 3)) + (func (result i32) (i32.const 4)) + (func (result i32) (i32.const 5)) + (func (result i32) (i32.const 6)) + (func (result i32) (i32.const 7)) + (func (result i32) (i32.const 8)) + (func (result i32) (i32.const 9)) + (func (export "test") + ${insn1} + ${insn2}))`); + + if (errText !== undefined) { + print(`(assert_trap (invoke "test") "${errText}")`); + } else { + print(`(invoke "test")`); + } +} + +function tab_test1(insn1, errText) { + do_test(insn1, "", errText); +} + +function tab_test2(insn1, insn2, errText) { + do_test(insn1, insn2, errText); +} + +// drop with elem seg ix indicating an active segment +tab_test1("(elem.drop 2)", + undefined); + +// init with elem seg ix indicating an active segment +tab_test1("(table.init 2 (i32.const 12) (i32.const 1) (i32.const 1))", + "out of bounds"); + +// init, using an elem seg ix more than once is OK +tab_test2( + "(table.init 1 (i32.const 12) (i32.const 1) (i32.const 1))", + "(table.init 1 (i32.const 21) (i32.const 1) (i32.const 1))", + undefined); + +// drop, then drop +tab_test2("(elem.drop 1)", + "(elem.drop 1)", + undefined); + +// drop, then init +tab_test2("(elem.drop 1)", + "(table.init 1 (i32.const 12) (i32.const 1) (i32.const 1))", + "out of bounds"); + +// init: seg ix is valid passive, but length to copy > len of seg +tab_test1("(table.init 1 (i32.const 12) (i32.const 0) (i32.const 5))", + "out of bounds"); + +// init: seg ix is valid passive, but implies copying beyond end of seg +tab_test1("(table.init 1 (i32.const 12) (i32.const 2) (i32.const 3))", + "out of bounds"); + +// init: seg ix is valid passive, but implies copying beyond end of dst +tab_test1("(table.init 1 (i32.const 28) (i32.const 1) (i32.const 3))", + "out of bounds"); + +// init: seg ix is valid passive, zero len, and src offset out of bounds at the +// end of the table - this is allowed +tab_test1("(table.init 1 (i32.const 12) (i32.const 4) (i32.const 0))", + undefined); + +// init: seg ix is valid passive, zero len, and src offset out of bounds past the +// end of the table - this is not allowed +tab_test1("(table.init 1 (i32.const 12) (i32.const 5) (i32.const 0))", + "out of bounds"); + +// init: seg ix is valid passive, zero len, and dst offset out of bounds at the +// end of the table - this is allowed +tab_test1("(table.init 1 (i32.const 30) (i32.const 2) (i32.const 0))", + undefined); + +// init: seg ix is valid passive, zero len, and dst offset out of bounds past the +// end of the table - this is not allowed +tab_test1("(table.init 1 (i32.const 31) (i32.const 2) (i32.const 0))", + "out of bounds"); + +// init: seg ix is valid passive, zero len, and dst and src offsets out of bounds +// at the end of the table - this is allowed +tab_test1("(table.init 1 (i32.const 30) (i32.const 4) (i32.const 0))", + undefined); + +// init: seg ix is valid passive, zero len, and src/dst offset out of bounds past the +// end of the table - this is not allowed +tab_test1("(table.init 1 (i32.const 31) (i32.const 5) (i32.const 0))", + "out of bounds"); + +// invalid argument types +{ + const tys = ['i32', 'f32', 'i64', 'f64']; + + for (let ty1 of tys) { + for (let ty2 of tys) { + for (let ty3 of tys) { + if (ty1 == 'i32' && ty2 == 'i32' && ty3 == 'i32') + continue; // this is the only valid case + print( +` +(assert_invalid + (module + (table 10 funcref) + (elem funcref (ref.func $f0) (ref.func $f0) (ref.func $f0)) + (func $f0) + (func (export "test") + (table.init 0 (${ty1}.const 1) (${ty2}.const 1) (${ty3}.const 1)))) + "type mismatch")`); + }}} +} + +// table.init: out of bounds of the table or the element segment, but should +// perform the operation up to the appropriate bound. +// +// Arithmetic overflow of tableoffset + len or of segmentoffset + len should not +// affect the behavior. + +// Note, the length of the element segment is 16. +const tbl_init_len = 16; + +function tbl_init(min, max, backup, write, segoffs=0) { + print( + ` +(module + (type (func (result i32))) + (table ${min} ${max} funcref) + (elem funcref + (ref.func $f0) (ref.func $f1) (ref.func $f2) (ref.func $f3) + (ref.func $f4) (ref.func $f5) (ref.func $f6) (ref.func $f7) + (ref.func $f8) (ref.func $f9) (ref.func $f10) (ref.func $f11) + (ref.func $f12) (ref.func $f13) (ref.func $f14) (ref.func $f15)) + (func $f0 (export "f0") (result i32) (i32.const 0)) + (func $f1 (export "f1") (result i32) (i32.const 1)) + (func $f2 (export "f2") (result i32) (i32.const 2)) + (func $f3 (export "f3") (result i32) (i32.const 3)) + (func $f4 (export "f4") (result i32) (i32.const 4)) + (func $f5 (export "f5") (result i32) (i32.const 5)) + (func $f6 (export "f6") (result i32) (i32.const 6)) + (func $f7 (export "f7") (result i32) (i32.const 7)) + (func $f8 (export "f8") (result i32) (i32.const 8)) + (func $f9 (export "f9") (result i32) (i32.const 9)) + (func $f10 (export "f10") (result i32) (i32.const 10)) + (func $f11 (export "f11") (result i32) (i32.const 11)) + (func $f12 (export "f12") (result i32) (i32.const 12)) + (func $f13 (export "f13") (result i32) (i32.const 13)) + (func $f14 (export "f14") (result i32) (i32.const 14)) + (func $f15 (export "f15") (result i32) (i32.const 15)) + (func (export "test") (param $n i32) (result i32) + (call_indirect (type 0) (local.get $n))) + (func (export "run") (param $offs i32) (param $len i32) + (table.init 0 (local.get $offs) (i32.const ${segoffs}) (local.get $len))))`); + + // A fill writing past the end of the table should throw *and* have filled + // all the way up to the end. + // + // A fill reading past the end of the segment should throw *and* have filled + // table with as much data as was available. + let offs = min - backup; + print(`(assert_trap (invoke "run" (i32.const ${offs}) (i32.const ${write})) "out of bounds")`); + for (let i=0; i < min; i++) { + print(`(assert_trap (invoke "test" (i32.const ${i})) "uninitialized element")`); + } +} + +// We exceed the bounds of the table but not of the element segment +tbl_init(tbl_init_len*2, tbl_init_len*4, Math.floor(tbl_init_len/2), tbl_init_len); +tbl_init(tbl_init_len*2, tbl_init_len*4, Math.floor(tbl_init_len/2)-1, tbl_init_len); + +// We exceed the bounds of the element segment but not the table +tbl_init(tbl_init_len*10, tbl_init_len*20, tbl_init_len*4, tbl_init_len*2); +tbl_init(tbl_init_len*10, tbl_init_len*20, tbl_init_len*4-1, tbl_init_len*2-1); + +// We arithmetically overflow the table limit but not the segment limit +tbl_init(tbl_init_len*4, tbl_init_len*4, tbl_init_len, 0xFFFFFFF0); + +// We arithmetically overflow the segment limit but not the table limit +tbl_init(tbl_init_len, tbl_init_len, tbl_init_len, 0xFFFFFFFC, Math.floor(tbl_init_len/2)); + diff --git a/test/meta/noderun.sh b/test/meta/noderun.sh new file mode 100755 index 0000000000..7b07a28cf9 --- /dev/null +++ b/test/meta/noderun.sh @@ -0,0 +1,16 @@ +if [ $# -ne 2 ]; then + echo "Bad args" + exit 1 +fi + +rm -f nodeprog.js +cat <> nodeprog.js +const WITH_SHARED_MEMORY=$1; +function print(x) { + console.log(x); +} +EOF +cat common.js >> nodeprog.js +cat $2 >> nodeprog.js +node nodeprog.js +rm nodeprog.js From 97dec20a991d545b0f932b5f941b7095323c4ccb Mon Sep 17 00:00:00 2001 From: Ben Smith Date: Wed, 15 Jan 2020 11:47:47 -0800 Subject: [PATCH 139/199] Travis setup; fix references to spec Based on the proposal howto: https://github.com/WebAssembly/proposals/blob/master/howto.md --- .travis.yml | 2 +- README.md | 2 +- deploy_key.enc | Bin 3248 -> 3360 bytes document/core/index.rst | 2 +- document/core/util/macros.def | 8 ++++---- 5 files changed, 7 insertions(+), 7 deletions(-) diff --git a/.travis.yml b/.travis.yml index 6ecbdb3566..18fed8d5d8 100644 --- a/.travis.yml +++ b/.travis.yml @@ -26,5 +26,5 @@ os: linux env: global: - - ENCRYPTION_LABEL: "304454be9d6c" + - ENCRYPTION_LABEL: "2cede2ad97c0" - COMMIT_AUTHOR_EMAIL: "noreply@webassembly.org" diff --git a/README.md b/README.md index 466b0e6a81..05ab9b3c32 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -[![Build Status](https://travis-ci.org/WebAssembly/spec.svg?branch=master)](https://travis-ci.org/WebAssembly/spec) +[![Build Status](https://travis-ci.org/WebAssembly/bulk-memory-operations.svg?branch=master)](https://travis-ci.org/WebAssembly/bulk-memory-operations) # Bulk Memory Operations Proposal for WebAssembly diff --git a/deploy_key.enc b/deploy_key.enc index b6d3e2f19771652a9711760b1712a77fe1b4e579..c4a7667a2f44f1a33d5addb6db535d6c0d0a2cd6 100644 GIT binary patch literal 3360 zcmV+*4d3$RoI@4sTzM8CUw|6r{rpsR5hM5OljI{#veR?^(kQ=cULp}oB$-3jI+H#O z1e6Rl!2g7sD9Y|+?QTRIHhIvn$F12$W`^uQcb}L9*&Gh1DbGfmZ3MX zi^}oPp6cs(i1%!`j}^=2eXe-Xsm2a#^Yl|M@Dt(FXfJvW3TlFc#CKVe$pZKE(mzTj zBA%%}3dF}sMxRtRT?QyU5?ME)Q?XVH#r*3W;gB`8mWo$yI^5LUGM9T2fN57Jr0`qw z4dISlJXQ(UkuzDcUKMmcsb=tIdFhk7PUck0(fh&3-L*{>oe!n>a4f_2c2}1>{K%bu zS^PL*&><{CJL$Nu$M3!Uh6*#QI{dff(BLUBqs%VQvJlygUJ;pX;kp=-HW3e4V-`EN zWY@&N_t#xlRg!ZnTJ+B>{~{*J#nsr4TX`WJ5}*`En&c-l_J9Yw<2@fz#*(dVpzwrd z;sp$HgUYpG!xxRgO}}Lyn=HDTR!6otG1bs#sdGROj!;}TxdNO6ze) zwzA6_FK!t{B%bQO7m504PMsB(i#L*DGrq?1x83)Na-rKwm8fhss7n#w;fN++>qJaC z$xy~v3cKv}u^1(@dDW~@CgMTL4yKZmqYv1tUaFY=xrx;Fx{7eA*}1UWXXWx5T~hy65#qDqaF9FEF!UKs46Z}TcbB>&Tg5E( zvZ!uZ*u0XCsHGp&rb~z8_9}lchUUE4PsE!xz>W$`{yq75m#-i$Ack-i?Kb>46SZO< zMX)6-b1oWei%z0EHrXddHqdjJ4M_^xE6-r^l;HpDN$TU+Lvl70^@VG74P%W?8q!dP zQw(2SEb;^G2&{&^AT0MXDCxP?_6kh-OT(KELtc4Q3%gK*XV(34`L*YESs&LF2KEB3_UJdL-3do1ulU@IM~vzqkWw>BEJ}JJD?1xV@9gGlT>M3l1@L)#WV$de<#&0eN2de^xzqrKoXgs$lBqQ+xaC%oFu zRulbAQMeC>E~#++A$}8kAwu_=Kjy<{Mkt!h0`3>OYx=@_)0?aRD>B79ltEGi@+-We z;(9minF%n9ZaOXpvQ3>~U=Q^v;JKg+=v=_`(}*!RDBVSi)3n~6=^sCXi|1hsfNBSL zU_h+c)-e)yi)~g;=hOzvmK&){pA@?h_IE={ey%T7k7ci9_iR0fN@wZDepZ;o!2VW~ z;EnJW3-$=_Yr{d{_X~Z^0W5lfdA)Q>i$3FviGeEPN>IA2k`2)YW`g0%%y@e46sqBL zp1m}Mc*muN36qS=9p^DB;k)+58l=XlDqQvJ(|4zrF$w7xB9ioJz9!KitS*6dm&2cDogu!pKLT;hdmquPR z&{*9>38wT%+OYM?I5$)%dD(88qF3ta*vCbq;LBWek+kn!{D&nc$DSf#bcP^&b%s1r z0PXAigWhJ}W&CZ2*`O3mXl8i^e`>13R6RiV?)@Q!Mz-5s3w&Inu&?7+fa63bI*+No zi@oBFDm{v1%r`k`!%+$0UBBC$#<`rDtZ_Ayjiv#iG*n!s?r#!3R)$_n@5fzLandV+ z(R@Ym#Uoh9n-XO-Cl4pHqQS$>hN8HJ7J$}z5UZQ$0pvOLRS=k- z`6-~`dT$d+M%16Pzu1(1FB%|xq@*InrqlJJ9_L#?X?z!k*IL}})n@sVK8{iLu)ZT3 zzb-y65TTY%fFD;fcv!`4Ix`CLxzsCt(z9t!GWf3}wqk0p%xU1^EamLk=RAR6%c~cF zNeR@HcP903pLj#l^J0l!ej$Vwk{D{>Jtsq56Vb68x%r>x(EsUqH)`Z7Wey_vJoLWLqVi?-?ldgh)9$|nDW+~|ea|&Im(pVR1{Ri%4a@FrQeubR7Yw(vip!s*} z9$t`arK+uT*}j*9@hgzqI)Dr{=dh}4HK`n_=*&`j3?x}dURvEme`a`Chl_P`eW|dH zLeC*{e$=!uy}&KJPN-utgN4xjQG3*(RYJH37rrO}UACX5pkhotBCP?3A2F>zC#a$8 z+UGouxV<-3Cc(&IK{f^JieK7ysnEIV;eI*)sKa<3av4d4oDZJ!dl|xt{nn;1 z?v=m0HHjU71X+&xu0oz6rV=;B7fXhpvEBG<0n#_ z@>w3VGvB;Ie@D!@01kQbR&z+4lW9!$&y0bruOpr*s6*7mb#6D$qm|6ML%oGX=9Utj zOfrLSCatayb#8Jt)W1oIGvJ2>4l~Dx!}88hmq%owxdSNyLpZapnbu%+fSIbN6tgLxKx9fc_*4*oL5%egx@E#@U` zF*TD;r#&dZ(!@WK?}fp{fa0l?e=4{(G(4e{Y66ABcT+IN)@jykEx~Vo_&#G93Tp)< z)K~pOMr~fg1xJTVj0d1&W%l(=sUOu`p8vUL%0sWTAOYXv>rw%%rtJ)z7n@$oKSQW7 zVelIzr$f$>3_x@v{8p}F^IR&&T+m>qN($Ff54?YnOYwWM>_Cb*nl768?xiQ4!$6Fk zcI1-r^;Dn1c=A@c__zP@o++*YLHcLvcv3zyLNi#cIf8a8NtqDh1-b+0;t;& z#m>lL*l^l}NBcYPK|(OI-ZtZ=#DhH*&;*2jtD_z1j7^nn-GswVeOHgY$RTRxxi?|W zr|~Y$=NR~Dlq>BnlQ{|vE|Ytqy~Xap1Jom611QC_Cs>B7W5$jvAn@2uPXh!osEC*O z4(joxmEJyqY&32B1Y3^6iR%7XFMNH5AtulsQ-rSdQp{|LcB9a$%Z`(PWo}dgg%uau z_W28$ngt8B3rgAgo?I5fmPg^9BBq!fU*t*QAV#xq`F`1iG=O$F6SJ>9Q=R;dtK&MeyjtbM;s+(w zfwYWyC=r_L)3MWj&0#;s4NN+1$?fpeedExtk(IH_fNhQGzVLz`Q<*2Txt67^OD8*= zcsfGaeEqT~3%(Ny7b4y8rHccLSYJQ3zCeTmy}0)AOQC8cE?=9{MoU<2tfDIl#42`> zy=Ubn7xoHZdm}(n^`6)up7q&ID9V&1!ts(?NVx~2H;PLBJ)clvp+)1*8O#XIWSql? zy;-LE=}d~AEj3RvKBATvPOO66JAkk)21yM;-gJL6d;WO7>wYYQ!sfnlXO=Bj#Ve`Z zPskOYP!0nuq0ON=@a_9tOqSdO>eNNcm?*g(3{Txudr$lT5RIuvD%}sxJ=cR~{~S_p z)|52?*cX@)MD;|NlQyXm@K*f%QQ^@3?@3tZnNet)T`Wqy+x+)3-sQUlWUS z!1k_xwKxN$hM{+3|D$UY;!ha4K6WPou`|(_K5{SIdA$i<1>|c^9g>He?EtTxsp`wi qxFAb>OVfMoxiroj)dA}NL?E%|SGP2t!lB1bqF&YW-+d$cJVkV$ZJ2BT literal 3248 zcmV;h3{UeoaMr!6kTNmX>{8Y#<|(CVbO6TJr-;79Ag-eBM!B~g(FTQ5ldW}>C6w#F z7?FSyFeYZ$v_V^lQFEF>+7k9B7m`7vS_SQ$;wWv|QOclL{NpaXb;g5ti(%WUt|3;5 z3CA#OrS)XS){2AUta7q}MSmhTJq zo{c?28()!ibPsqvTfOAA!4zOONU^F*gLcD(DrJbnNphXRZ3yC#LaPJi{CC$C(2A_7 zNaF$Iwo+ftMAzTpRFW1@B>=0mk{V^}DS!4rt3&v*?r8!}EfiTzY#jX?%ckauU9h@W zx(fD`Pk=~T7D1zi5Xgo-F3df<=bCbjU0(ZD&z`12ST)Xxn<2-%!cB^F0IoG~-*{lROB{l$8;> zQYD6uvZB!WjR97=Gm5k(nd?fS-skc&EK?_V8WnS+v(_4N1NbVfWy{T9c3+w+eKW@y z`gzb1V%Tr>ul(ay+I}7y2o4<>nNeC`_9<4dQwbaZcv=lR5j&@)QY$OIg__IEl?CzP zj*w)N-7!X;zax-wu2%HYpX17nK^l2cLppXhM>Q8<9AmF4V+?wF~S-rGWRU;<& zEfi}`>wt%Un_w@H!oNoZ>x+M|o6OWL0ZWAvCDS3ci~T8hKI0BHLyhmaX>a@YdQNK^9SJORstB zfvrm3TfM$`MMQQXp+4m=U~?Y#8>LXJEJKe+QT3ai?lI{90Zbd!SJdk4H(U1tebkQS zElH@QyluL-tMcF~ED_;l>!0Ijv*4gtnDwmLYV{a3@tjZ`D zFgG=OkZ90lfbv6>Fy&2v?b=c~Y_N9G zUi9};vfpk;9dPn4FMkaR{o~nn&h!a-?Sdb%SZ)!fI~GWnk~X{F~0*MZTR*=jmm-h1@t zDL!$f-TC0j9#3k6yGm=yVm`^%@wfi3bq#*03KSe>$d+&xjHOcMc8uJt8)hN2{SBal z4ob$b$`dj=o#p1YnW?UI^yZ;rkMjLI{F#<8G09bp2NC-f7?!MtUZ(JwIdFlSzu%EdX7u+as(dHl z58QQZ`uk&2UcuOD{=l^SW7lbUC)YQxLZoD(4yfjbALj)ocgYIM0ZYz?(TpdH^*N^lP&fD?>5S3l5d9vDe0MYX}=L@v0ac*d^h zMC3X&i8_TGc*nis1+Hbb@FGCYM0^b7+Ks%np4Yi`?%nMjTjK}kiD^peA^u+*e>(aKEP(B~>~mZq#KO^e z%~M*@SsY^h6(tY`GdMou`@})%F*bIbRNZ>mC~Kmlo-i?%UtfW#dT*z*RcdL zpk60TCgJqxKBvX~s$%Shh(AI%*I`@P2!X_@lhC_lv0_yIg6%&*TKAQRPZQNW>=_H-#1pBvjD+m{Zb}zcH8nbpNqr9whn4 zA=y)BHKQ-DrD~ATW$s5sLj-tJ#cf~=mO{+4YNwZc;4(}zeG0i5iXTW*#VVOL90%~C zVKMQHgk?j=XH43>K+-CeY3%JXI)VIB$Ad;DSsk-VJs=GfjP+|s{r){_ozCKbFDNi| zfEk3yUlIo}(x+SiFz(8%;%1%!B5`O|M9Tgg3bui&lu)v`(ydUn{aib=ktlW8MU&;r zQ+2LIr_4e3%GTLQ5?58orh7HmWd&Z&T0Uz!9~Ha`K^gp=fQ`FR=0~z|>MuzT4#e%& zBXJPHh`^tE;|zIgNiR(*kU@PB&}J%3Coh;M^QnC8vP7h%*_Gozd?$RZWr_#dXYF>u zT>^8L;b}KO+gPONfMBv1ae%Hy6R+;S^w+Ng{zo&nGB`o<^fxC>{v`=!WnoSACN9e? z!P}dgK-N^z=5p%- zjAkKdA-dFrZxs{<7wntcycPzJOC})W{%YX>7&0{p8S%XXI0{sJi2me-X!z#kb@^(L zIrTxbTFMXTi!+maqh2OdhC54A&#rQ{4~>UL|6E*af1FP^b#OX~#=VRt;}}z+FhX7& z(?0)PAKjGZ*g(dZNg81514!QK;bQWS0-qDq&xgnv8vdcEkLzW9YdU7Q`jSwWHd*~b zqQ?O;jM%iLY>Zw*$r*lZ~?dz)vtCi6GqzmKd+b z!(zZgpXf?*+wbzsxQ&XJ3)2p#3|IEa$pe0b>QbH=rr|j)yS-i=SFADE7tJ`oCmN@} zL{UA^mr)_ZWdcbz>BGLSKFnFY^oV4EXulUCv6iQUG?d~nuNbxQiWI`F1pbLxAfG^h iY#Pu|2q&8>`3}#6q-2Cz`ZEbT?K&=q;2asiqpF?e?>4gl diff --git a/document/core/index.rst b/document/core/index.rst index 1d8d6a4aa1..2ef0bd83ae 100644 --- a/document/core/index.rst +++ b/document/core/index.rst @@ -3,7 +3,7 @@ WebAssembly Specification .. only:: html - | Release |release| (Draft, |today|) + | Release |release| + bulk memory operations (Draft, |today|) | Editor: Andreas Rossberg diff --git a/document/core/util/macros.def b/document/core/util/macros.def index 86acdc9850..23e3b2f385 100644 --- a/document/core/util/macros.def +++ b/document/core/util/macros.def @@ -3,11 +3,11 @@ .. External Standards .. ------------------ -.. |WasmDraft| replace:: http://webassembly.github.io/spec/core/ -.. _WasmDraft: http://webassembly.github.io/spec/core/ +.. |WasmDraft| replace:: http://webassembly.github.io/bulk-memory-operations/core/ +.. _WasmDraft: http://webassembly.github.io/bulk-memory-operations/core/ -.. |WasmIssues| replace:: http://github.com/webassembly/spec/issues/ -.. _WasmIssues: http://github.com/webassembly/spec/issues/ +.. |WasmIssues| replace:: http://github.com/webassembly/bulk-memory-operations/issues/ +.. _WasmIssues: http://github.com/webassembly/bulk-memory-operations/issues/ .. |IEEE754| replace:: IEEE 754-2019 .. _IEEE754: https://ieeexplore.ieee.org/document/8766229 From 3e32403b5cc932938185bc370ab4966c18e42396 Mon Sep 17 00:00:00 2001 From: Andreas Rossberg Date: Thu, 16 Jan 2020 16:35:32 +0100 Subject: [PATCH 140/199] Fix various TODOs (#72) * Move to small-step semantics for table instructions [interpreter]. * Add back-compat sugar for table instructions omitting table index [spec/interpreter]. * Add optional item keyword to syntactically represent multi-instr element expressions, analogous to syntax for offset. [spec/interpreter] * Generalise bulk table ops to multiple tables [spec]. * A few smaller todos in spec (segment instantiation, removing funcelems). --- document/core/appendix/properties.rst | 4 +- document/core/exec/conventions.rst | 2 +- document/core/exec/instructions.rst | 114 +++++++++++++------------- document/core/exec/modules.rst | 25 +++--- document/core/exec/runtime.rst | 3 +- document/core/text/instructions.rst | 22 ++++- document/core/text/modules.rst | 11 ++- document/core/util/macros.def | 1 - interpreter/README.md | 29 ++++--- interpreter/exec/eval.ml | 56 ++++++++++--- interpreter/runtime/table.ml | 23 ------ interpreter/runtime/table.mli | 5 -- interpreter/syntax/ast.ml | 4 +- interpreter/text/arrange.ml | 6 +- interpreter/text/lexer.mll | 1 + interpreter/text/parser.mly | 46 ++++++----- proposals/reference-types/Overview.md | 2 + test/core/elem.wast | 2 +- 18 files changed, 199 insertions(+), 157 deletions(-) diff --git a/document/core/appendix/properties.rst b/document/core/appendix/properties.rst index 9956e528be..76e47b7439 100644 --- a/document/core/appendix/properties.rst +++ b/document/core/appendix/properties.rst @@ -286,8 +286,6 @@ Module instances are classified by *module contexts*, which are regular :ref:`co .. index:: element instance, reference .. _valid-eleminst: -.. todo:: TODO: adjust elem instances - :ref:`Element Instances ` :math:`\{ \EIELEM~\X{fa}^\ast \}` ............................................................................ @@ -303,7 +301,7 @@ Module instances are classified by *module contexts*, which are regular :ref:`co \frac{ (S \vdash \reff : t')^\ast \qquad - (\vdashreftypematch t' \matchesvaltype t)^n + (\vdashreftypematch t' \matchesvaltype t)^\ast }{ S \vdasheleminst \{ \EITYPE~t, \EIELEM~\reff^\ast \} \ok } diff --git a/document/core/exec/conventions.rst b/document/core/exec/conventions.rst index 3e14d8e875..807239b044 100644 --- a/document/core/exec/conventions.rst +++ b/document/core/exec/conventions.rst @@ -33,7 +33,7 @@ The following conventions are adopted in stating these rules. * The execution rules also assume the presence of an implicit :ref:`stack ` that is modified by *pushing* or *popping* - :ref:`values `, :ref:`function elements `, :ref:`labels `, and :ref:`frames `. + :ref:`values `, :ref:`labels `, and :ref:`frames `. * Certain rules require the stack to contain at least one frame. The most recent frame is referred to as the *current* frame. diff --git a/document/core/exec/instructions.rst b/document/core/exec/instructions.rst index ffad9cb326..1b1181252d 100644 --- a/document/core/exec/instructions.rst +++ b/document/core/exec/instructions.rst @@ -633,11 +633,11 @@ Table Instructions 2. Assert: due to :ref:`validation `, :math:`F.\AMODULE.\MITABLES[x]` exists. -3. Let :math:`a` be the :ref:`table address ` :math:`F.\AMODULE.\MITABLES[x]`. +3. Let :math:`\X{ta}` be the :ref:`table address ` :math:`F.\AMODULE.\MITABLES[x]`. -4. Assert: due to :ref:`validation `, :math:`S.\STABLES[a]` exists. +4. Assert: due to :ref:`validation `, :math:`S.\STABLES[\X{ta}]` exists. -5. Let :math:`\X{tab}` be the :ref:`table instance ` :math:`S.\STABLES[a]`. +5. Let :math:`\X{tab}` be the :ref:`table instance ` :math:`S.\STABLES[\X{ta}]`. 6. Assert: due to :ref:`validation `, a value of :ref:`value type ` |I32| is on the top of the stack. @@ -693,50 +693,56 @@ Table Instructions .. _exec-table.copy: -:math:`\TABLECOPY` -.................. - -.. todo:: TODO: multi tables +:math:`\TABLECOPY~x~y` +...................... 1. Let :math:`F` be the :ref:`current ` :ref:`frame `. -2. Assert: due to :ref:`validation `, :math:`F.\AMODULE.\MITABLES[0]` exists. +2. Assert: due to :ref:`validation `, :math:`F.\AMODULE.\MITABLES[x]` exists. -3. Let :math:`\X{ta}` be the :ref:`table address ` :math:`F.\AMODULE.\MITABLES[0]`. +3. Let :math:`\X{ta}_x` be the :ref:`table address ` :math:`F.\AMODULE.\MITABLES[x]`. -4. Assert: due to :ref:`validation `, :math:`S.\STABLES[\X{ta}]` exists. +4. Assert: due to :ref:`validation `, :math:`S.\STABLES[\X{ta}_x]` exists. -5. Let :math:`\X{tab}` be the :ref:`table instance ` :math:`S.\STABLES[\X{ta}]`. +5. Let :math:`\X{tab}_x` be the :ref:`table instance ` :math:`S.\STABLES[\X{ta}_x]`. -6. Assert: due to :ref:`validation `, a value of :ref:`value type ` |I32| is on the top of the stack. +6. Assert: due to :ref:`validation `, :math:`F.\AMODULE.\MITABLES[y]` exists. -7. Pop the value :math:`\I32.\CONST~n` from the stack. +7. Let :math:`\X{ta}_y` be the :ref:`table address ` :math:`F.\AMODULE.\MITABLES[y]`. -8. Assert: due to :ref:`validation `, a value of :ref:`value type ` |I32| is on the top of the stack. +8. Assert: due to :ref:`validation `, :math:`S.\STABLES[\X{ta}_y]` exists. -9. Pop the value :math:`\I32.\CONST~s` from the stack. +9. Let :math:`\X{tab}_y` be the :ref:`table instance ` :math:`S.\STABLES[\X{ta}_y]`. 10. Assert: due to :ref:`validation `, a value of :ref:`value type ` |I32| is on the top of the stack. -11. Pop the value :math:`\I32.\CONST~d` from the stack. +11. Pop the value :math:`\I32.\CONST~n` from the stack. + +12. Assert: due to :ref:`validation `, a value of :ref:`value type ` |I32| is on the top of the stack. + +13. Pop the value :math:`\I32.\CONST~s` from the stack. -12. If :math:`s + n` is larger than the length of :math:`\X{tab}.\TIELEM` or :math:`d + n` is larger than the length of :math:`\X{tab}.\TIELEM`, then: +14. Assert: due to :ref:`validation `, a value of :ref:`value type ` |I32| is on the top of the stack. + +15. Pop the value :math:`\I32.\CONST~d` from the stack. + +16. If :math:`s + n` is larger than the length of :math:`\X{tab}_y.\TIELEM` or :math:`d + n` is larger than the length of :math:`\X{tab}_x.\TIELEM`, then: a. Trap. -13. If :math:`n = 0`, then: +17. If :math:`n = 0`, then: a. Return. -14. If :math:`d \leq s`, then: +18. If :math:`d \leq s`, then: a. Push the value :math:`\I32.\CONST~d` to the stack. b. Push the value :math:`\I32.\CONST~s` to the stack. - c. Execute the instruction :math:`\TABLEGET`. + c. Execute the instruction :math:`\TABLEGET~y`. - d. Execute the instruction :math:`\TABLESET`. + d. Execute the instruction :math:`\TABLESET~x`. e. Assert: due to the earlier check against the table size, :math:`d+1 < 2^{32}`. @@ -746,7 +752,7 @@ Table Instructions h. Push the value :math:`\I32.\CONST~(s+1)` to the stack. -15. Else: +19. Else: a. Assert: due to the earlier check against the table size, :math:`d+n-1 < 2^{32}`. @@ -756,48 +762,48 @@ Table Instructions d. Push the value :math:`\I32.\CONST~(s+n-1)` to the stack. - c. Execute the instruction :math:`\TABLEGET`. + c. Execute the instruction :math:`\TABLEGET~y`. - f. Execute the instruction :math:`\TABLESET`. + f. Execute the instruction :math:`\TABLESET~x`. g. Push the value :math:`\I32.\CONST~d` to the stack. h. Push the value :math:`\I32.\CONST~s` to the stack. -16. Push the value :math:`\I32.\CONST~(n-1)` to the stack. +20. Push the value :math:`\I32.\CONST~(n-1)` to the stack. -17. Execute the instruction :math:`\TABLECOPY`. +21. Execute the instruction :math:`\TABLECOPY~x~y`. .. math:: ~\\[-1ex] \begin{array}{l} - S; F; (\I32.\CONST~d)~(\I32.\CONST~s)~(\I32.\CONST~n)~\TABLECOPY + S; F; (\I32.\CONST~d)~(\I32.\CONST~s)~(\I32.\CONST~n)~(\TABLECOPY~x~y) \quad\stepto\quad S; F; \TRAP \\ \qquad \begin{array}[t]{@{}r@{~}l@{}} - (\iff & s + n > |S.\STABLES[F.\AMODULE.\MITABLES[0]].\TIELEM| \\ - \vee & d + n > |S.\STABLES[F.\AMODULE.\MITABLES[0]].\TIELEM|) \\ + (\iff & s + n > |S.\STABLES[F.\AMODULE.\MITABLES[y]].\TIELEM| \\ + \vee & d + n > |S.\STABLES[F.\AMODULE.\MITABLES[x]].\TIELEM|) \\ \end{array} \\[1ex] - S; F; (\I32.\CONST~d)~(\I32.\CONST~s)~(\I32.\CONST~0)~\TABLECOPY + S; F; (\I32.\CONST~d)~(\I32.\CONST~s)~(\I32.\CONST~0)~(\TABLECOPY~x~y) \quad\stepto\quad S; F; \epsilon \\ \qquad (\otherwise) \\[1ex] - S; F; (\I32.\CONST~d)~(\I32.\CONST~s)~(\I32.\CONST~n+1)~\TABLECOPY + S; F; (\I32.\CONST~d)~(\I32.\CONST~s)~(\I32.\CONST~n+1)~(\TABLECOPY~x~y) \quad\stepto\quad S; F; \begin{array}[t]{@{}l@{}} - (\I32.\CONST~d)~(\I32.\CONST~s)~\TABLEGET~\TABLESET \\ - (\I32.\CONST~d+1)~(\I32.\CONST~s+1)~(\I32.\CONST~n)~\TABLECOPY \\ + (\I32.\CONST~d)~(\I32.\CONST~s)~(\TABLEGET~y)~(\TABLESET~x) \\ + (\I32.\CONST~d+1)~(\I32.\CONST~s+1)~(\I32.\CONST~n)~(\TABLECOPY~x~y) \\ \end{array} \\ \qquad (\otherwise, \iff d \leq s) \\[1ex] - S; F; (\I32.\CONST~d)~(\I32.\CONST~s)~(\I32.\CONST~n+1)~\TABLECOPY + S; F; (\I32.\CONST~d)~(\I32.\CONST~s)~(\I32.\CONST~n+1)~(\TABLECOPY~x~y) \quad\stepto\quad S; F; \begin{array}[t]{@{}l@{}} - (\I32.\CONST~d+n-1)~(\I32.\CONST~s+n-1)~\TABLEGET~\TABLESET \\ - (\I32.\CONST~d)~(\I32.\CONST~s)~(\I32.\CONST~n)~\TABLECOPY \\ + (\I32.\CONST~d+n-1)~(\I32.\CONST~s+n-1)~(\TABLEGET~y)~(\TABLESET~x) \\ + (\I32.\CONST~d)~(\I32.\CONST~s)~(\I32.\CONST~n)~(\TABLECOPY~x~y) \\ \end{array} \\ \qquad (\otherwise, \iff d > s) \\ @@ -806,24 +812,22 @@ Table Instructions .. _exec-table.init: -:math:`\TABLEINIT~x` -.................... - -.. todo:: TODO: multi tables +:math:`\TABLEINIT~x~y` +...................... 1. Let :math:`F` be the :ref:`current ` :ref:`frame `. -2. Assert: due to :ref:`validation `, :math:`F.\AMODULE.\MITABLES[0]` exists. +2. Assert: due to :ref:`validation `, :math:`F.\AMODULE.\MITABLES[x]` exists. -3. Let :math:`\X{ta}` be the :ref:`table address ` :math:`F.\AMODULE.\MITABLES[0]`. +3. Let :math:`\X{ta}` be the :ref:`table address ` :math:`F.\AMODULE.\MITABLES[x]`. 4. Assert: due to :ref:`validation `, :math:`S.\STABLES[\X{ta}]` exists. 5. Let :math:`\X{tab}` be the :ref:`table instance ` :math:`S.\STABLES[\X{ta}]`. -6. Assert: due to :ref:`validation `, :math:`F.\AMODULE.\MIELEMS[x]` exists. +6. Assert: due to :ref:`validation `, :math:`F.\AMODULE.\MIELEMS[y]` exists. -7. Let :math:`\X{ea}` be the :ref:`element address ` :math:`F.\AMODULE.\MIELEMS[x]`. +7. Let :math:`\X{ea}` be the :ref:`element address ` :math:`F.\AMODULE.\MIELEMS[y]`. 8. Assert: due to :ref:`validation `, :math:`S.\SELEMS[\X{ea}]` exists. @@ -849,13 +853,13 @@ Table Instructions a. Return. -18. Let :math:`\funcelem` be the :ref:`function element ` :math:`\X{elem}.\EIELEM[s]`. +18. Let :math:`\val` be the :ref:`reference value ` :math:`\X{elem}.\EIELEM[s]`. 19. Push the value :math:`\I32.\CONST~d` to the stack. -20. Push the value :math:`\funcelem` to the stack. +20. Push the value :math:`\val` to the stack. -21. Execute the instruction :math:`\TABLESET`. +21. Execute the instruction :math:`\TABLESET~x`. 22. Assert: due to the earlier check against the table size, :math:`d+1 < 2^{32}`. @@ -867,32 +871,32 @@ Table Instructions 26. Push the value :math:`\I32.\CONST~(n-1)` to the stack. -27. Execute the instruction :math:`\TABLEINIT~x`. +27. Execute the instruction :math:`\TABLEINIT~x~y`. .. math:: ~\\[-1ex] \begin{array}{l} - S; F; (\I32.\CONST~d)~(\I32.\CONST~s)~(\I32.\CONST~n)~(\TABLEINIT~x) + S; F; (\I32.\CONST~d)~(\I32.\CONST~s)~(\I32.\CONST~n)~(\TABLEINIT~x~y) \quad\stepto\quad S; F; \TRAP \\ \qquad \begin{array}[t]{@{}r@{~}l@{}} - (\iff & s + n > |S.\SELEMS[F.\AMODULE.\MIELEMS[x]].\EIELEM| \\ + (\iff & s + n > |S.\SELEMS[F.\AMODULE.\MIELEMS[y]].\EIELEM| \\ \vee & d + n > |S.\STABLES[F.\AMODULE.\MITABLES[x]].\TIELEM|) \\ \end{array} \\[1ex] - S; F; (\I32.\CONST~d)~(\I32.\CONST~s)~(\I32.\CONST~0)~(\TABLEINIT~x) + S; F; (\I32.\CONST~d)~(\I32.\CONST~s)~(\I32.\CONST~0)~(\TABLEINIT~x~y) \quad\stepto\quad S; F; \epsilon \\ \qquad (\otherwise) \\[1ex] - S; F; (\I32.\CONST~d)~(\I32.\CONST~s)~(\I32.\CONST~n+1)~(\TABLEINIT~x) + S; F; (\I32.\CONST~d)~(\I32.\CONST~s)~(\I32.\CONST~n+1)~(\TABLEINIT~x~y) \quad\stepto\quad S; F; \begin{array}[t]{@{}l@{}} - (\I32.\CONST~d)~\funcelem~(\TABLESET~x) \\ - (\I32.\CONST~d+1)~(\I32.\CONST~s+1)~(\I32.\CONST~n)~(\TABLEINIT~x) \\ + (\I32.\CONST~d)~\val~(\TABLESET~x) \\ + (\I32.\CONST~d+1)~(\I32.\CONST~s+1)~(\I32.\CONST~n)~(\TABLEINIT~x~y) \\ \end{array} \\ \qquad - (\otherwise, \iff \funcelem = S.\SELEMS[F.\AMODULE.\MIELEMS[x]].\EIELEM[s]) \\ + (\otherwise, \iff \val = S.\SELEMS[F.\AMODULE.\MIELEMS[x]].\EIELEM[s]) \\ \end{array} diff --git a/document/core/exec/modules.rst b/document/core/exec/modules.rst index 1211356d23..002964b91d 100644 --- a/document/core/exec/modules.rst +++ b/document/core/exec/modules.rst @@ -630,21 +630,21 @@ It is up to the :ref:`embedder ` to define how such conditions are rep 6. Let :math:`(\reff^\ast)^\ast` be the list of :ref:`reference ` vectors determined by the :ref:`element segments ` in :math:`\module`. These may be calculated as follows. - .. todo:: TODO desugar funcelem + a. Let :math:`\moduleinst_{\F{im}}` be the auxiliary module :ref:`instance ` :math:`\{\MIGLOBALS~\evglobals(\externval^n)\}` that only consists of the imported globals. - a. For each :ref:`element segment ` :math:`\elem_i` in :math:`\module.\MELEMS`, and for each element :ref:`expression ` :math:`\expr_{ij}` in :math:`\elem_i.\EINIT`, do: + b. Let :math:`F_{\F{im}}` be the auxiliary :ref:`frame ` :math:`\{ \AMODULE~\moduleinst_{\F{im}}, \ALOCALS~\epsilon \}`. - i. If :math:`\expr_{ij}` is of the form :math:`\REFNULL`, then let the :ref:`function element ` :math:`\funcelem_{ij}` be :math:`\epsilon`. + c. Push the frame :math:`F_{\F{im}}` to the stack. - ii. Else, :math:`\expr_{ij}` is of the form is :math:`\REFFUNC~\funcidx_{ij}`. + d. For each :ref:`element segment ` :math:`\elem_i` in :math:`\module.\MELEMS`, and for each element :ref:`expression ` :math:`\expr_{ij}` in :math:`\elem_i.\EINIT`, do: - iii. Assert: due to :ref:`validation `, :math:`\moduleinst.\MIFUNCS[\funcidx_{ij}]` exists. + i. Let :math:`\reff_{ij}` be the result of :ref:`evaluating ` the initializer expression :math:`\expr_{ij}`. - iv. Let the :ref:`function element ` :math:`\funcelem_{ij}` be the :ref:`function address ` :math:`\moduleinst.\MIFUNCS[\funcidx_{ij}]`. + e. Pop the frame :math:`F_{\F{im}}` from the stack. - b. Let :math:`\funcelem^\ast_i` be the concatenation of function elements :math:`\funcelem_{ij}` in order of index :math:`j`. + f. Let :math:`\reff^\ast_i` be the concatenation of function elements :math:`\reff_{ij}` in order of index :math:`j`. - c. Let :math:`(\funcelem^\ast)^\ast` be the concatenation of function element vectors :math:`\funcelem^\ast_i` in order of index :math:`i`. + g. Let :math:`(\reff^\ast)^\ast` be the concatenation of function element vectors :math:`\reff^\ast_i` in order of index :math:`i`. 7. Let :math:`\moduleinst` be a new module instance :ref:`allocated ` from :math:`\module` in store :math:`S` with imports :math:`\externval^n`, global initializer values :math:`\val^\ast`, and element segment contents :math:`(\reff^\ast)^\ast`, and let :math:`S'` be the extended store produced by module allocation. @@ -711,10 +711,13 @@ It is up to the :ref:`embedder ` to define how such conditions are rep &\wedge& \module.\MGLOBALS = \global^\ast \\ &\wedge& \module.\MELEMS = \elem^n \\ &\wedge& \module.\MDATAS = \data^m \\ - &\wedge& \module.\MSTART = \start^? \\[1ex] - &\wedge& S', \moduleinst = \allocmodule(S, \module, \externval^k, \val^\ast) \\ + &\wedge& \module.\MSTART = \start^? \\ + &\wedge& (\expr_{\F{g}} = \global.GINIT)^\ast \\ + &\wedge& (\expr_{\F{e}}^\ast = \elem.EINIT)^n \\[1ex] + &\wedge& S', \moduleinst = \allocmodule(S, \module, \externval^k, \val^\ast, (\reff^\ast)^n) \\ &\wedge& F = \{ \AMODULE~\moduleinst, \ALOCALS~\epsilon \} \\[1ex] - &\wedge& (S'; F; \global.\GINIT \stepto^\ast S'; F; \val~\END)^\ast \\ + &\wedge& (S'; F; \expr_{\F{g}} \stepto^\ast S'; F; \val~\END)^\ast \\ + &\wedge& ((S'; F; \expr_{\F{e}} \stepto^\ast S'; F; \reff~\END)^\ast)^n \\ &\wedge& (\tableaddr = \moduleinst.\MITABLES[\elem.\ETABLE])^\ast \\ &\wedge& (\memaddr = \moduleinst.\MIMEMS[\data.\DMEM])^\ast \\ &\wedge& (\funcaddr = \moduleinst.\MIFUNCS[\start.\SFUNC])^?) diff --git a/document/core/exec/runtime.rst b/document/core/exec/runtime.rst index 594255be7e..851b088e26 100644 --- a/document/core/exec/runtime.rst +++ b/document/core/exec/runtime.rst @@ -258,7 +258,6 @@ but within certain :ref:`constraints ` that ensure the integri .. index:: ! table instance, table, function address, table type, embedder, element segment pair: abstract syntax; table instance pair: table; instance -.. _syntax-funcelem: .. _syntax-tableinst: Table Instances @@ -340,7 +339,7 @@ It holds a vector of references and their common :ref:`type `. .. math:: \begin{array}{llll} \production{(element instance)} & \eleminst &::=& - \{ \EITYPE~\reftype, \EIELEM~\vec(\funcelem) \} \\ + \{ \EITYPE~\reftype, \EIELEM~\vec(\reff) \} \\ \end{array} diff --git a/document/core/text/instructions.rst b/document/core/text/instructions.rst index 8dfddabbac..dad0d02e1c 100644 --- a/document/core/text/instructions.rst +++ b/document/core/text/instructions.rst @@ -215,12 +215,30 @@ Table Instructions \text{table.size}~~x{:}\Ttableidx_I &\Rightarrow& \TABLESIZE~x \\ &&|& \text{table.grow}~~x{:}\Ttableidx_I &\Rightarrow& \TABLEGROW~x \\ &&|& \text{table.fill}~~x{:}\Ttableidx_I &\Rightarrow& \TABLEFILL~x \\ - \text{table.copy} &\Rightarrow& \TABLECOPY \\ &&|& - \text{table.init}~~x{:}\Telemidx_I &\Rightarrow& \TABLEINIT~x \\ &&|& + \text{table.copy}~~x{:}\Ttableidx_I~~y{:}\Ttableidx_I &\Rightarrow& \TABLECOPY~x~y \\ &&|& + \text{table.init}~~x{:}\Ttableidx_I~~y{:}\Telemidx_I &\Rightarrow& \TABLEINIT~x~y \\ &&|& \text{elem.drop}~~x{:}\Telemidx_I &\Rightarrow& \ELEMDROP~x \\ \end{array} +Abbreviations +............. + +For backwards compatibility, all :math:`table indices ` may be omitted from table instructions, defaulting to :math:`0`. + +.. math:: + \begin{array}{llclll} + \production{instruction} & + \text{table.get} &\equiv& \text{table.get}~~\text{0} \\ &&|& + \text{table.set} &\equiv& \text{table.set}~~\text{0} \\ &&|& + \text{table.size} &\equiv& \text{table.size}~~\text{0} \\ &&|& + \text{table.grow} &\equiv& \text{table.grow}~~\text{0} \\ &&|& + \text{table.fill} &\equiv& \text{table.fill}~~\text{0} \\ &&|& + \text{table.copy} &\equiv& \text{table.copy}~~\text{0}~~\text{0} \\ &&|& + \text{table.init}~~x{:}\Telemidx_I &\equiv& \text{table.init}~~\text{0}~~x{:}\Telemidx_I \\ &&|& + \end{array} + + .. index:: memory instruction, memory index pair: text format; instruction .. _text-instr-memory: diff --git a/document/core/text/modules.rst b/document/core/text/modules.rst index 57f4c630f7..ac61429aec 100644 --- a/document/core/text/modules.rst +++ b/document/core/text/modules.rst @@ -505,7 +505,7 @@ Element segments allow for an optional :ref:`table index ` to ide \production{element list} & \Telemlist &::=& t{:}\Treftype~~y^\ast{:}\Tvec(\Telemexpr_I) \qquad\Rightarrow\quad ( \ETYPE~t, \EINIT~y^\ast ) \\ \production{element expression} & \Telemexpr &::=& - \text{(}~e{:}\Tinstr~\text{)} + \text{(}~\text{item}~~e{:}\Texpr~\text{)} \quad\Rightarrow\quad e \\ \production{table use} & \Ttableuse_I &::=& \text{(}~\text{table}~~x{:}\Ttableidx_I ~\text{)} @@ -516,13 +516,16 @@ Element segments allow for an optional :ref:`table index ` to ide Abbreviations ............. -As an abbreviation, a single instruction may occur in place of the offset of an active element segment: +As an abbreviation, a single instruction may occur in place of the offset of an active element segment or as an element expression: .. math:: \begin{array}{llcll} \production{element offset} & \Tinstr &\equiv& - \text{(}~\text{offset}~~\Tinstr~\text{)} + \text{(}~\text{offset}~~\Tinstr~\text{)} \\ + \production{element item} & + \Tinstr &\equiv& + \text{(}~\text{item}~~\Tinstr~\text{)} \\ \end{array} Also, the element list may be written as just a sequence of :ref:`function indices `: @@ -534,7 +537,7 @@ Also, the element list may be written as just a sequence of :ref:`function indic \text{funcref}~~\Tvec(\text{(}~\text{ref.func}~~\Tfuncidx_I~\text{)}) \end{array} -Also, a table use can be omitted, defaulting to :math:`\T{0}`. +A table use can be omitted, defaulting to :math:`\T{0}`. Furthermore, for backwards compatibility with earlier versions of WebAssembly, if the table use is omitted, the :math:`\text{func}` keyword can be omitted as well. .. math:: diff --git a/document/core/util/macros.def b/document/core/util/macros.def index 87b5ca2804..f2ad64f37b 100644 --- a/document/core/util/macros.def +++ b/document/core/util/macros.def @@ -903,7 +903,6 @@ .. |moduleinst| mathdef:: \xref{exec/runtime}{syntax-moduleinst}{\X{moduleinst}} .. |funcinst| mathdef:: \xref{exec/runtime}{syntax-funcinst}{\X{funcinst}} .. |tableinst| mathdef:: \xref{exec/runtime}{syntax-tableinst}{\X{tableinst}} -.. |funcelem| mathdef:: \xref{exec/runtime}{syntax-funcelem}{\X{funcelem}} .. |meminst| mathdef:: \xref{exec/runtime}{syntax-meminst}{\X{meminst}} .. |globalinst| mathdef:: \xref{exec/runtime}{syntax-globalinst}{\X{globalinst}} .. |eleminst| mathdef:: \xref{exec/runtime}{syntax-eleminst}{\X{eleminst}} diff --git a/interpreter/README.md b/interpreter/README.md index f38f57207a..4a1c937ec7 100644 --- a/interpreter/README.md +++ b/interpreter/README.md @@ -216,7 +216,7 @@ op: br_table + return call - call_indirect + call_indirect ? drop select local.get @@ -224,13 +224,13 @@ op: local.tee global.get global.set - table.get - table.set - table.size - table.grow - table.fill - table.copy - table.init + table.get ? + table.set ? + table.size ? + table.grow ? + table.fill ? + table.copy ? ? + table.init ? elem.drop .load((8|16|32)_)? ? ? .store(8|16|32)? ? ? @@ -263,15 +263,18 @@ global: ( global ? * ) table: ( table ? ) ( table ? ( export ) <...> ) ;; = (export (table )) (table ? <...>) ( table ? ( import ) ) ;; = (import ? (table )) - ( table ? ( export )* ( elem * ) ) ;; = (table ? ( export )* ) (elem (i32.const 0) *) -elem: ( elem ? (offset * ) * ) - ( elem ? * ) ;; = (elem ? (offset ) *) + ( table ? ( export )* ( elem * ) ) ;; = (table ? ( export )* ) (elem (i32.const 0) *) +elem: ( elem ? ( table )? * ) + ( elem ? ( table )? func * ) ;; = (elem ? ( table )? funcref (ref.func )*) +offset: ( offset * ) + ;; = ( offset ) +item: ( item * ) + ;; = ( item ) memory: ( memory ? ) ( memory ? ( export ) <...> ) ;; = (export (memory ))+ (memory ? <...>) ( memory ? ( import ) ) ;; = (import ? (memory )) ( memory ? ( export )* ( data * ) ) ;; = (memory ? ( export )* ) (data (i32.const 0) *) -data: ( data ? ( offset * ) * ) - ( data ? * ) ;; = (data ? (offset ) *) +data: ( data ? ( memory )? * ) start: ( start ) diff --git a/interpreter/exec/eval.ml b/interpreter/exec/eval.ml index 7a9039fe07..8fc0336069 100644 --- a/interpreter/exec/eval.ml +++ b/interpreter/exec/eval.ml @@ -57,6 +57,7 @@ type code = value stack * admin_instr list and admin_instr = admin_instr' phrase and admin_instr' = | Plain of instr' + | Refer of ref_ | Invoke of func_inst | Trapping of string | Returning of value stack @@ -240,20 +241,43 @@ let rec step (c : config) : config = vs', [] else let _ = assert (I32.lt_u i 0xffff_ffffl) in - Ref r :: Num (I32 i) :: Num (I32 (I32.sub n 1l)) :: - Ref r :: Num (I32 (I32.add i 1l)) :: vs', - [Plain (TableSet x) @@ e.at; Plain (TableFill x) @@ e.at] + vs', List.map (at e.at) [ + Plain (Const (I32 i @@ e.at)); + Refer r; + Plain (TableSet x); + Plain (Const (I32 (I32.add i 1l) @@ e.at)); + Refer r; + Plain (Const (I32 (I32.sub n 1l) @@ e.at)); + Plain (TableFill x); + ] | TableCopy (x, y), Num (I32 n) :: Num (I32 s) :: Num (I32 d) :: vs' -> if table_oob frame x d n || table_oob frame y s n then vs', [Trapping (table_error e.at Table.Bounds) @@ e.at] else if n = 0l then vs', [] - else - (* TODO: turn into small-step, but needs reference values *) - let tab = table frame.inst x in (*TODO*) - (try Table.copy tab d s n; vs', [] - with exn -> vs', [Trapping (table_error e.at exn) @@ e.at]) + else if d <= s then + vs', List.map (at e.at) [ + Plain (Const (I32 d @@ e.at)); + Plain (Const (I32 s @@ e.at)); + Plain (TableGet y); + Plain (TableSet x); + Plain (Const (I32 (I32.add d 1l) @@ e.at)); + Plain (Const (I32 (I32.add s 1l) @@ e.at)); + Plain (Const (I32 (I32.sub n 1l) @@ e.at)); + Plain (TableCopy (x, y)); + ] + else (* d > s *) + vs', List.map (at e.at) [ + Plain (Const (I32 (I32.add d 1l) @@ e.at)); + Plain (Const (I32 (I32.add s 1l) @@ e.at)); + Plain (Const (I32 (I32.sub n 1l) @@ e.at)); + Plain (TableCopy (x, y)); + Plain (Const (I32 d @@ e.at)); + Plain (Const (I32 s @@ e.at)); + Plain (TableGet y); + Plain (TableSet x); + ] | TableInit (x, y), Num (I32 n) :: Num (I32 s) :: Num (I32 d) :: vs' -> if table_oob frame x d n || elem_oob frame y s n then @@ -261,11 +285,16 @@ let rec step (c : config) : config = else if n = 0l then vs', [] else - (* TODO: turn into small-step, but needs reference values *) - let tab = table frame.inst x in let seg = !(elem frame.inst y) in - (try Table.init tab seg d s n; vs', [] - with exn -> vs', [Trapping (table_error e.at exn) @@ e.at]) + vs', List.map (at e.at) [ + Plain (Const (I32 d @@ e.at)); + Refer (List.nth seg (Int32.to_int s)); + Plain (TableSet x); + Plain (Const (I32 (I32.add d 1l) @@ e.at)); + Plain (Const (I32 (I32.add s 1l) @@ e.at)); + Plain (Const (I32 (I32.sub n 1l) @@ e.at)); + Plain (TableInit (x, y)); + ] | ElemDrop x, vs -> let seg = elem frame.inst x in @@ -421,6 +450,9 @@ let rec step (c : config) : config = ("missing or ill-typed operand on stack (" ^ s1 ^ " : " ^ s2 ^ ")") ) + | Refer r, vs -> + Ref r :: vs, [] + | Trapping msg, vs -> assert false diff --git a/interpreter/runtime/table.ml b/interpreter/runtime/table.ml index 811edcff72..8da0090eb5 100644 --- a/interpreter/runtime/table.ml +++ b/interpreter/runtime/table.ml @@ -58,26 +58,3 @@ let blit tab offset rs = let data = Array.of_list rs in try Lib.Array32.blit data 0l tab.content offset (Lib.Array32.length data) with Invalid_argument _ -> raise Bounds - -(*TODO: remove*) -let init tab es d s n = - let rec loop es d s n = - match s, n, es with - | s, 0l, _ -> () - | 0l, n, e::es' -> - store tab d e; - loop es' (Int32.add d 1l) 0l (Int32.sub n 1l) - | s, n, _::es' -> loop es' d (Int32.sub s 1l) n - | _ -> raise Bounds - in loop es d s n - -let copy tab d s n = - let rec loop d s n dx = - if I32.gt_u n 0l then begin - store tab d (load tab s); - loop (Int32.add d dx) (Int32.add s dx) (Int32.sub n 1l) dx - end - in (if s < d then - loop Int32.(add d (sub n 1l)) Int32.(add s (sub n 1l)) n (-1l) - else - loop d s n 1l) diff --git a/interpreter/runtime/table.mli b/interpreter/runtime/table.mli index dcc28f686f..cf424e3572 100644 --- a/interpreter/runtime/table.mli +++ b/interpreter/runtime/table.mli @@ -23,8 +23,3 @@ val grow : table -> size -> ref_ -> unit val load : table -> index -> ref_ (* raises Bounds *) val store : table -> index -> ref_ -> unit (* raises Type, Bounds *) val blit : table -> index -> ref_ list -> unit (* raises Bounds *) - -(*TODO: remove*) -val init : - table -> ref_ list -> index -> index -> count -> unit (* raises Bounds *) -val copy : table -> index -> index -> count -> unit (* raises Bounds *) diff --git a/interpreter/syntax/ast.ml b/interpreter/syntax/ast.ml index 5926bffd79..79181e800b 100644 --- a/interpreter/syntax/ast.ml +++ b/interpreter/syntax/ast.ml @@ -63,7 +63,7 @@ type storeop = Memory.pack_size memop (* Expressions *) type var = int32 Source.phrase -type literal = Values.num Source.phrase +type num = Values.num Source.phrase type name = int list type instr = instr' Source.phrase @@ -105,7 +105,7 @@ and instr' = | RefNull (* null reference *) | RefIsNull (* null test *) | RefFunc of var (* function reference *) - | Const of literal (* constant *) + | Const of num (* constant *) | Test of testop (* numeric test *) | Compare of relop (* numeric comparison *) | Unary of unop (* unary numeric operator *) diff --git a/interpreter/text/arrange.ml b/interpreter/text/arrange.ml index 72420679d0..ce32cc6269 100644 --- a/interpreter/text/arrange.ml +++ b/interpreter/text/arrange.ml @@ -251,8 +251,8 @@ let rec instr e = | TableSize x -> "table.size " ^ var x, [] | TableGrow x -> "table.grow " ^ var x, [] | TableFill x -> "table.fill " ^ var x, [] - | TableCopy (x, y) -> "table.copy", [] (*TODO*) - | TableInit (x, y) -> "table.init " ^ var y, [] (*TODO*) + | TableCopy (x, y) -> "table.copy " ^ var x ^ " " ^ var y, [] + | TableInit (x, y) -> "table.init " ^ var x ^ " " ^ var y, [] | ElemDrop x -> "elem.drop " ^ var x, [] | Load op -> loadop op, [] | Store op -> storeop op, [] @@ -265,7 +265,7 @@ let rec instr e = | RefNull -> "ref.null", [] | RefIsNull -> "ref.is_null", [] | RefFunc x -> "ref.func " ^ var x, [] - | Const lit -> constop lit ^ " " ^ num lit, [] + | Const n -> constop n ^ " " ^ num n, [] | Test op -> testop op, [] | Compare op -> relop op, [] | Unary op -> unop op, [] diff --git a/interpreter/text/lexer.mll b/interpreter/text/lexer.mll index 9511a8e3d0..a74a4431e0 100644 --- a/interpreter/text/lexer.mll +++ b/interpreter/text/lexer.mll @@ -349,6 +349,7 @@ rule token = parse | "elem" { ELEM } | "data" { DATA } | "offset" { OFFSET } + | "item" { ITEM } | "import" { IMPORT } | "export" { EXPORT } diff --git a/interpreter/text/parser.mly b/interpreter/text/parser.mly index 2f36c3f54b..8220539a9f 100644 --- a/interpreter/text/parser.mly +++ b/interpreter/text/parser.mly @@ -36,7 +36,7 @@ let ati i = (* Literals *) -let literal f s = +let num f s = try f s with Failure _ -> error s.at "constant out of range" let nanop f nan = @@ -176,7 +176,7 @@ let inline_type_explicit (c : context) x ft at = %token CONST UNARY BINARY TEST COMPARE CONVERT %token REF_ANY REF_NULL REF_FUNC REF_HOST REF_IS_NULL %token FUNC START TYPE PARAM RESULT LOCAL GLOBAL -%token TABLE ELEM MEMORY DATA OFFSET IMPORT EXPORT +%token TABLE ELEM MEMORY DATA OFFSET ITEM IMPORT EXPORT %token MODULE BIN QUOTE %token SCRIPT REGISTER INVOKE GET %token ASSERT_MALFORMED ASSERT_INVALID ASSERT_SOFT_INVALID ASSERT_UNLINKABLE @@ -274,7 +274,7 @@ type_use : /* Immediates */ -literal : +num : | NAT { $1 @@ at () } | INT { $1 @@ at () } | FLOAT { $1 @@ at () } @@ -352,9 +352,17 @@ plain_instr : | TABLE_SIZE var { fun c -> table_size ($2 c table) } | TABLE_GROW var { fun c -> table_grow ($2 c table) } | TABLE_FILL var { fun c -> table_fill ($2 c table) } - | TABLE_COPY { let at = ati 1 in fun c -> table_copy (0l @@ at) (0l @@ at) } - | TABLE_INIT var /*TODO*/ - { let at = ati 1 in fun c -> table_init (0l @@ at) ($2 c elem) } + | TABLE_COPY var var { fun c -> table_copy ($2 c table) ($3 c table) } + | TABLE_INIT var var { fun c -> table_init ($2 c table) ($3 c elem) } + | TABLE_GET { let at = at () in fun c -> table_get (0l @@ at) } /* Sugar */ + | TABLE_SET { let at = at () in fun c -> table_set (0l @@ at) } /* Sugar */ + | TABLE_SIZE { let at = at () in fun c -> table_size (0l @@ at) } /* Sugar */ + | TABLE_GROW { let at = at () in fun c -> table_grow (0l @@ at) } /* Sugar */ + | TABLE_FILL { let at = at () in fun c -> table_fill (0l @@ at) } /* Sugar */ + | TABLE_COPY /* Sugar */ + { let at = at () in fun c -> table_copy (0l @@ at) (0l @@ at) } + | TABLE_INIT var /* Sugar */ + { let at = at () in fun c -> table_init (0l @@ at) ($2 c elem) } | ELEM_DROP var { fun c -> elem_drop ($2 c elem) } | LOAD offset_opt align_opt { fun c -> $1 $3 $2 } | STORE offset_opt align_opt { fun c -> $1 $3 $2 } @@ -367,7 +375,7 @@ plain_instr : | REF_NULL { fun c -> ref_null } | REF_IS_NULL { fun c -> ref_is_null } | REF_FUNC var { fun c -> ref_func ($2 c func) } - | CONST literal { fun c -> fst (literal $1 $2) } + | CONST num { fun c -> fst (num $1 $2) } | TEST { fun c -> $1 } | COMPARE { fun c -> $1 } | UNARY { fun c -> $1 } @@ -648,7 +656,7 @@ elem_kind : | FUNC { FuncRefType } elem_expr : - /* TODO: | LPAR ITEM const_expr RPAR { $3 } */ + | LPAR ITEM const_expr RPAR { $3 } | expr { let at = at () in fun c -> $1 c @@ at } /* Sugar */ elem_expr_list : @@ -733,16 +741,16 @@ data : { let at = at () in fun c -> ignore ($3 c anon_data bind_data); fun () -> {dinit = $4; dmode = Passive @@ at} @@ at } - | LPAR DATA bind_var_opt memory_use offset string_list RPAR - { let at = at () in - fun c -> ignore ($3 c anon_data bind_data); - fun () -> - {dinit = $6; dmode = Active {index = $4 c memory; offset = $5 c} @@ at} @@ at } - | LPAR DATA bind_var_opt offset string_list RPAR /* Sugar */ - { let at = at () in - fun c -> ignore ($3 c anon_data bind_data); - fun () -> - {dinit = $5; dmode = Active {index = 0l @@ at; offset = $4 c} @@ at} @@ at } + | LPAR DATA bind_var_opt memory_use offset string_list RPAR + { let at = at () in + fun c -> ignore ($3 c anon_data bind_data); + fun () -> + {dinit = $6; dmode = Active {index = $4 c memory; offset = $5 c} @@ at} @@ at } + | LPAR DATA bind_var_opt offset string_list RPAR /* Sugar */ + { let at = at () in + fun c -> ignore ($3 c anon_data bind_data); + fun () -> + {dinit = $5; dmode = Active {index = 0l @@ at; offset = $4 c} @@ at} @@ at } memory : | LPAR MEMORY bind_var_opt memory_fields RPAR @@ -972,7 +980,7 @@ meta : | LPAR OUTPUT script_var_opt RPAR { Output ($3, None) @@ at () } const : - | LPAR CONST literal RPAR { Values.Num (snd (literal $2 $3)) @@ at () } + | LPAR CONST num RPAR { Values.Num (snd (num $2 $3)) @@ at () } | LPAR REF_NULL RPAR { Values.Ref Values.NullRef @@ at () } | LPAR REF_HOST NAT RPAR { Values.Ref (HostRef (nat32 $3 (ati 3))) @@ at () } diff --git a/proposals/reference-types/Overview.md b/proposals/reference-types/Overview.md index e051112971..8e35ab7106 100644 --- a/proposals/reference-types/Overview.md +++ b/proposals/reference-types/Overview.md @@ -117,6 +117,8 @@ New/extended instructions: - and `$x : table t'` - and `t' <: funcref` +* In all instructions, table indices can be omitted and default to 0. + Note: - In the binary format, space for the additional table indices is already reserved. - For backwards compatibility, all table indices may be omitted in the text format, in which case they default to 0 (for `table.copy`, both indices must be either present or absent). diff --git a/test/core/elem.wast b/test/core/elem.wast index bb622ee662..b594acd6e3 100644 --- a/test/core/elem.wast +++ b/test/core/elem.wast @@ -8,7 +8,7 @@ ;; Passive (elem funcref) - (elem funcref (ref.func $f) (ref.func $f) (ref.null) (ref.func $g)) + (elem funcref (ref.func $f) (item ref.func $f) (item (ref.null)) (ref.func $g)) (elem func) (elem func $f $f $g $g) From 64f9837a8af5285c96e76235d174b6b47b9e124e Mon Sep 17 00:00:00 2001 From: Andreas Rossberg Date: Thu, 16 Jan 2020 17:12:28 +0100 Subject: [PATCH 141/199] [spec/interpreter/test] Declarative element segments (#73) --- document/core/binary/modules.rst | 10 +++++--- document/core/exec/modules.rst | 4 +++- document/core/syntax/modules.rst | 14 +++++++---- document/core/text/modules.rst | 4 +++- document/core/util/macros.def | 18 +++++++------- document/core/valid/conventions.rst | 4 +++- document/core/valid/instructions.rst | 4 ++++ document/core/valid/modules.rst | 22 +++++++++++++---- interpreter/README.md | 7 +++++- interpreter/binary/decode.ml | 13 +++++++++++ interpreter/binary/encode.ml | 6 +++++ interpreter/exec/eval.ml | 13 +++++++---- interpreter/syntax/ast.ml | 1 + interpreter/syntax/free.ml | 12 +++++----- interpreter/syntax/free.mli | 2 ++ interpreter/text/arrange.ml | 13 ++++++----- interpreter/text/lexer.mll | 1 + interpreter/text/parser.mly | 7 +++++- interpreter/util/lib.ml | 1 + interpreter/util/lib.mli | 1 + interpreter/valid/valid.ml | 20 ++++++++++++++-- test/core/elem.wast | 35 ++++++++++++++++++++++++++++ test/core/linking.wast | 1 + test/core/ref_func.wast | 24 ++++++++++++++++++- test/core/table_grow.wast | 2 ++ 25 files changed, 194 insertions(+), 45 deletions(-) diff --git a/document/core/binary/modules.rst b/document/core/binary/modules.rst index e947fc30d1..706044fc89 100644 --- a/document/core/binary/modules.rst +++ b/document/core/binary/modules.rst @@ -333,20 +333,24 @@ It decodes into a vector of :ref:`element segments ` that represent &\Rightarrow& \{ \ETYPE~\X{et}, \EINIT~((\REFFUNC~y)~\END)^\ast, \EMODE~\EPASSIVE \} \\ &&|& \hex{02}~~x{:}\Btableidx~~e{:}\Bexpr~~\X{et}:\Belemkind~~y^\ast{:}\Bvec(\Bfuncidx) &\Rightarrow& \{ \ETYPE~\X{et}, \EINIT~((\REFFUNC~y)~\END)^\ast, \EMODE~\EACTIVE~\{ \ETABLE~x, \EOFFSET~e \} \} \\ &&|& + \hex{03}~~\X{et}:\Belemkind~~y^\ast{:}\Bvec(\Bfuncidx) + &\Rightarrow& \{ \ETYPE~\X{et}, \EINIT~((\REFFUNC~y)~\END)^\ast, \EMODE~\EDECLARATIVE \} \\ &&|& \hex{04}~~e{:}\Bexpr~~\X{el}^\ast{:}\Bvec(\Bexpr) &\Rightarrow& \{ \ETYPE~\FUNCREF, \EINIT~\X{el}^\ast, \EMODE~\EACTIVE~\{ \ETABLE~0, \EOFFSET~e \} \} \\ &&|& \hex{05}~~\X{et}:\Breftype~~\X{el}^\ast{:}\Bvec(\Bexpr) &\Rightarrow& \{ \ETYPE~et, \EINIT~\X{el}^\ast, \EMODE~\EPASSIVE \} \\ &&|& \hex{06}~~x{:}\Btableidx~~e{:}\Bexpr~~\X{et}:\Breftype~~\X{el}^\ast{:}\Bvec(\Bexpr) - &\Rightarrow& \{ \ETYPE~et, \EINIT~\X{el}^\ast, \EMODE~\EACTIVE~\{ \ETABLE~x, \EOFFSET~e \} \} \\ + &\Rightarrow& \{ \ETYPE~et, \EINIT~\X{el}^\ast, \EMODE~\EACTIVE~\{ \ETABLE~x, \EOFFSET~e \} \} \\ &&|& + \hex{07}~~\X{et}:\Breftype~~\X{el}^\ast{:}\Bvec(\Bexpr) + &\Rightarrow& \{ \ETYPE~et, \EINIT~\X{el}^\ast, \EMODE~\EDECLARATIVE \} \\ \production{element kind} & \Belemkind &::=& \hex{00} &\Rightarrow& \FUNCREF \\ \end{array} .. note:: The initial byte can be interpreted as a bitfield. - Bit 0 indicates a passive segment, - bit 1 indicates the presence of an explicit table index for an active segment, + Bit 0 indicates a passive or declarative segment, + bit 1 indicates the presence of an explicit table index for an active segment and otherwise distinguishes passive from declarative segments, bit 2 indicates the use of element type and element :ref:`expressions ` instead of element kind and element indices. Additional element kinds may be added in future versions of WebAssembly. diff --git a/document/core/exec/modules.rst b/document/core/exec/modules.rst index 002964b91d..eb46eb6836 100644 --- a/document/core/exec/modules.rst +++ b/document/core/exec/modules.rst @@ -729,7 +729,9 @@ where: \begin{array}{@{}l} \F{runelem}_i(\{\ETYPE~\X{et}, \EINIT~\reff^n, \EMODE~\EPASSIVE\}) \quad=\quad \epsilon \\ \F{runelem}_i(\{\ETYPE~\X{et}, \EINIT~\reff^n, \EMODE~\EACTIVE \{\ETABLE~0, \EOFFSET~\instr^\ast~\END\}\}) \quad=\\ \qquad - \instr^\ast~(\I32.\CONST~0)~(\I32.\CONST~n)~(\TABLEINIT~i)~(\ELEMDROP~i) \\[1ex] + \instr^\ast~(\I32.\CONST~0)~(\I32.\CONST~n)~(\TABLEINIT~i)~(\ELEMDROP~i) \\ + \F{runelem}_i(\{\ETYPE~\X{et}, \EINIT~\reff^n, \EMODE~\EDECLARATIVE\}) \quad=\\ \qquad + (\ELEMDROP~i) \\[1ex] \F{rundata}_i(\{\DINIT~b^n, DMODE~\DPASSIVE\}) \quad=\quad \epsilon \\ \F{rundata}_i(\{\DINIT~b^n, DMODE~\DACTIVE \{\DMEM~0, \DOFFSET~\instr^\ast~\END\}\}) \quad=\\ \qquad \instr^\ast~(\I32.\CONST~0)~(\I32.\CONST~n)~(\MEMORYINIT~i)~(\DATADROP~i) \\ diff --git a/document/core/syntax/modules.rst b/document/core/syntax/modules.rst index 91562bce6f..f0973d814e 100644 --- a/document/core/syntax/modules.rst +++ b/document/core/syntax/modules.rst @@ -106,10 +106,10 @@ Conventions * The meta variables :math:`x, y` range over indices in any of the other index spaces. -* The notation :math:`\F{idx}(A)` denotes the set of indices from index space :math:`\X{idx}` occurring free in :math:`A`. +* The notation :math:`\F{idx}(A)` denotes the set of indices from index space :math:`\X{idx}` occurring free in :math:`A`. We sometimes reinterpret this set as the :ref:`vector ` of its elements. .. note:: - For example, if :math:`\instr^\ast` is :math:`(\DATADROP~x) (\MEMORYINIT~y)`, then :math:`\freedataidx(\instr^\ast) = \{x, y\}`. + For example, if :math:`\instr^\ast` is :math:`(\DATADROP~x) (\MEMORYINIT~y)`, then :math:`\freedataidx(\instr^\ast) = \{x, y\}`, or equivalently, the vector :math:`x~y`. .. index:: ! type definition, type index, function type @@ -242,10 +242,12 @@ Globals are referenced through :ref:`global indices `, starting with the smallest index not referencing a global :ref:`import `. -.. index:: ! element, active, passive, element index, table, table index, expression, constant, function index, vector +.. index:: ! element, ! element mode, ! active, ! passive, ! declarative, element index, table, table index, expression, constant, function index, vector pair: abstract syntax; element + pair: abstract syntax; element mode single: table; element single: element; segment + single: element; mode .. _syntax-elem: .. _syntax-elemmode: @@ -257,9 +259,10 @@ The initial contents of a table is uninitialized. *Element segments* can be used The |MELEMS| component of a module defines a vector of element segments. Each element segment defines an :ref:`reference type ` and a corresponding list of :ref:`constant ` element :ref:`expressions `. -Element segments have a mode that identifies them as either *passive* or *active*. +Element segments have a mode that identifies them as either *passive*, *active*, or *declarative*. A passive element segment's elements can be copied to a table using the |TABLEINIT| instruction. An active element segment copies its elements into a table during :ref:`instantiation `, as specified by a :ref:`table index ` and a :ref:`constant ` :ref:`expression ` defining an offset into that table. +A declarative element segment is not available at runtime but merely serves to forward-declare references that are formed in code with instructions like :math:`REFFUNC`. .. math:: \begin{array}{llll} @@ -267,7 +270,8 @@ An active element segment copies its elements into a table during :ref:`instanti \{ \ETYPE~\reftype, \EINIT~\vec(\expr), \EMODE~\elemmode \} \\ \production{element segment mode} & \elemmode &::=& \EPASSIVE \\&&|& - \EACTIVE~\{ \ETABLE~\tableidx, \EOFFSET~\expr \} \\ + \EACTIVE~\{ \ETABLE~\tableidx, \EOFFSET~\expr \} \\&&|& + \EDECLARATIVE \\ \end{array} The |EOFFSET| is given by a :ref:`constant ` :ref:`expression `. diff --git a/document/core/text/modules.rst b/document/core/text/modules.rst index ac61429aec..b23cdb7d9d 100644 --- a/document/core/text/modules.rst +++ b/document/core/text/modules.rst @@ -501,7 +501,9 @@ Element segments allow for an optional :ref:`table index ` to ide \text{(}~\text{elem}~~\Tid^?~~(et, y^\ast){:}\Telemlist~\text{)} \\ &&& \qquad \Rightarrow\quad \{ \ETYPE~et, \EINIT~y^\ast, \EMODE~\EPASSIVE \} \\ &&|& \text{(}~\text{elem}~~\Tid^?~~x{:}\Ttableuse_I~~\text{(}~\text{offset}~~e{:}\Texpr_I~\text{)}~~(et, y^\ast){:}\Telemlist~\text{)} \\ &&& \qquad - \Rightarrow\quad \{ \ETYPE~et, \EINIT~y^\ast, \EMODE~\EACTIVE~\{ \ETABLE~x, \EOFFSET~e \} \} \\ + \Rightarrow\quad \{ \ETYPE~et, \EINIT~y^\ast, \EMODE~\EACTIVE~\{ \ETABLE~x, \EOFFSET~e \} \} \\ &&& + \text{(}~\text{elem}~~\Tid^?~~\text{declare}~~(et, y^\ast){:}\Telemlist~\text{)} \\ &&& \qquad + \Rightarrow\quad \{ \ETYPE~et, \EINIT~y^\ast, \EMODE~\EDECLARATIVE \} \\ \production{element list} & \Telemlist &::=& t{:}\Treftype~~y^\ast{:}\Tvec(\Telemexpr_I) \qquad\Rightarrow\quad ( \ETYPE~t, \EINIT~y^\ast ) \\ \production{element expression} & \Telemexpr &::=& diff --git a/document/core/util/macros.def b/document/core/util/macros.def index f2ad64f37b..4151d7a509 100644 --- a/document/core/util/macros.def +++ b/document/core/util/macros.def @@ -3,20 +3,20 @@ .. External Standards .. ------------------ -.. |WasmDraft| replace:: http://webassembly.github.io/spec/core/ -.. _WasmDraft: http://webassembly.github.io/spec/core/ +.. |WasmDraft| replace:: https://webassembly.github.io/reference-types/core/ +.. _WasmDraft: https://webassembly.github.io/reference-types/core/ -.. |WasmIssues| replace:: http://github.com/webassembly/spec/issues/ -.. _WasmIssues: http://github.com/webassembly/spec/issues/ +.. |WasmIssues| replace:: https://github.com/webassembly/reference-types/issues/ +.. _WasmIssues: https://github.com/webassembly/reference-types/issues/ .. |IEEE754| replace:: IEEE 754-2019 .. _IEEE754: https://ieeexplore.ieee.org/document/8766229 .. |Unicode| replace:: Unicode -.. _Unicode: http://www.unicode.org/versions/latest/ +.. _Unicode: https://www.unicode.org/versions/latest/ .. |ASCII| replace:: ASCII -.. _ASCII: http://webstore.ansi.org/RecordDetail.aspx?sku=INCITS+4-1986%5bR2012%5d +.. _ASCII: https://webstore.ansi.org/RecordDetail.aspx?sku=INCITS+4-1986%5bR2012%5d .. External Definitions @@ -273,8 +273,9 @@ .. |ETYPE| mathdef:: \xref{syntax/modules}{syntax-elem}{\K{type}} .. |EINIT| mathdef:: \xref{syntax/modules}{syntax-elem}{\K{init}} .. |EMODE| mathdef:: \xref{syntax/modules}{syntax-elem}{\K{mode}} -.. |EPASSIVE| mathdef:: \xref{syntax/modules}{syntax-elem}{\K{passive}} -.. |EACTIVE| mathdef:: \xref{syntax/modules}{syntax-elem}{\K{active}} +.. |EPASSIVE| mathdef:: \xref{syntax/modules}{syntax-elemmode}{\K{passive}} +.. |EACTIVE| mathdef:: \xref{syntax/modules}{syntax-elemmode}{\K{active}} +.. |EDECLARATIVE| mathdef:: \xref{syntax/modules}{syntax-elemmode}{\K{declarative}} .. |ETABLE| mathdef:: \xref{syntax/modules}{syntax-elem}{\K{table}} .. |EOFFSET| mathdef:: \xref{syntax/modules}{syntax-elem}{\K{offset}} @@ -782,6 +783,7 @@ .. |CLOCALS| mathdef:: \xref{valid/conventions}{context}{\K{locals}} .. |CLABELS| mathdef:: \xref{valid/conventions}{context}{\K{labels}} .. |CRETURN| mathdef:: \xref{valid/conventions}{context}{\K{return}} +.. |CREFS| mathdef:: \xref{valid/conventions}{context}{\K{refs}} .. Judgments diff --git a/document/core/valid/conventions.rst b/document/core/valid/conventions.rst index 7f132d7ea3..9c0a4046bd 100644 --- a/document/core/valid/conventions.rst +++ b/document/core/valid/conventions.rst @@ -43,6 +43,7 @@ which collects relevant information about the surrounding :ref:`module ` that occur in element segments and can hence be used to form references elsewhere. In other words, a context contains a sequence of suitable :ref:`types ` for each :ref:`index space `, describing each defined entry in that space. @@ -64,7 +65,8 @@ More concretely, contexts are defined as :ref:`records ` :math: & \CDATAS & {\ok}^\ast, \\ & \CLOCALS & \valtype^\ast, \\ & \CLABELS & \resulttype^\ast, \\ - & \CRETURN & \resulttype^? ~\} \\ + & \CRETURN & \resulttype^?, \\ + & \CREFS & \funcidx^\ast ~\} \\ \end{array} \end{array} diff --git a/document/core/valid/instructions.rst b/document/core/valid/instructions.rst index 9a27e94441..843a736acc 100644 --- a/document/core/valid/instructions.rst +++ b/document/core/valid/instructions.rst @@ -198,11 +198,15 @@ Reference Instructions * The function :math:`C.\CFUNCS[x]` must be defined in the context. +* The :ref:`function index ` :math:`x` must be contained in :math:`C.\CREFS`. + * The instruction is valid with type :math:`[] \to [\FUNCREF]`. .. math:: \frac{ C.\CFUNCS[x] = \functype + \qquad + x \in C.\CREFS }{ C \vdashinstr \REFFUNC~x : [] \to [\FUNCREF] } diff --git a/document/core/valid/modules.rst b/document/core/valid/modules.rst index 461b9a5563..4337cf867d 100644 --- a/document/core/valid/modules.rst +++ b/document/core/valid/modules.rst @@ -217,6 +217,18 @@ Element segments :math:`\elem` are not classified by any type but merely checked C; \X{et} \vdashelemmode \EACTIVE~\{ \ETABLE~x, \EOFFSET~\expr \} \ok } +:math:`\EDECLARATIVE` +..................... + +* The element mode is valid for any :ref:`reference type ` :math:`\X{et}`. + +.. math:: + \frac{ + }{ + C; \X{et} \vdashelemmode \EDECLARATIVE \ok + } + + .. index:: data, memory, memory index, expression, byte pair: validation; data @@ -278,7 +290,7 @@ Data segments :math:`\data` are not classified by any type but merely checked fo \qquad C \vdashexprconst \expr \const }{ - C \vdashelemmode \EACTIVE~\{ \DMEM~x, \DOFFSET~\expr \} \ok + C \vdashelemmode \DACTIVE~\{ \DMEM~x, \DOFFSET~\expr \} \ok } @@ -529,6 +541,8 @@ Instead, the context :math:`C` for validation of the module's content is constru * :math:`C.\CRETURN` is empty. + * :math:`C.\CREFS` is the set :math:`\freefuncidx(\module.\MELEMS)`, i.e., the set of :ref:`function indices ` occurring in any of the module's :ref:`element segments `. + * Let :math:`C'` be the :ref:`context ` where :math:`C'.\CGLOBALS` is the sequence :math:`\etglobals(\X{it}^\ast)` and all other fields are empty. * Under the context :math:`C`: @@ -614,7 +628,7 @@ Instead, the context :math:`C` for validation of the module's content is constru \qquad \X{igt}^\ast = \etglobals(\X{it}^\ast) \\ - C = \{ \CTYPES~\functype^\ast, \CFUNCS~\X{ift}^\ast~\X{ft}^\ast, \CTABLES~\X{itt}^\ast~\X{tt}^\ast, \CMEMS~\X{imt}^\ast~\X{mt}^\ast, \CGLOBALS~\X{igt}^\ast~\X{gt}^\ast, \CELEMS~{\ok}^{N_e}, \CDATAS~{\ok}^{N_d} \} + C = \{ \CTYPES~\functype^\ast, \CFUNCS~\X{ift}^\ast~\X{ft}^\ast, \CTABLES~\X{itt}^\ast~\X{tt}^\ast, \CMEMS~\X{imt}^\ast~\X{mt}^\ast, \CGLOBALS~\X{igt}^\ast~\X{gt}^\ast, \CELEMS~{\ok}^{N_e}, \CDATAS~{\ok}^{N_d}, \CREFS~\freefuncidx(\elem^{N_e}) \} \\ C' = \{ \CGLOBALS~\X{igt}^\ast \} \qquad @@ -630,8 +644,8 @@ Instead, the context :math:`C` for validation of the module's content is constru \MTABLES~\table^\ast, \MMEMS~\mem^\ast, \MGLOBALS~\global^\ast, \\ - \MELEMS~\elem^\ast, - \MDATAS~\data^\ast, + \MELEMS~\elem^{N_e}, + \MDATAS~\data^{N_d}, \MSTART~\start^?, \MIMPORTS~\import^\ast, \MEXPORTS~\export^\ast \} : \X{it}^\ast \to \X{et}^\ast \\ diff --git a/interpreter/README.md b/interpreter/README.md index 4a1c937ec7..f88950005e 100644 --- a/interpreter/README.md +++ b/interpreter/README.md @@ -262,10 +262,15 @@ global: ( global ? * ) ( global ? ( import ) ) ;; = (import ? (global )) table: ( table ? ) ( table ? ( export ) <...> ) ;; = (export (table )) (table ? <...>) - ( table ? ( import ) ) ;; = (import ? (table )) + ( table ? ( import ) ) ;; = (import (table ? )) ( table ? ( export )* ( elem * ) ) ;; = (table ? ( export )* ) (elem (i32.const 0) *) +elem: ( elem ? (offset * ) * ) + ( elem ? * ) ;; = (elem ? (offset ) *) + ( elem ? declare * ) elem: ( elem ? ( table )? * ) ( elem ? ( table )? func * ) ;; = (elem ? ( table )? funcref (ref.func )*) + ( elem ? declare? * ) + ( elem ? declare? func * ) ;; = (elem ? declare? funcref (ref.func )*) offset: ( offset * ) ;; = ( offset ) item: ( item * ) diff --git a/interpreter/binary/decode.ml b/interpreter/binary/decode.ml index c97026215b..61e94212cf 100644 --- a/interpreter/binary/decode.ml +++ b/interpreter/binary/decode.ml @@ -651,6 +651,9 @@ let active_zero s = let offset = const s in Active {index; offset} +let declarative s = + Declarative + let elem_index s = let x = at var s in [Source.(ref_func x @@ x.at)] @@ -676,6 +679,11 @@ let elem s = let etype = elem_kind s in let einit = vec (at elem_index) s in {etype; einit; emode} + | 0x03l -> + let emode = at declarative s in + let etype = elem_kind s in + let einit = vec (at elem_index) s in + {etype; einit; emode} | 0x04l -> let emode = at active_zero s in let einit = vec const s in @@ -690,6 +698,11 @@ let elem s = let etype = ref_type s in let einit = vec const s in {etype; einit; emode} + | 0x07l -> + let emode = at declarative s in + let etype = ref_type s in + let einit = vec const s in + {etype; einit; emode} | _ -> error s (pos s - 1) "invalid elements segment kind" let elem_section s = diff --git a/interpreter/binary/encode.ml b/interpreter/binary/encode.ml index 690697c79f..6910cf4256 100644 --- a/interpreter/binary/encode.ml +++ b/interpreter/binary/encode.ml @@ -524,6 +524,8 @@ let encode m = | Active {index; offset} -> vu32 0x02l; var index; const offset; elem_kind etype; vec elem_index einit + | Declarative -> + vu32 0x03l; elem_kind etype; vec elem_index einit else match emode.it with | Passive -> @@ -532,6 +534,8 @@ let encode m = vu32 0x04l; const offset; vec const einit | Active {index; offset} -> vu32 0x06l; var index; const offset; ref_type etype; vec const einit + | Declarative -> + vu32 0x07l; ref_type etype; vec const einit let elem_section elems = section 9 (vec elem) elems (elems <> []) @@ -546,6 +550,8 @@ let encode m = vu32 0x00l; const offset; string dinit | Active {index; offset} -> vu32 0x02l; var index; const offset; string dinit + | Declarative -> + assert false let data_section datas = section 11 (vec data) datas (datas <> []) diff --git a/interpreter/exec/eval.ml b/interpreter/exec/eval.ml index 8fc0336069..5880285015 100644 --- a/interpreter/exec/eval.ml +++ b/interpreter/exec/eval.ml @@ -573,7 +573,7 @@ let create_export (inst : module_inst) (ex : export) : export_inst = | TableExport x -> ExternTable (table inst x) | MemoryExport x -> ExternMemory (memory inst x) | GlobalExport x -> ExternGlobal (global inst x) - in name, ext + in (name, ext) let create_elem (inst : module_inst) (seg : elem_segment) : elem_inst = let {etype; einit; _} = seg.it in @@ -600,31 +600,34 @@ let init_func (inst : module_inst) (func : func_inst) = | _ -> assert false let run_elem i elem = + let at = elem.it.emode.at in + let x = i @@ at in match elem.it.emode.it with | Passive -> [] | Active {index; offset} -> - let at = elem.it.emode.at in - let x = i @@ at in offset.it @ [ Const (I32 0l @@ at) @@ at; Const (I32 (Lib.List32.length elem.it.einit) @@ at) @@ at; TableInit (index, x) @@ at; ElemDrop x @@ at ] + | Declarative -> + [ElemDrop x @@ at] let run_data i data = + let at = data.it.dmode.at in + let x = i @@ at in match data.it.dmode.it with | Passive -> [] | Active {index; offset} -> assert (index.it = 0l); - let at = data.it.dmode.at in - let x = i @@ at in offset.it @ [ Const (I32 0l @@ at) @@ at; Const (I32 (Int32.of_int (String.length data.it.dinit)) @@ at) @@ at; MemoryInit x @@ at; DataDrop x @@ at ] + | Declarative -> assert false let run_start start = [Call start @@ start.at] diff --git a/interpreter/syntax/ast.ml b/interpreter/syntax/ast.ml index 79181e800b..543469d820 100644 --- a/interpreter/syntax/ast.ml +++ b/interpreter/syntax/ast.ml @@ -151,6 +151,7 @@ type segment_mode = segment_mode' Source.phrase and segment_mode' = | Passive | Active of {index : var; offset : const} + | Declarative type elem_segment = elem_segment' Source.phrase and elem_segment' = diff --git a/interpreter/syntax/free.ml b/interpreter/syntax/free.ml index 39e1474ce5..af322f672d 100644 --- a/interpreter/syntax/free.ml +++ b/interpreter/syntax/free.ml @@ -62,9 +62,9 @@ let list free xs = List.fold_left union empty (List.map free xs) let rec instr (e : instr) = match e.it with | Unreachable | Nop | Drop | Select _ -> empty - | Const _ | Test _ | Compare _ | Unary _ | Binary _ | Convert _ -> empty | RefNull | RefIsNull -> empty | RefFunc x -> funcs (var x) + | Const _ | Test _ | Compare _ | Unary _ | Binary _ | Convert _ -> empty | Block (_, es) | Loop (_, es) -> block es | If (_, es1, es2) -> block es1 ++ block es2 | Br x | BrIf x -> labels (var x) @@ -74,15 +74,15 @@ let rec instr (e : instr) = | CallIndirect (x, y) -> tables (var x) ++ types (var y) | LocalGet x | LocalSet x | LocalTee x -> locals (var x) | GlobalGet x | GlobalSet x -> globals (var x) - | Load _ | Store _ | MemorySize | MemoryGrow | MemoryCopy | MemoryFill -> - memories zero - | MemoryInit x -> memories zero ++ datas (var x) | TableGet x | TableSet x | TableSize x | TableGrow x | TableFill x -> tables (var x) | TableCopy (x, y) -> tables (var x) ++ tables (var y) | TableInit (x, y) -> tables (var x) ++ elems (var y) - | DataDrop x -> datas (var x) | ElemDrop x -> elems (var x) + | Load _ | Store _ | MemorySize | MemoryGrow | MemoryCopy | MemoryFill -> + memories zero + | MemoryInit x -> memories zero ++ datas (var x) + | DataDrop x -> datas (var x) and block (es : instr list) = let free = list instr es in {free with labels = shift free.labels} @@ -96,7 +96,7 @@ let memory (m : memory) = empty let segment_mode f (m : segment_mode) = match m.it with - | Passive -> empty + | Passive | Declarative -> empty | Active {index; offset} -> f (var index) ++ const offset let elem (s : elem_segment) = diff --git a/interpreter/syntax/free.mli b/interpreter/syntax/free.mli index 288a27b679..dc01edc02e 100644 --- a/interpreter/syntax/free.mli +++ b/interpreter/syntax/free.mli @@ -32,3 +32,5 @@ val import : Ast.import -> t val start : Ast.var option -> t val module_ : Ast.module_ -> t + +val list : ('a -> t) -> 'a list -> t diff --git a/interpreter/text/arrange.ml b/interpreter/text/arrange.ml index ce32cc6269..6fc76e9325 100644 --- a/interpreter/text/arrange.ml +++ b/interpreter/text/arrange.ml @@ -334,10 +334,11 @@ let segment_mode category mode = | Active {index; offset} -> (if index.it = 0l then [] else [Node (category, [atom var index])]) @ [const "offset" offset] + | Declarative -> [Atom "declare"] -let elem seg = +let elem i seg = let {etype; einit; emode} = seg.it in - Node ("elem", + Node ("elem $" ^ nat i, segment_mode "table" emode @ if is_elem_kind etype && List.for_all is_elem_index einit then atom elem_kind etype :: list elem_index einit @@ -345,9 +346,9 @@ let elem seg = atom ref_type etype :: list (const "item") einit ) -let data seg = +let data i seg = let {dinit; dmode} = seg.it in - Node ("data", segment_mode "memory" dmode @ break_bytes dinit) + Node ("data $" ^ nat i, segment_mode "memory" dmode @ break_bytes dinit) (* Modules *) @@ -409,8 +410,8 @@ let module_with_var_opt x_opt m = listi (func_with_index !fx) m.it.funcs @ list export m.it.exports @ opt start m.it.start @ - list elem m.it.elems @ - list data m.it.datas + listi elem m.it.elems @ + listi data m.it.datas ) let binary_module_with_var_opt x_opt bs = diff --git a/interpreter/text/lexer.mll b/interpreter/text/lexer.mll index a74a4431e0..3a1c3f1145 100644 --- a/interpreter/text/lexer.mll +++ b/interpreter/text/lexer.mll @@ -348,6 +348,7 @@ rule token = parse | "memory" { MEMORY } | "elem" { ELEM } | "data" { DATA } + | "declare" { DECLARE } | "offset" { OFFSET } | "item" { ITEM } | "import" { IMPORT } diff --git a/interpreter/text/parser.mly b/interpreter/text/parser.mly index 8220539a9f..305765c69d 100644 --- a/interpreter/text/parser.mly +++ b/interpreter/text/parser.mly @@ -176,7 +176,7 @@ let inline_type_explicit (c : context) x ft at = %token CONST UNARY BINARY TEST COMPARE CONVERT %token REF_ANY REF_NULL REF_FUNC REF_HOST REF_IS_NULL %token FUNC START TYPE PARAM RESULT LOCAL GLOBAL -%token TABLE ELEM MEMORY DATA OFFSET ITEM IMPORT EXPORT +%token TABLE ELEM MEMORY DATA DECLARE OFFSET ITEM IMPORT EXPORT %token MODULE BIN QUOTE %token SCRIPT REGISTER INVOKE GET %token ASSERT_MALFORMED ASSERT_INVALID ASSERT_SOFT_INVALID ASSERT_UNLINKABLE @@ -687,6 +687,11 @@ elem : fun () -> { etype = (fst $6); einit = (snd $6) c; emode = Active {index = $4 c table; offset = $5 c} @@ at } @@ at } + | LPAR ELEM bind_var_opt DECLARE elem_list RPAR + { let at = at () in + fun c -> ignore ($3 c anon_elem bind_elem); + fun () -> + { etype = (fst $5); einit = (snd $5) c; emode = Declarative @@ at } @@ at } | LPAR ELEM bind_var_opt offset elem_list RPAR /* Sugar */ { let at = at () in fun c -> ignore ($3 c anon_elem bind_elem); diff --git a/interpreter/util/lib.ml b/interpreter/util/lib.ml index 675890cb5c..c4e0c361e1 100644 --- a/interpreter/util/lib.ml +++ b/interpreter/util/lib.ml @@ -1,5 +1,6 @@ module Fun = struct + let id x = x let curry f x y = f (x, y) let uncurry f (x, y) = f x y diff --git a/interpreter/util/lib.mli b/interpreter/util/lib.mli index a44253e502..1cadd9c9c8 100644 --- a/interpreter/util/lib.mli +++ b/interpreter/util/lib.mli @@ -2,6 +2,7 @@ module Fun : sig + val id : 'a -> 'a val curry : ('a * 'b -> 'c) -> ('a -> 'b -> 'c) val uncurry : ('a -> 'b -> 'c) -> ('a * 'b -> 'c) diff --git a/interpreter/valid/valid.ml b/interpreter/valid/valid.ml index 9edbc1e16e..d7d7f29521 100644 --- a/interpreter/valid/valid.ml +++ b/interpreter/valid/valid.ml @@ -26,12 +26,15 @@ type context = locals : value_type list; results : value_type list; labels : stack_type list; + refs : Free.t; } let empty_context = { types = []; funcs = []; tables = []; memories = []; globals = []; datas = []; elems = []; - locals = []; results = []; labels = [] } + locals = []; results = []; labels = []; + refs = Free.empty + } let lookup category list x = try Lib.List32.nth list x.it with Failure _ -> @@ -47,6 +50,13 @@ let elem (c : context) x = lookup "elem segment" c.elems x let local (c : context) x = lookup "local" c.locals x let label (c : context) x = lookup "label" c.labels x +let refer category (s : Free.Set.t) x = + if not (Free.Set.mem x.it s) then + error x.at + ("undeclared " ^ category ^ " reference " ^ Int32.to_string x.it) + +let refer_func (c : context) x = refer "function" c.refs.Free.funcs x + (* Stack typing *) @@ -334,6 +344,7 @@ let rec check_instr (c : context) (e : instr) (s : infer_stack_type) : op_type = | RefFunc x -> let _ft = func c x in + refer_func c x; [] --> [RefType FuncRefType] | Const v -> @@ -479,6 +490,7 @@ let check_elem_mode (c : context) (t : ref_type) (mode : segment_mode) = require (match_ref_type t et) mode.at "type mismatch in active element segment"; check_const c offset (NumType I32Type) + | Declarative -> () let check_elem (c : context) (seg : elem_segment) = let {etype; einit; emode} = seg.it in @@ -491,6 +503,7 @@ let check_data_mode (c : context) (mode : segment_mode) = | Active {index; offset} -> ignore (memory c index); check_const c offset (NumType I32Type) + | Declarative -> assert false let check_data (c : context) (seg : data_segment) = let {dinit; dmode} = seg.it in @@ -545,7 +558,10 @@ let check_module (m : module_) = in let c0 = List.fold_right check_import imports - {empty_context with types = List.map (fun ty -> ty.it) types} + { empty_context with + refs = Free.list Free.elem elems; + types = List.map (fun ty -> ty.it) types; + } in let c1 = { c0 with diff --git a/test/core/elem.wast b/test/core/elem.wast index b594acd6e3..6661c9a89f 100644 --- a/test/core/elem.wast +++ b/test/core/elem.wast @@ -63,6 +63,17 @@ (elem $a24 (i32.const 0) funcref (ref.func $f) (ref.null)) (elem $a25 (i32.const 0) func $f $f) (elem $a26 (i32.const 0) $f $f) + + ;; Declarative + (elem declare funcref) + (elem declare funcref (ref.func $f) (ref.func $f) (ref.null) (ref.func $g)) + (elem declare func) + (elem declare func $f $f $g $g) + + (elem $d1 declare funcref) + (elem $d2 declare funcref (ref.func $f) (ref.func $f) (ref.null) (ref.func $g)) + (elem $d3 declare func) + (elem $d4 declare func $f $f $g $g) ) (module @@ -71,6 +82,8 @@ (table $t funcref (elem (ref.func $f) (ref.null) (ref.func $g))) ) + + ;; Basic use (module @@ -294,6 +307,28 @@ "out of bounds" ) +;; Implicitly dropped elements + +(module + (table 10 funcref) + (elem $e (i32.const 0) func $f) + (func $f) + (func (export "init") + (table.init $e (i32.const 0) (i32.const 0) (i32.const 1)) + ) +) +(assert_trap (invoke "init") "out of bounds") + +(module + (table 10 funcref) + (elem $e declare func $f) + (func $f) + (func (export "init") + (table.init $e (i32.const 0) (i32.const 0) (i32.const 1)) + ) +) +(assert_trap (invoke "init") "out of bounds") + ;; Element without table (assert_invalid diff --git a/test/core/linking.wast b/test/core/linking.wast index bf6356fbb9..49d55723db 100644 --- a/test/core/linking.wast +++ b/test/core/linking.wast @@ -129,6 +129,7 @@ "incompatible import type" ) + (assert_unlinkable (module (global (import "Mref_ex" "g-var-null") (mut funcref))) "incompatible import type" diff --git a/test/core/ref_func.wast b/test/core/ref_func.wast index 393d3f829f..e9033a3b04 100644 --- a/test/core/ref_func.wast +++ b/test/core/ref_func.wast @@ -5,7 +5,9 @@ (module (func $f (import "M" "f") (param i32) (result i32)) - (func $g (param $x i32) (result i32) (i32.add (local.get $x) (i32.const 1))) + (func $g (param $x i32) (result i32) + (i32.add (local.get $x) (i32.const 1)) + ) (global anyref (ref.func $f)) (global anyref (ref.func $g)) @@ -13,6 +15,16 @@ (global funcref (ref.func $g)) (global $v (mut funcref) (ref.func $f)) + (global funcref (ref.func $gf1)) + (global funcref (ref.func $gf2)) + (func (drop (ref.func $ff1)) (drop (ref.func $ff2))) + (elem declare func $gf1 $ff1) + (elem declare funcref (ref.func $gf2) (ref.func $ff2)) + (func $gf1) + (func $gf2) + (func $ff1) + (func $ff2) + (func (export "is_null-f") (result i32) (ref.is_null (ref.func $f)) ) @@ -27,6 +39,7 @@ (func (export "set-g") (global.set $v (ref.func $g))) (table $t 1 funcref) + (elem declare func $f $g) (func (export "call-f") (param $x i32) (result i32) (table.set $t (i32.const 0) (ref.func $f)) @@ -62,3 +75,12 @@ ) "unknown function 7" ) + +(assert_invalid + (module (func $f) (global funcref (ref.func $f))) + "undeclared function reference" +) +(assert_invalid + (module (func $f (drop (ref.func $f)))) + "undeclared function reference" +) diff --git a/test/core/table_grow.wast b/test/core/table_grow.wast index 158df3cab1..91fc096f45 100644 --- a/test/core/table_grow.wast +++ b/test/core/table_grow.wast @@ -38,6 +38,7 @@ ;; Reject growing to size outside i32 value range (module (table $t 0x10 anyref) + (elem declare func $f) (func $f (export "grow") (result i32) (table.grow $t (ref.func $f) (i32.const 0xffff_fff0)) ) @@ -82,6 +83,7 @@ (func (export "grow") (param i32) (result i32) (table.grow $t (ref.null) (local.get 0)) ) + (elem declare func 1) (func (export "check-table-null") (param i32 i32) (result anyref) (local anyref) (local.set 2 (ref.func 1)) From 2719ec316ca1c31527d8d0a64a258f18e706d84d Mon Sep 17 00:00:00 2001 From: Andreas Rossberg Date: Thu, 16 Jan 2020 17:30:49 +0100 Subject: [PATCH 142/199] [spec] Fix merge artefact --- document/core/appendix/index-instructions.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/document/core/appendix/index-instructions.rst b/document/core/appendix/index-instructions.rst index e94643a94b..f54363c7c2 100644 --- a/document/core/appendix/index-instructions.rst +++ b/document/core/appendix/index-instructions.rst @@ -44,8 +44,8 @@ Instruction Binary Opcode Type :math:`\LOCALTEE~x` :math:`\hex{22}` :math:`[t] \to [t]` :ref:`validation ` :ref:`execution ` :math:`\GLOBALGET~x` :math:`\hex{23}` :math:`[] \to [t]` :ref:`validation ` :ref:`execution ` :math:`\GLOBALSET~x` :math:`\hex{24}` :math:`[t] \to []` :ref:`validation ` :ref:`execution ` -+:math:`\TABLEGET~x` :math:`\hex{25}` :math:`[\I32] \to [t]` :ref:`validation ` :ref:`execution ` -+:math:`\TABLESET~x` :math:`\hex{26}` :math:`[\I32~t] \to []` :ref:`validation ` :ref:`execution ` +:math:`\TABLEGET~x` :math:`\hex{25}` :math:`[\I32] \to [t]` :ref:`validation ` :ref:`execution ` +:math:`\TABLESET~x` :math:`\hex{26}` :math:`[\I32~t] \to []` :ref:`validation ` :ref:`execution ` (reserved) :math:`\hex{27}` :math:`\I32.\LOAD~\memarg` :math:`\hex{28}` :math:`[\I32] \to [\I32]` :ref:`validation ` :ref:`execution ` :math:`\I64.\LOAD~\memarg` :math:`\hex{29}` :math:`[\I32] \to [\I64]` :ref:`validation ` :ref:`execution ` From 11388e787b201266223c28bf6d9cda154583b58a Mon Sep 17 00:00:00 2001 From: Ben Smith Date: Tue, 28 Jan 2020 09:56:15 -0800 Subject: [PATCH 143/199] Add test ensuring data segment index is unsigned (#136) Decoding 64 as an signed LEB will produce the value -64 = 4294967232. This change adds tests to ensure that the segment is decoded as 64. --- test/core/bulk.wast | 40 +++++++++++++++++++++++++++++++ test/core/memory_init.wast | 16 +++++++++++++ test/core/table_init.wast | 24 +++++++++++++++++++ test/meta/generate_memory_init.js | 19 +++++++++++++++ test/meta/generate_table_init.js | 27 +++++++++++++++++++++ 5 files changed, 126 insertions(+) diff --git a/test/core/bulk.wast b/test/core/bulk.wast index fe71939d3b..e30cca4229 100644 --- a/test/core/bulk.wast +++ b/test/core/bulk.wast @@ -176,6 +176,22 @@ (assert_trap (invoke "init_active" (i32.const 1)) "out of bounds") (invoke "init_active" (i32.const 0)) +;; Test that the data segment index is properly encoded as an unsigned (not +;; signed) LEB. +(module + (memory 1) + ;; 65 data segments. 64 is the smallest positive number that is encoded + ;; differently as a signed LEB. + (data "") (data "") (data "") (data "") (data "") (data "") (data "") (data "") + (data "") (data "") (data "") (data "") (data "") (data "") (data "") (data "") + (data "") (data "") (data "") (data "") (data "") (data "") (data "") (data "") + (data "") (data "") (data "") (data "") (data "") (data "") (data "") (data "") + (data "") (data "") (data "") (data "") (data "") (data "") (data "") (data "") + (data "") (data "") (data "") (data "") (data "") (data "") (data "") (data "") + (data "") (data "") (data "") (data "") (data "") (data "") (data "") (data "") + (data "") (data "") (data "") (data "") (data "") (data "") (data "") (data "") + (data "") + (func (data.drop 64))) ;; table.init (module @@ -251,6 +267,30 @@ (assert_trap (invoke "init_active" (i32.const 1)) "out of bounds") (invoke "init_active" (i32.const 0)) +;; Test that the elem segment index is properly encoded as an unsigned (not +;; signed) LEB. +(module + (table 1 funcref) + ;; 65 elem segments. 64 is the smallest positive number that is encoded + ;; differently as a signed LEB. + (elem funcref) (elem funcref) (elem funcref) (elem funcref) + (elem funcref) (elem funcref) (elem funcref) (elem funcref) + (elem funcref) (elem funcref) (elem funcref) (elem funcref) + (elem funcref) (elem funcref) (elem funcref) (elem funcref) + (elem funcref) (elem funcref) (elem funcref) (elem funcref) + (elem funcref) (elem funcref) (elem funcref) (elem funcref) + (elem funcref) (elem funcref) (elem funcref) (elem funcref) + (elem funcref) (elem funcref) (elem funcref) (elem funcref) + (elem funcref) (elem funcref) (elem funcref) (elem funcref) + (elem funcref) (elem funcref) (elem funcref) (elem funcref) + (elem funcref) (elem funcref) (elem funcref) (elem funcref) + (elem funcref) (elem funcref) (elem funcref) (elem funcref) + (elem funcref) (elem funcref) (elem funcref) (elem funcref) + (elem funcref) (elem funcref) (elem funcref) (elem funcref) + (elem funcref) (elem funcref) (elem funcref) (elem funcref) + (elem funcref) (elem funcref) (elem funcref) (elem funcref) + (elem funcref) + (func (elem.drop 64))) ;; table.copy (module diff --git a/test/core/memory_init.wast b/test/core/memory_init.wast index c647079d91..bd9418c86f 100644 --- a/test/core/memory_init.wast +++ b/test/core/memory_init.wast @@ -949,3 +949,19 @@ (assert_return (invoke "checkRange" (i32.const 0) (i32.const 1) (i32.const 0)) (i32.const -1)) + +(module + (memory 1) + ;; 65 data segments. 64 is the smallest positive number that is encoded + ;; differently as a signed LEB. + (data "") (data "") (data "") (data "") (data "") (data "") (data "") (data "") + (data "") (data "") (data "") (data "") (data "") (data "") (data "") (data "") + (data "") (data "") (data "") (data "") (data "") (data "") (data "") (data "") + (data "") (data "") (data "") (data "") (data "") (data "") (data "") (data "") + (data "") (data "") (data "") (data "") (data "") (data "") (data "") (data "") + (data "") (data "") (data "") (data "") (data "") (data "") (data "") (data "") + (data "") (data "") (data "") (data "") (data "") (data "") (data "") (data "") + (data "") (data "") (data "") (data "") (data "") (data "") (data "") (data "") + (data "") + (func (memory.init 64 (i32.const 0) (i32.const 0) (i32.const 0)))) + diff --git a/test/core/table_init.wast b/test/core/table_init.wast index 80eaf065d8..e67e2b1bc3 100644 --- a/test/core/table_init.wast +++ b/test/core/table_init.wast @@ -1750,3 +1750,27 @@ (assert_trap (invoke "test" (i32.const 13)) "uninitialized element") (assert_trap (invoke "test" (i32.const 14)) "uninitialized element") (assert_trap (invoke "test" (i32.const 15)) "uninitialized element") + +(module + (table 1 funcref) + ;; 65 elem segments. 64 is the smallest positive number that is encoded + ;; differently as a signed LEB. + (elem funcref) (elem funcref) (elem funcref) (elem funcref) + (elem funcref) (elem funcref) (elem funcref) (elem funcref) + (elem funcref) (elem funcref) (elem funcref) (elem funcref) + (elem funcref) (elem funcref) (elem funcref) (elem funcref) + (elem funcref) (elem funcref) (elem funcref) (elem funcref) + (elem funcref) (elem funcref) (elem funcref) (elem funcref) + (elem funcref) (elem funcref) (elem funcref) (elem funcref) + (elem funcref) (elem funcref) (elem funcref) (elem funcref) + (elem funcref) (elem funcref) (elem funcref) (elem funcref) + (elem funcref) (elem funcref) (elem funcref) (elem funcref) + (elem funcref) (elem funcref) (elem funcref) (elem funcref) + (elem funcref) (elem funcref) (elem funcref) (elem funcref) + (elem funcref) (elem funcref) (elem funcref) (elem funcref) + (elem funcref) (elem funcref) (elem funcref) (elem funcref) + (elem funcref) (elem funcref) (elem funcref) (elem funcref) + (elem funcref) (elem funcref) (elem funcref) (elem funcref) + (elem funcref) + (func (table.init 64 (i32.const 0) (i32.const 0) (i32.const 0)))) + diff --git a/test/meta/generate_memory_init.js b/test/meta/generate_memory_init.js index 0b5d7f6505..64fb07f95d 100644 --- a/test/meta/generate_memory_init.js +++ b/test/meta/generate_memory_init.js @@ -292,3 +292,22 @@ mem_init(1, "", "", Math.floor(mem_init_len/2), 0xFFFFFF00); // We arithmetically overflow the segment limit but not the memory limit mem_init(1, "", "", PAGESIZE, 0xFFFFFFFC); +// Test that the data segment index is properly encoded as an unsigned (not +// signed) LEB. +print( +` +(module + (memory 1) + ;; 65 data segments. 64 is the smallest positive number that is encoded + ;; differently as a signed LEB. + (data "") (data "") (data "") (data "") (data "") (data "") (data "") (data "") + (data "") (data "") (data "") (data "") (data "") (data "") (data "") (data "") + (data "") (data "") (data "") (data "") (data "") (data "") (data "") (data "") + (data "") (data "") (data "") (data "") (data "") (data "") (data "") (data "") + (data "") (data "") (data "") (data "") (data "") (data "") (data "") (data "") + (data "") (data "") (data "") (data "") (data "") (data "") (data "") (data "") + (data "") (data "") (data "") (data "") (data "") (data "") (data "") (data "") + (data "") (data "") (data "") (data "") (data "") (data "") (data "") (data "") + (data "") + (func (memory.init 64 (i32.const 0) (i32.const 0) (i32.const 0)))) +`) diff --git a/test/meta/generate_table_init.js b/test/meta/generate_table_init.js index 9329d937d7..e34a7e1e54 100644 --- a/test/meta/generate_table_init.js +++ b/test/meta/generate_table_init.js @@ -336,3 +336,30 @@ tbl_init(tbl_init_len*4, tbl_init_len*4, tbl_init_len, 0xFFFFFFF0); // We arithmetically overflow the segment limit but not the table limit tbl_init(tbl_init_len, tbl_init_len, tbl_init_len, 0xFFFFFFFC, Math.floor(tbl_init_len/2)); +// Test that the elem segment index is properly encoded as an unsigned (not +// signed) LEB. +print( +` +(module + (table 1 funcref) + ;; 65 elem segments. 64 is the smallest positive number that is encoded + ;; differently as a signed LEB. + (elem funcref) (elem funcref) (elem funcref) (elem funcref) + (elem funcref) (elem funcref) (elem funcref) (elem funcref) + (elem funcref) (elem funcref) (elem funcref) (elem funcref) + (elem funcref) (elem funcref) (elem funcref) (elem funcref) + (elem funcref) (elem funcref) (elem funcref) (elem funcref) + (elem funcref) (elem funcref) (elem funcref) (elem funcref) + (elem funcref) (elem funcref) (elem funcref) (elem funcref) + (elem funcref) (elem funcref) (elem funcref) (elem funcref) + (elem funcref) (elem funcref) (elem funcref) (elem funcref) + (elem funcref) (elem funcref) (elem funcref) (elem funcref) + (elem funcref) (elem funcref) (elem funcref) (elem funcref) + (elem funcref) (elem funcref) (elem funcref) (elem funcref) + (elem funcref) (elem funcref) (elem funcref) (elem funcref) + (elem funcref) (elem funcref) (elem funcref) (elem funcref) + (elem funcref) (elem funcref) (elem funcref) (elem funcref) + (elem funcref) (elem funcref) (elem funcref) (elem funcref) + (elem funcref) + (func (table.init 64 (i32.const 0) (i32.const 0) (i32.const 0)))) +`) From 22ce5e36584e0116795244e928402dc0b5fd6f65 Mon Sep 17 00:00:00 2001 From: Andreas Rossberg Date: Mon, 3 Feb 2020 20:11:57 +0100 Subject: [PATCH 144/199] [interpreter] Fix ref asserts (#78) --- interpreter/script/js.ml | 35 +++++++++++++++-------------------- test/core/select.wast | 4 ++-- 2 files changed, 17 insertions(+), 22 deletions(-) diff --git a/interpreter/script/js.ml b/interpreter/script/js.ml index 461c94dfe7..f0eeb11441 100644 --- a/interpreter/script/js.ml +++ b/interpreter/script/js.ml @@ -146,11 +146,20 @@ function assert_return(action, expected) { switch (expected) { case "nan:canonical": case "nan:arithmetic": - case "nan:any": // Note that JS can't reliably distinguish different NaN values, // so there's no good way to test that it's a canonical NaN. if (!Number.isNaN(actual)) { - throw new Error("Wasm return value NaN expected, got " + actual); + throw new Error("Wasm NaN return value expected, got " + actual); + }; + return; + case "ref.func": + if (typeof actual !== "function") { + throw new Error("Wasm function return value expected, got " + actual); + }; + return; + case "ref.any": + if (actual === null) { + throw new Error("Wasm reference return value expected, got " + actual); }; return; default: @@ -159,20 +168,6 @@ function assert_return(action, expected) { }; } } - -function assert_return_ref(action) { - let actual = action(); - if (actual === null || typeof actual !== "object" && typeof actual !== "function") { - throw new Error("Wasm reference return value expected, got " + actual); - }; -} - -function assert_return_func(action) { - let actual = action(); - if (typeof actual !== "function") { - throw new Error("Wasm function return value expected, got " + actual); - }; -} |} @@ -417,8 +412,8 @@ let of_value v = | _ -> assert false let of_nan = function - | CanonicalNan -> "nan:canonical" - | ArithmeticNan -> "nan:arithmetic" + | CanonicalNan -> "\"nan:canonical\"" + | ArithmeticNan -> "\"nan:arithmetic\"" let of_result res = match res.it with @@ -428,8 +423,8 @@ let of_result res = | Values.I32 _ | Values.I64 _ -> assert false | Values.F32 n | Values.F64 n -> of_nan n ) - | RefResult -> "ref.any" - | FuncResult -> "ref.func" + | RefResult -> "\"ref.any\"" + | FuncResult -> "\"ref.func\"" let rec of_definition def = match def.it with diff --git a/test/core/select.wast b/test/core/select.wast index 7d02a44da2..267dd57389 100644 --- a/test/core/select.wast +++ b/test/core/select.wast @@ -40,10 +40,10 @@ ) (func (export "join-nullref") (param i32) (result anyref) - (select (result anyref) (ref.null) (ref.null) (local.get 0)) + (select (result nullref) (ref.null) (ref.null) (local.get 0)) ) (func (export "join-funcref") (param i32) (result anyref) - (select (result anyref) + (select (result funcref) (table.get $tab (i32.const 0)) (ref.null) (local.get 0) From fc990e3a9a732bbe1839b23dd92f36fb1636913a Mon Sep 17 00:00:00 2001 From: Andreas Rossberg Date: Mon, 3 Feb 2020 20:13:21 +0100 Subject: [PATCH 145/199] [spec] Fix validation context for globals (#77) --- document/core/valid/modules.rst | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/document/core/valid/modules.rst b/document/core/valid/modules.rst index 4337cf867d..48e4a9caa8 100644 --- a/document/core/valid/modules.rst +++ b/document/core/valid/modules.rst @@ -543,7 +543,15 @@ Instead, the context :math:`C` for validation of the module's content is constru * :math:`C.\CREFS` is the set :math:`\freefuncidx(\module.\MELEMS)`, i.e., the set of :ref:`function indices ` occurring in any of the module's :ref:`element segments `. -* Let :math:`C'` be the :ref:`context ` where :math:`C'.\CGLOBALS` is the sequence :math:`\etglobals(\X{it}^\ast)` and all other fields are empty. +* Let :math:`C'` be the :ref:`context ` where: + + * :math:`C'.\CGLOBALS` is the sequence :math:`\etglobals(\X{it}^\ast)`, + + * :math:`C'.\CFUNCS` is the same as :math:`C.\CFUNCS`, + + * :math:`C'.\CREFS` is the same as :math:`C.\CREFS`, + + * all other fields are empty. * Under the context :math:`C`: @@ -630,7 +638,7 @@ Instead, the context :math:`C` for validation of the module's content is constru \\ C = \{ \CTYPES~\functype^\ast, \CFUNCS~\X{ift}^\ast~\X{ft}^\ast, \CTABLES~\X{itt}^\ast~\X{tt}^\ast, \CMEMS~\X{imt}^\ast~\X{mt}^\ast, \CGLOBALS~\X{igt}^\ast~\X{gt}^\ast, \CELEMS~{\ok}^{N_e}, \CDATAS~{\ok}^{N_d}, \CREFS~\freefuncidx(\elem^{N_e}) \} \\ - C' = \{ \CGLOBALS~\X{igt}^\ast \} + C' = \{ \CGLOBALS~\X{igt}^\ast, \CFUNCS~(C.\CFUNCS), \CREFS~(C.\CREFS) \} \qquad |C.\CMEMS| \leq 1 \qquad @@ -661,7 +669,7 @@ Instead, the context :math:`C` for validation of the module's content is constru All types needed to construct :math:`C` can easily be determined from a simple pre-pass over the module that does not perform any actual validation. Globals, however, are not recursive. - The effect of defining the limited context :math:`C'` for validating the module's globals is that their initialization expressions can only access imported globals and nothing else. + The effect of defining the limited context :math:`C'` for validating the module's globals is that their initialization expressions can only access functions and imported globals and nothing else. .. note:: The restriction on the number of memories may be lifted in future versions of WebAssembly. From 404b7e7b4276ab3b772a03a1786d5277d6e24836 Mon Sep 17 00:00:00 2001 From: Nick Fitzgerald Date: Thu, 6 Feb 2020 21:59:12 +0100 Subject: [PATCH 146/199] [interpreter/test] Fix validation for `elem.drop` (#137) --- interpreter/valid/valid.ml | 2 -- test/core/memory_init.wast | 2 +- test/core/table_init.wast | 4 ++-- 3 files changed, 3 insertions(+), 5 deletions(-) diff --git a/interpreter/valid/valid.ml b/interpreter/valid/valid.ml index 76e0d7153a..112d10ddf0 100644 --- a/interpreter/valid/valid.ml +++ b/interpreter/valid/valid.ml @@ -261,7 +261,6 @@ let rec check_instr (c : context) (e : instr) (s : infer_stack_type) : op_type = [I32Type; I32Type; I32Type] --> [] | ElemDrop x -> - ignore (table c (0l @@ e.at)); ignore (elem c x); [] --> [] @@ -295,7 +294,6 @@ let rec check_instr (c : context) (e : instr) (s : infer_stack_type) : op_type = [I32Type; I32Type; I32Type] --> [] | DataDrop x -> - ignore (memory c (0l @@ e.at)); ignore (data c x); [] --> [] diff --git a/test/core/memory_init.wast b/test/core/memory_init.wast index bd9418c86f..60b60578cf 100644 --- a/test/core/memory_init.wast +++ b/test/core/memory_init.wast @@ -189,7 +189,7 @@ (module (func (export "test") (data.drop 0))) - "unknown memory 0") + "unknown data segment") (assert_invalid (module diff --git a/test/core/table_init.wast b/test/core/table_init.wast index e67e2b1bc3..90f86ac17e 100644 --- a/test/core/table_init.wast +++ b/test/core/table_init.wast @@ -193,7 +193,7 @@ (module (func (export "test") (elem.drop 0))) - "unknown table 0") + "unknown elem segment 0") (assert_invalid (module @@ -207,7 +207,7 @@ (func (result i32) (i32.const 0)) (func (export "test") (elem.drop 4))) - "unknown table 0") + "unknown elem segment 4") (assert_invalid (module From d2589027633afe11a5428d3ab05cff6857ec2adc Mon Sep 17 00:00:00 2001 From: Andreas Rossberg Date: Thu, 13 Feb 2020 18:28:47 +0100 Subject: [PATCH 147/199] [spec/interpreter] Fix missing multi table bulk cases (#80) --- document/core/appendix/index-rules.rst | 4 +- document/core/binary/instructions.rst | 4 +- document/core/valid/conventions.rst | 4 +- document/core/valid/instructions.rst | 52 ++++++++++++++++++-------- document/core/valid/modules.rst | 48 ++++++++++++------------ interpreter/valid/valid.ml | 24 +++++++----- test/core/table-sub.wast | 31 +++++++++++++++ 7 files changed, 113 insertions(+), 54 deletions(-) create mode 100644 test/core/table-sub.wast diff --git a/document/core/appendix/index-rules.rst b/document/core/appendix/index-rules.rst index 4d3db62f16..525fe1397a 100644 --- a/document/core/appendix/index-rules.rst +++ b/document/core/appendix/index-rules.rst @@ -26,8 +26,8 @@ Construct Judgement :ref:`Table ` :math:`C \vdashtable \table : \tabletype` :ref:`Memory ` :math:`C \vdashmem \mem : \memtype` :ref:`Global ` :math:`C \vdashglobal \global : \globaltype` -:ref:`Element segment ` :math:`C \vdashelem \elem \ok` -:ref:`Element mode ` :math:`C \vdashelemmode \elemmode \ok` +:ref:`Element segment ` :math:`C \vdashelem \elem : \reftype` +:ref:`Element mode ` :math:`C \vdashelemmode \elemmode : \reftype` :ref:`Data segment ` :math:`C \vdashdata \data \ok` :ref:`Data mode ` :math:`C \vdashdatamode \datamode \ok` :ref:`Start function ` :math:`C \vdashstart \start \ok` diff --git a/document/core/binary/instructions.rst b/document/core/binary/instructions.rst index 84b6296bae..ed3e506dc2 100644 --- a/document/core/binary/instructions.rst +++ b/document/core/binary/instructions.rst @@ -157,9 +157,9 @@ Table Instructions \hex{FC}~\hex{0F}~~x{:}\Btableidx &\Rightarrow& \TABLEGROW~x \\ &&|& \hex{FC}~\hex{10}~~x{:}\Btableidx &\Rightarrow& \TABLESIZE~x \\ &&|& \hex{FC}~\hex{11}~~x{:}\Btableidx &\Rightarrow& \TABLEFILL~x \\ - \hex{FC}~\hex{0C}~~\hex{00}~x{:}\Belemidx &\Rightarrow& \TABLEINIT~x \\ &&|& + \hex{FC}~\hex{0C}~~x{:}\Btableidx~~y{:}\Belemidx &\Rightarrow& \TABLEINIT~x~y \\ &&|& \hex{FC}~\hex{0D}~~x{:}\Belemidx &\Rightarrow& \ELEMDROP~x \\ &&|& - \hex{FC}~\hex{0E}~~\hex{00}~~\hex{00} &\Rightarrow& \TABLECOPY \\ + \hex{FC}~\hex{0E}~~x{:}\Btableidx~~y{:}\Btableidx &\Rightarrow& \TABLECOPY~x~y \\ \end{array} diff --git a/document/core/valid/conventions.rst b/document/core/valid/conventions.rst index 9c0a4046bd..727d9ecb71 100644 --- a/document/core/valid/conventions.rst +++ b/document/core/valid/conventions.rst @@ -38,7 +38,7 @@ which collects relevant information about the surrounding :ref:`module ` :math: & \CTABLES & \tabletype^\ast, \\ & \CMEMS & \memtype^\ast, \\ & \CGLOBALS & \globaltype^\ast, \\ - & \CELEMS & {\ok}^\ast, \\ + & \CELEMS & \reftype^\ast, \\ & \CDATAS & {\ok}^\ast, \\ & \CLOCALS & \valtype^\ast, \\ & \CLABELS & \resulttype^\ast, \\ diff --git a/document/core/valid/instructions.rst b/document/core/valid/instructions.rst index 843a736acc..e55a08031a 100644 --- a/document/core/valid/instructions.rst +++ b/document/core/valid/instructions.rst @@ -431,7 +431,7 @@ Table Instructions .. math:: \frac{ - C.\CTABLES[x] = t + C.\CTABLES[x] = \tabletype }{ C \vdashinstr \TABLESIZE~x : [] \to [\I32] } @@ -450,7 +450,7 @@ Table Instructions .. math:: \frac{ - C.\CTABLES[x] = t + C.\CTABLES[x] = \limits~t }{ C \vdashinstr \TABLEGROW~x : [t~\I32] \to [\I32] } @@ -469,7 +469,7 @@ Table Instructions .. math:: \frac{ - C.\CTABLES[x] = t + C.\CTABLES[x] = \limits~t }{ C \vdashinstr \TABLEFILL~x : [\I32~t~\I32] \to [] } @@ -477,39 +477,59 @@ Table Instructions .. _valid-table.copy: -:math:`\TABLECOPY` -..................... +:math:`\TABLECOPY~x~y` +...................... + +* The table :math:`C.\CTABLES[x]` must be defined in the context. + +* Let :math:`\limits_1~t_1` be the :ref:`table type ` :math:`C.\CTABLES[x]`. + +* The table :math:`C.\CTABLES[y]` must be defined in the context. -* The table :math:`C.\CTABLES[0]` must be defined in the context. +* Let :math:`\limits_2~t_2` be the :ref:`table type ` :math:`C.\CTABLES[y]`. + +* The :ref:`reference type ` :math:`t_2` must :ref:`match ` :math:`t_1`. * Then the instruction is valid with type :math:`[\I32~\I32~\I32] \to []`. .. math:: \frac{ - C.\CTABLES[0] = \tabletype + C.\CTABLES[x] = \limits_1~t_1 + \qquad + C.\CTABLES[x] = \limits_2~t_2 + \qquad + \vdashreftypematch t_2 \matchesvaltype t_1 }{ - C \vdashinstr \TABLECOPY : [\I32~\I32~\I32] \to [] + C \vdashinstr \TABLECOPY~x~y : [\I32~\I32~\I32] \to [] } .. _valid-table.init: -:math:`\TABLEINIT~x` -..................... +:math:`\TABLEINIT~x~y` +...................... -* The table :math:`C.\CTABLES[0]` must be defined in the context. +* The table :math:`C.\CTABLES[x]` must be defined in the context. -* The element segment :math:`C.\CELEMS[x]` must be defined in the context. +* Let :math:`\limits~t_1` be the :ref:`table type ` :math:`C.\CTABLES[x]`. + +* The element segment :math:`C.\CELEMS[y]` must be defined in the context. + +* Let :math:`t_2` be the :ref:`reference type ` :math:`C.\CELEMS[y]`. + +* The :ref:`reference type ` :math:`t_2` must :ref:`match ` :math:`t_1`. * Then the instruction is valid with type :math:`[\I32~\I32~\I32] \to []`. .. math:: \frac{ - C.\CTABLES[0] = \tabletype + C.\CTABLES[x] = \limits_1~t_1 + \qquad + C.\CELEMS[y] = t_2 \qquad - C.\CELEMS[x] = {\ok} + \vdashreftypematch t_2 \matchesvaltype t_1 }{ - C \vdashinstr \TABLEINIT~x : [\I32~\I32~\I32] \to [] + C \vdashinstr \TABLEINIT~x~y : [\I32~\I32~\I32] \to [] } @@ -524,7 +544,7 @@ Table Instructions .. math:: \frac{ - C.\CELEMS[x] = {\ok} + C.\CELEMS[x] = t }{ C \vdashinstr \ELEMDROP~x : [] \to [] } diff --git a/document/core/valid/modules.rst b/document/core/valid/modules.rst index 48e4a9caa8..fc2f9be133 100644 --- a/document/core/valid/modules.rst +++ b/document/core/valid/modules.rst @@ -145,10 +145,10 @@ Globals :math:`\global` are classified by :ref:`global types Element Segments ~~~~~~~~~~~~~~~~ -Element segments :math:`\elem` are not classified by any type but merely checked for well-formedness. +Element segments :math:`\elem` are classified by the :ref:`reference type ` of their elements. -:math:`\{ \ETYPE~et, \EINIT~e^\ast, \EMODE~\elemmode \}` -........................................................ +:math:`\{ \ETYPE~t, \EINIT~e^\ast, \EMODE~\elemmode \}` +....................................................... * For each :math:`e_i` in :math:`e^\ast`, @@ -156,9 +156,11 @@ Element segments :math:`\elem` are not classified by any type but merely checked * The expression :math:`e_i` must be :ref:`constant `. -* The element mode :math:`\elemmode` must be valid for :ref:`reference type ` :math:`\X{et}`. +* The element mode :math:`\elemmode` must be valid with :ref:`reference type ` :math:`t'`. -* Then the element segment is valid. +* The :ref:`reference type ` :math:`t` must :ref:`match ` the reference type :math:`t'`. + +* Then the element segment is valid with :ref:`reference type ` :math:`t`. .. math:: @@ -167,9 +169,11 @@ Element segments :math:`\elem` are not classified by any type but merely checked \qquad (C \vdashexprconst e \const)^\ast \qquad - C; \X{et} \vdashelemmode \elemmode \ok + C \vdashelemmode \elemmode : t' + \qquad + \vdashreftypematch t \matchesvaltype t' }{ - C \vdashelem \{ \ETYPE~et, \EINIT~e^\ast, \EMODE~\elemmode \} \ok + C \vdashelem \{ \ETYPE~t, \EINIT~e^\ast, \EMODE~\elemmode \} : t } @@ -178,12 +182,12 @@ Element segments :math:`\elem` are not classified by any type but merely checked :math:`\EPASSIVE` ................. -* The element mode is valid for any :ref:`reference type ` :math:`\X{et}`. +* The element mode is valid with any :ref:`reference type `. .. math:: \frac{ }{ - C; \X{et} \vdashelemmode \EPASSIVE \ok + C \vdashelemmode \EPASSIVE : \reftype } @@ -194,38 +198,34 @@ Element segments :math:`\elem` are not classified by any type but merely checked * Let :math:`\limits~t` be the :ref:`table type ` :math:`C.\CTABLES[x]`. -* The :ref:`reference type ` :math:`\X{et}` must :ref:`match ` the reference type :math:`t`. - * The expression :math:`\expr` must be :ref:`valid ` with :ref:`result type ` :math:`[\I32]`. * The expression :math:`\expr` must be :ref:`constant `. -* Then the element mode is valid for :ref:`reference type ` :math:`\X{et}`. +* Then the element mode is valid with :ref:`reference type ` :math:`t`. .. math:: \frac{ \begin{array}{@{}c@{}} C.\CTABLES[x] = \limits~t - \qquad - \vdashreftypematch \X{et} \matchesvaltype t \\ C \vdashexpr \expr : [\I32] \qquad C \vdashexprconst \expr \const \end{array} }{ - C; \X{et} \vdashelemmode \EACTIVE~\{ \ETABLE~x, \EOFFSET~\expr \} \ok + C \vdashelemmode \EACTIVE~\{ \ETABLE~x, \EOFFSET~\expr \} : t } :math:`\EDECLARATIVE` ..................... -* The element mode is valid for any :ref:`reference type ` :math:`\X{et}`. +* The element mode is valid with any :ref:`reference type `. .. math:: \frac{ }{ - C; \X{et} \vdashelemmode \EDECLARATIVE \ok + C \vdashelemmode \EDECLARATIVE : \reftype } @@ -290,7 +290,7 @@ Data segments :math:`\data` are not classified by any type but merely checked fo \qquad C \vdashexprconst \expr \const }{ - C \vdashelemmode \DACTIVE~\{ \DMEM~x, \DOFFSET~\expr \} \ok + C \vdashdatamode \DACTIVE~\{ \DMEM~x, \DOFFSET~\expr \} \ok } @@ -531,7 +531,7 @@ Instead, the context :math:`C` for validation of the module's content is constru * :math:`C.\CGLOBALS` is :math:`\etglobals(\X{it}^\ast)` concatenated with :math:`\X{gt}^\ast`, with the import's :ref:`external types ` :math:`\X{it}^\ast` and the internal :ref:`global types ` :math:`\X{gt}^\ast` as determined below, - * :math:`C.\CELEMS` is :math:`{\ok}^{N_e}`, where :math:`N_e` is the length of the vector :math:`\module.\MELEMS`, + * :math:`C.\CELEMS` is :math:`{\X{rt}}^\ast` as determined below, * :math:`C.\CDATAS` is :math:`{\ok}^{N_d}`, where :math:`N_d` is the length of the vector :math:`\module.\MDATAS`, @@ -573,7 +573,7 @@ Instead, the context :math:`C` for validation of the module's content is constru the definition :math:`\global_i` must be :ref:`valid ` with a :ref:`global type ` :math:`\X{gt}_i`. * For each :math:`\elem_i` in :math:`\module.\MELEMS`, - the segment :math:`\elem_i` must be :ref:`valid `. + the segment :math:`\elem_i` must be :ref:`valid ` with :ref:`reference type ` :math:`\X{rt}_i`. * For each :math:`\data_i` in :math:`\module.\MDATAS`, the segment :math:`\data_i` must be :ref:`valid `. @@ -599,6 +599,8 @@ Instead, the context :math:`C` for validation of the module's content is constru * Let :math:`\X{gt}^\ast` be the concatenation of the internal :ref:`global types ` :math:`\X{gt}_i`, in index order. +* Let :math:`\X{rt}^\ast` be the concatenation of the :ref:`referense types ` :math:`\X{rt}_i`, in index order. + * Let :math:`\X{it}^\ast` be the concatenation of :ref:`external types ` :math:`\X{it}_i` of the imports, in index order. * Let :math:`\X{et}^\ast` be the concatenation of :ref:`external types ` :math:`\X{et}_i` of the exports, in index order. @@ -618,7 +620,7 @@ Instead, the context :math:`C` for validation of the module's content is constru \quad (C' \vdashglobal \global : \X{gt})^\ast \\ - (C \vdashelem \elem \ok)^{N_e} + (C \vdashelem \elem : \X{rt})^\ast \quad (C \vdashdata \data \ok)^{N_d} \quad @@ -636,7 +638,7 @@ Instead, the context :math:`C` for validation of the module's content is constru \qquad \X{igt}^\ast = \etglobals(\X{it}^\ast) \\ - C = \{ \CTYPES~\functype^\ast, \CFUNCS~\X{ift}^\ast~\X{ft}^\ast, \CTABLES~\X{itt}^\ast~\X{tt}^\ast, \CMEMS~\X{imt}^\ast~\X{mt}^\ast, \CGLOBALS~\X{igt}^\ast~\X{gt}^\ast, \CELEMS~{\ok}^{N_e}, \CDATAS~{\ok}^{N_d}, \CREFS~\freefuncidx(\elem^{N_e}) \} + C = \{ \CTYPES~\functype^\ast, \CFUNCS~\X{ift}^\ast~\X{ft}^\ast, \CTABLES~\X{itt}^\ast~\X{tt}^\ast, \CMEMS~\X{imt}^\ast~\X{mt}^\ast, \CGLOBALS~\X{igt}^\ast~\X{gt}^\ast, \CELEMS~\X{rt}^\ast, \CDATAS~{\ok}^{N_d}, \CREFS~\freefuncidx(\elem^\ast) \} \\ C' = \{ \CGLOBALS~\X{igt}^\ast, \CFUNCS~(C.\CFUNCS), \CREFS~(C.\CREFS) \} \qquad @@ -652,7 +654,7 @@ Instead, the context :math:`C` for validation of the module's content is constru \MTABLES~\table^\ast, \MMEMS~\mem^\ast, \MGLOBALS~\global^\ast, \\ - \MELEMS~\elem^{N_e}, + \MELEMS~\elem^\ast, \MDATAS~\data^{N_d}, \MSTART~\start^?, \MIMPORTS~\import^\ast, diff --git a/interpreter/valid/valid.ml b/interpreter/valid/valid.ml index d7d7f29521..9752bd928d 100644 --- a/interpreter/valid/valid.ml +++ b/interpreter/valid/valid.ml @@ -21,8 +21,8 @@ type context = tables : table_type list; memories : memory_type list; globals : global_type list; + elems : ref_type list; datas : unit list; - elems : unit list; locals : value_type list; results : value_type list; labels : stack_type list; @@ -31,7 +31,7 @@ type context = let empty_context = { types = []; funcs = []; tables = []; memories = []; - globals = []; datas = []; elems = []; + globals = []; elems = []; datas = []; locals = []; results = []; labels = []; refs = Free.empty } @@ -45,8 +45,8 @@ let func (c : context) x = lookup "function" c.funcs x let table (c : context) x = lookup "table" c.tables x let memory (c : context) x = lookup "memory" c.memories x let global (c : context) x = lookup "global" c.globals x -let data (c : context) x = lookup "data segment" c.datas x let elem (c : context) x = lookup "elem segment" c.elems x +let data (c : context) x = lookup "data segment" c.datas x let local (c : context) x = lookup "local" c.locals x let label (c : context) x = lookup "label" c.labels x @@ -288,13 +288,19 @@ let rec check_instr (c : context) (e : instr) (s : infer_stack_type) : op_type = [NumType I32Type; RefType t; NumType I32Type] --> [] | TableCopy (x, y) -> - ignore (table c x); - ignore (table c y); + let TableType (_lim1, t1) = table c x in + let TableType (_lim2, t2) = table c y in + require (match_ref_type t2 t1) x.at + ("type mismatch: source element type " ^ string_of_ref_type t1 ^ + " does not match destination element type " ^ string_of_ref_type t2); [NumType I32Type; NumType I32Type; NumType I32Type] --> [] | TableInit (x, y) -> - ignore (table c x); - ignore (elem c y); + let TableType (_lim1, t1) = table c x in + let t2 = elem c y in + require (match_ref_type t2 t1) x.at + ("type mismatch: source element type " ^ string_of_ref_type t1 ^ + " does not match destination element type " ^ string_of_ref_type t2); [NumType I32Type; NumType I32Type; NumType I32Type] --> [] | ElemDrop x -> @@ -568,8 +574,8 @@ let check_module (m : module_) = funcs = c0.funcs @ List.map (fun f -> type_ c0 f.it.ftype) funcs; tables = c0.tables @ List.map (fun tab -> tab.it.ttype) tables; memories = c0.memories @ List.map (fun mem -> mem.it.mtype) memories; - elems = List.map (fun _ -> ()) elems; - datas = List.map (fun _ -> ()) datas; + elems = List.map (fun elem -> elem.it.etype) elems; + datas = List.map (fun _data -> ()) datas; } in let c = diff --git a/test/core/table-sub.wast b/test/core/table-sub.wast new file mode 100644 index 0000000000..66f183108b --- /dev/null +++ b/test/core/table-sub.wast @@ -0,0 +1,31 @@ +(module + (table $t1 10 anyref) + (table $t2 10 funcref) + (elem $el funcref) + (func $f + (table.init $t1 $el (i32.const 0) (i32.const 1) (i32.const 2)) + (table.copy $t1 $t2 (i32.const 0) (i32.const 1) (i32.const 2)) + ) +) + +(assert_invalid + (module + (table $t1 10 funcref) + (table $t2 10 anyref) + (func $f + (table.copy $t1 $t2 (i32.const 0) (i32.const 1) (i32.const 2)) + ) + ) + "type mismatch" +) + +(assert_invalid + (module + (table $t 10 funcref) + (elem $el anyref) + (func $f + (table.init $t $el (i32.const 0) (i32.const 1) (i32.const 2)) + ) + ) + "type mismatch" +) From 774dd1d023cec2f32ae91f54afd32e27861fec17 Mon Sep 17 00:00:00 2001 From: Andreas Rossberg Date: Wed, 19 Feb 2020 16:25:52 +0100 Subject: [PATCH 148/199] [spec] Typo --- document/core/valid/modules.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/document/core/valid/modules.rst b/document/core/valid/modules.rst index fc2f9be133..374cfddbcb 100644 --- a/document/core/valid/modules.rst +++ b/document/core/valid/modules.rst @@ -599,7 +599,7 @@ Instead, the context :math:`C` for validation of the module's content is constru * Let :math:`\X{gt}^\ast` be the concatenation of the internal :ref:`global types ` :math:`\X{gt}_i`, in index order. -* Let :math:`\X{rt}^\ast` be the concatenation of the :ref:`referense types ` :math:`\X{rt}_i`, in index order. +* Let :math:`\X{rt}^\ast` be the concatenation of the :ref:`reference types ` :math:`\X{rt}_i`, in index order. * Let :math:`\X{it}^\ast` be the concatenation of :ref:`external types ` :math:`\X{it}_i` of the imports, in index order. From a1bfe97366746921e43f44506ccd575e06a944b5 Mon Sep 17 00:00:00 2001 From: Andreas Rossberg Date: Mon, 24 Feb 2020 13:56:56 +0100 Subject: [PATCH 149/199] [spec] Fix binary immediate order for table/memory.init (#82) --- document/core/binary/instructions.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/document/core/binary/instructions.rst b/document/core/binary/instructions.rst index ed3e506dc2..cb34bba1fe 100644 --- a/document/core/binary/instructions.rst +++ b/document/core/binary/instructions.rst @@ -157,7 +157,7 @@ Table Instructions \hex{FC}~\hex{0F}~~x{:}\Btableidx &\Rightarrow& \TABLEGROW~x \\ &&|& \hex{FC}~\hex{10}~~x{:}\Btableidx &\Rightarrow& \TABLESIZE~x \\ &&|& \hex{FC}~\hex{11}~~x{:}\Btableidx &\Rightarrow& \TABLEFILL~x \\ - \hex{FC}~\hex{0C}~~x{:}\Btableidx~~y{:}\Belemidx &\Rightarrow& \TABLEINIT~x~y \\ &&|& + \hex{FC}~\hex{0C}~~y{:}\Belemidx~~x{:}\Btableidx &\Rightarrow& \TABLEINIT~x~y \\ &&|& \hex{FC}~\hex{0D}~~x{:}\Belemidx &\Rightarrow& \ELEMDROP~x \\ &&|& \hex{FC}~\hex{0E}~~x{:}\Btableidx~~y{:}\Btableidx &\Rightarrow& \TABLECOPY~x~y \\ \end{array} @@ -214,7 +214,7 @@ Each variant of :ref:`memory instruction ` is encoded with \hex{3E}~~m{:}\Bmemarg &\Rightarrow& \I64.\STORE\K{32}~m \\ &&|& \hex{3F}~~\hex{00} &\Rightarrow& \MEMORYSIZE \\ &&|& \hex{40}~~\hex{00} &\Rightarrow& \MEMORYGROW \\ &&|& - \hex{FC}~\hex{08}~~\hex{00}~x{:}\Bdataidx &\Rightarrow& \MEMORYINIT~x \\ &&|& + \hex{FC}~\hex{08}~~x{:}\Bdataidx~~\hex{00} &\Rightarrow& \MEMORYINIT~x \\ &&|& \hex{FC}~\hex{09}~~x{:}\Bdataidx &\Rightarrow& \DATADROP~x \\ &&|& \hex{FC}~\hex{0A}~~\hex{00}~~\hex{00} &\Rightarrow& \MEMORYCOPY \\ &&|& \hex{FC}~\hex{0B}~~\hex{00} &\Rightarrow& \MEMORYFILL \\ From 7cfa19962056c87c8747c2c1edf8679cf055cd3f Mon Sep 17 00:00:00 2001 From: Andreas Rossberg Date: Thu, 27 Feb 2020 14:40:50 +0100 Subject: [PATCH 150/199] [test] call_indirect with multiple tables (#83) --- test/core/call_indirect.wast | 46 ++++++++++++++++++++++++++++++++++++ 1 file changed, 46 insertions(+) diff --git a/test/core/call_indirect.wast b/test/core/call_indirect.wast index 87d1df75a5..de7534b9c6 100644 --- a/test/core/call_indirect.wast +++ b/test/core/call_indirect.wast @@ -588,6 +588,52 @@ (assert_return (invoke "as-compare-right") (i32.const 1)) (assert_return (invoke "as-convert-operand") (i64.const 1)) + +;; Multiple tables + +(module + (type $ii-i (func (param i32 i32) (result i32))) + + (table $t1 funcref (elem $f $g)) + (table $t2 funcref (elem $h $i $j)) + (table $t3 4 funcref) + (elem (table $t3) (i32.const 0) func $g $h) + (elem (table $t3) (i32.const 3) func $z) + + (func $f (type $ii-i) (i32.add (local.get 0) (local.get 1))) + (func $g (type $ii-i) (i32.sub (local.get 0) (local.get 1))) + (func $h (type $ii-i) (i32.mul (local.get 0) (local.get 1))) + (func $i (type $ii-i) (i32.div_u (local.get 0) (local.get 1))) + (func $j (type $ii-i) (i32.rem_u (local.get 0) (local.get 1))) + (func $z) + + (func (export "call-1") (param i32 i32 i32) (result i32) + (call_indirect $t1 (type $ii-i) (local.get 0) (local.get 1) (local.get 2)) + ) + (func (export "call-2") (param i32 i32 i32) (result i32) + (call_indirect $t2 (type $ii-i) (local.get 0) (local.get 1) (local.get 2)) + ) + (func (export "call-3") (param i32 i32 i32) (result i32) + (call_indirect $t3 (type $ii-i) (local.get 0) (local.get 1) (local.get 2)) + ) +) + +(assert_return (invoke "call-1" (i32.const 2) (i32.const 3) (i32.const 0)) (i32.const 5)) +(assert_return (invoke "call-1" (i32.const 2) (i32.const 3) (i32.const 1)) (i32.const -1)) +(assert_trap (invoke "call-1" (i32.const 2) (i32.const 3) (i32.const 2)) "undefined element") + +(assert_return (invoke "call-2" (i32.const 2) (i32.const 3) (i32.const 0)) (i32.const 6)) +(assert_return (invoke "call-2" (i32.const 2) (i32.const 3) (i32.const 1)) (i32.const 0)) +(assert_return (invoke "call-2" (i32.const 2) (i32.const 3) (i32.const 2)) (i32.const 2)) +(assert_trap (invoke "call-2" (i32.const 2) (i32.const 3) (i32.const 3)) "undefined element") + +(assert_return (invoke "call-3" (i32.const 2) (i32.const 3) (i32.const 0)) (i32.const -1)) +(assert_return (invoke "call-3" (i32.const 2) (i32.const 3) (i32.const 1)) (i32.const 6)) +(assert_trap (invoke "call-3" (i32.const 2) (i32.const 3) (i32.const 2)) "uninitialized element") +(assert_trap (invoke "call-3" (i32.const 2) (i32.const 3) (i32.const 3)) "indirect call type mismatch") +(assert_trap (invoke "call-3" (i32.const 2) (i32.const 3) (i32.const 4)) "undefined element") + + ;; Invalid syntax (assert_malformed From ffdbb6e357d79818c88c3557cd3325346a057d27 Mon Sep 17 00:00:00 2001 From: Ben Smith Date: Fri, 28 Feb 2020 14:23:49 -0800 Subject: [PATCH 151/199] Test that drop instructions work w/on memory/table (#140) This was fixed in the interpreter in the last PR, but only fixed the messages in various assertions. This commit adds a new explicit test for this. --- test/core/bulk.wast | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/test/core/bulk.wast b/test/core/bulk.wast index e30cca4229..6fb1f0decc 100644 --- a/test/core/bulk.wast +++ b/test/core/bulk.wast @@ -179,7 +179,6 @@ ;; Test that the data segment index is properly encoded as an unsigned (not ;; signed) LEB. (module - (memory 1) ;; 65 data segments. 64 is the smallest positive number that is encoded ;; differently as a signed LEB. (data "") (data "") (data "") (data "") (data "") (data "") (data "") (data "") @@ -193,6 +192,9 @@ (data "") (func (data.drop 64))) +;; No memory is required for the data.drop instruction. +(module (data "goodbye") (func (data.drop 0))) + ;; table.init (module (table 3 funcref) @@ -270,7 +272,6 @@ ;; Test that the elem segment index is properly encoded as an unsigned (not ;; signed) LEB. (module - (table 1 funcref) ;; 65 elem segments. 64 is the smallest positive number that is encoded ;; differently as a signed LEB. (elem funcref) (elem funcref) (elem funcref) (elem funcref) @@ -292,6 +293,9 @@ (elem funcref) (func (elem.drop 64))) +;; No table is required for the elem.drop instruction. +(module (elem funcref (ref.func 0)) (func (elem.drop 0))) + ;; table.copy (module (table 10 funcref) From 060678fff4ac8206a531dd3cef64be405fd61c5c Mon Sep 17 00:00:00 2001 From: Ben Smith Date: Mon, 23 Mar 2020 10:01:48 -0700 Subject: [PATCH 152/199] Change validation error -> malformed in Overview (#143) Fixes #142. A mismatched `DataCount` is malformed, not a validation error. --- proposals/bulk-memory-operations/Overview.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/proposals/bulk-memory-operations/Overview.md b/proposals/bulk-memory-operations/Overview.md index 09fd953c30..d843f00866 100644 --- a/proposals/bulk-memory-operations/Overview.md +++ b/proposals/bulk-memory-operations/Overview.md @@ -448,6 +448,6 @@ segments in the `Data` section: | ----- | ---- | ----------- | | count | `varuint32` | count of data segments in `Data` section | -It is a validation error if `count` is not equal to the number of data segments -in the `Data` section. It is also a validation error if the `DataCount` section +The binary is malformed if `count` is not equal to the number of data segments +in the `Data` section. The binary is also malformed if the `DataCount` section is omitted and a `memory.init` or `data.drop` instruction is used. From d7f0241fbf676ccf0b9686c87796ab11646b14ed Mon Sep 17 00:00:00 2001 From: Ben Smith Date: Mon, 23 Mar 2020 11:25:48 -0700 Subject: [PATCH 153/199] Fix {memory,table}.init immediate order (#147) The data/elem index comes before the memory/table index. --- document/core/binary/instructions.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/document/core/binary/instructions.rst b/document/core/binary/instructions.rst index b119b2e99f..1e6127814d 100644 --- a/document/core/binary/instructions.rst +++ b/document/core/binary/instructions.rst @@ -122,7 +122,7 @@ Each variant of :ref:`table instruction ` is encoded with a .. math:: \begin{array}{llclll} \production{instruction} & \Binstr &::=& \dots \\ &&|& - \hex{FC}~\hex{0C}~~\hex{00}~x{:}\Belemidx &\Rightarrow& \TABLEINIT~x \\ &&|& + \hex{FC}~\hex{0C}~~x{:}\Belemidx~\hex{00} &\Rightarrow& \TABLEINIT~x \\ &&|& \hex{FC}~\hex{0D}~~x{:}\Belemidx &\Rightarrow& \ELEMDROP~x \\ &&|& \hex{FC}~\hex{0E}~~\hex{00}~~\hex{00} &\Rightarrow& \TABLECOPY \\ \end{array} @@ -182,7 +182,7 @@ Each variant of :ref:`memory instruction ` is encoded with \hex{3E}~~m{:}\Bmemarg &\Rightarrow& \I64.\STORE\K{32}~m \\ &&|& \hex{3F}~~\hex{00} &\Rightarrow& \MEMORYSIZE \\ &&|& \hex{40}~~\hex{00} &\Rightarrow& \MEMORYGROW \\ &&|& - \hex{FC}~\hex{08}~~\hex{00}~x{:}\Bdataidx &\Rightarrow& \MEMORYINIT~x \\ &&|& + \hex{FC}~\hex{08}~~x{:}\Bdataidx~\hex{00} &\Rightarrow& \MEMORYINIT~x \\ &&|& \hex{FC}~\hex{09}~~x{:}\Bdataidx &\Rightarrow& \DATADROP~x \\ &&|& \hex{FC}~\hex{0A}~~\hex{00}~~\hex{00} &\Rightarrow& \MEMORYCOPY \\ &&|& \hex{FC}~\hex{0B}~~\hex{00} &\Rightarrow& \MEMORYFILL \\ From 2028231a0421807e3a17ddc5020d13c76feadd6b Mon Sep 17 00:00:00 2001 From: Ms2ger Date: Tue, 24 Mar 2020 11:55:13 +0100 Subject: [PATCH 154/199] [js-api] Extend with reference types support. (#79) * [js-api] Remove spurious argument to ToWebAssemblyValue(). Fixes #51. * [js-api] Extend the WebAssembly.Table API. Fixes #22. Fixes #67. --- document/js-api/index.bs | 61 ++++++++++++++++++++++++++-------------- 1 file changed, 40 insertions(+), 21 deletions(-) diff --git a/document/js-api/index.bs b/document/js-api/index.bs index f39746da97..8367506493 100644 --- a/document/js-api/index.bs +++ b/document/js-api/index.bs @@ -722,10 +722,10 @@ dictionary TableDescriptor { [LegacyNamespace=WebAssembly, Exposed=(Window,Worker,Worklet)] interface Table { - constructor(TableDescriptor descriptor); - unsigned long grow([EnforceRange] unsigned long delta); - Function? get([EnforceRange] unsigned long index); - void set([EnforceRange] unsigned long index, Function? value); + constructor(TableDescriptor descriptor, optional any value); + unsigned long grow([EnforceRange] unsigned long delta, optional any value); + any get([EnforceRange] unsigned long index); + void set([EnforceRange] unsigned long index, optional any value); readonly attribute unsigned long length; };
    @@ -736,7 +736,7 @@ which can be simultaneously referenced by multiple {{Instance}} objects. Each {{Table}} object has the following internal slots: * \[[Table]] : a [=table address=] - * \[[Values]] : a [=list=] whose elements are either null or [=Exported Function=]s. + * \[[Values]] : a [=list=] whose elements depend on the element type of \[[Table]]'s [=table type=].
    @@ -761,29 +761,41 @@ which can be simultaneously referenced by multiple {{Instance}} objects. Each
    - The Table(|descriptor|) constructor, when invoked, performs the following steps: + The Table(|descriptor|, |value|) constructor, when invoked, performs the following steps: + 1. Let |elementType| be ToValueType(descriptor|["element"]). 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 |type| be the [=table type=] {[=table type|𝗆𝗂𝗇=] n, [=table type|𝗆𝖺𝗑=] |maximum|} [=table type|funcref=]. + 1. If |value| is missing, + 1. Let |ref| be [=DefaultValue=](|elementType|). + 1. Otherwise, + 1. Let |ref| be ? [=ToWebAssemblyValue=](|value|, |elementType|). + 1. Let |type| be the [=table type=] {[=table type|𝗆𝗂𝗇=] |initial|, [=table type|𝗆𝖺𝗑=] |maximum|} |elementType|. 1. Let |store| be the [=surrounding agent=]'s [=associated store=]. - 1. Let (|store|, |tableaddr|) be [=table_alloc=](|store|, |type|, [=ref.null=]). + 1. Let (|store|, |tableaddr|) be [=table_alloc=](|store|, |type|, |ref|). 1. Set the [=surrounding agent=]'s [=associated store=] to |store|. 1. [=initialize a table object|Initialize=] **this** from |tableaddr|. + 1. [=list/Empty=] **this**.\[[Values]]. + 1. [=list/Append=] |value| to **this**.\[[Values]] |initial| times.
    - The grow(|delta|) method, when invoked, performs the following steps: + The grow(|delta|, |value|) method, when invoked, performs the following steps: 1. Let |tableaddr| be **this**.\[[Table]]. 1. Let |initialSize| be the length of **this**.\[[Values]]. 1. Let |store| be the [=surrounding agent=]'s [=associated store=]. - 1. Let |result| be [=table_grow=](|store|, |tableaddr|, |delta|, [=ref.null=]). + 1. Let (limits, |elementType|) be [=table_type=](|tableaddr|). + 1. If |value| is missing, + 1. Let |ref| be [=DefaultValue=](|elementType|). + 1. Otherwise, + 1. Let |ref| be ? [=ToWebAssemblyValue=](|value|, |elementType|). + 1. Let |result| be [=table_grow=](|store|, |tableaddr|, |delta|, |ref|). 1. If |result| is [=error=], throw a {{RangeError}} exception. Note: The above exception may happen due to either insufficient memory or an invalid size parameter. 1. Set the [=surrounding agent=]'s [=associated store=] to |result|. - 1. [=list/Append=] null to **this**.\[[Values]] |delta| times. + 1. [=list/Append=] |value| to **this**.\[[Values]] |delta| times. 1. Return |initialSize|.
    @@ -803,10 +815,11 @@ which can be simultaneously referenced by multiple {{Instance}} objects. Each The set(|index|, |value|) method, when invoked, performs the following steps: 1. Let |tableaddr| be **this**.\[[Table]]. 1. Let |values| be **this**.\[[Values]]. - 1. If |value| is null, let |ref| be [=ref.null=]. + 1. Let (limits, |elementType|) be [=table_type=](|tableaddr|). + 1. If |value| is missing, + 1. Let |ref| be [=DefaultValue=](|elementType|). 1. Otherwise, - 1. If |value| does not have a \[[FunctionAddress]] internal slot, throw a {{TypeError}} exception. - 1. Let |ref| be [=ref.func=] |value|.\[[FunctionAddress]]. + 1. Let |ref| be ? [=ToWebAssemblyValue=](|value|, |elementType|). 1. Let |store| be the [=surrounding agent=]'s [=associated store=]. 1. Let |store| be [=table_write=](|store|, |tableaddr|, |index|, |ref|). 1. If |store| is [=error=], throw a {{RangeError}} exception. @@ -822,7 +835,10 @@ enum ValueType { "i32", "i64", "f32", - "f64" + "f64", + "nullref", + "anyref", + "anyfunc", };
    @@ -886,14 +902,17 @@ which can be simultaneously referenced by multiple {{Instance}} objects. Each 1. If |valuetype| equals [=𝗂𝟨𝟦=], return [=𝗂𝟨𝟦.𝖼𝗈𝗇𝗌𝗍=] 0. 1. If |valuetype| equals [=𝖿𝟥𝟤=], return [=𝖿𝟥𝟤.𝖼𝗈𝗇𝗌𝗍=] 0. 1. If |valuetype| equals [=𝖿𝟨𝟦=], return [=𝖿𝟨𝟦.𝖼𝗈𝗇𝗌𝗍=] 0. - 1. Else, return [=ref.null=]. + 1. If |valuetype| equals [=nullref=], return [=ref.null=]. + 1. If |valuetype| equals [=anyref=], return [=ToWebAssemblyValue=](undefined, |valuetype|). + 1. If |valuetype| equals [=nullref=], return [=ref.null=]. + 1. Assert: This step is not reached.
    The Global(|descriptor|, |v|) constructor, when invoked, performs the following steps: 1. Let |mutable| be |descriptor|["mutable"]. 1. Let |valuetype| be [=ToValueType=](|descriptor|["value"]). - 1. If |v| is undefined, + 1. If |v| is missing, 1. let |value| be [=DefaultValue=](|valuetype|). 1. Otherwise, 1. If |valuetype| is [=𝗂𝟨𝟦=], throw a {{TypeError}} exception. @@ -993,7 +1012,7 @@ This slot holds a [=function address=] relative to the [=surrounding agent=]'s [ 1. For each type |t| of |parameters|, 1. If the length of |argValues| > |i|, let |arg| be |argValues|[|i|]. 1. Otherwise, let |arg| be undefined. - 1. [=list/Append=] [=ToWebAssemblyValue=](|arg|, |t|, {{TypeError}}) to |args|. + 1. [=list/Append=] [=ToWebAssemblyValue=](|arg|, |t|) to |args|. 1. Set |i| to |i| + 1. 1. Let |argsSeq| be a WebAssembly [=sequence=] containing the elements of |args|. 1. Let (|store|, |ret|) be the result of [=func_invoke=](|store|, |funcaddr|, |argsSeq|). @@ -1060,7 +1079,7 @@ Note: Number values which are equal to NaN may have various observable NaN paylo
    -The algorithm ToWebAssemblyValue(|v|, |type|, |error|) coerces a JavaScript value to a [=WebAssembly value=] performs the following steps: +The algorithm ToWebAssemblyValue(|v|, |type|) coerces a JavaScript value to a [=WebAssembly value=] performs the following steps: 1. Assert: |type| is not [=𝗂𝟨𝟦=]. @@ -1077,9 +1096,9 @@ The algorithm ToWebAssemblyValue(|v|, |type|, |error|) coerces a Java 1. If |type| is [=anyref=], 1. Do nothing. 1. If |type| is [=funcref=], - 1. If |v| is not an [=Exported function=] or null, throw |error|. + 1. If |v| is not an [=Exported function=] or null, throw a {{TypeError}}. 1. If |type| is [=nullref=], - 1. If |v| is not null, throw |error|. + 1. If |v| is not null, throw a {{TypeError}}. 1. Return the result of [=allocating a host address=] for |v|.
    From 1568b3599a7f1be6f8e4e144b6fe4682b4a0d312 Mon Sep 17 00:00:00 2001 From: Lars T Hansen Date: Tue, 24 Mar 2020 11:58:16 +0100 Subject: [PATCH 155/199] Generalize test generators for table.copy and table.init to multi-table (#84) --- test/core/memory_copy.wast | 1 + test/core/memory_fill.wast | 1 + test/core/memory_init.wast | 1 + test/core/table_copy.wast | 2149 +++++++++++++++++++++++++----- test/core/table_init.wast | 512 ++++++- test/meta/Makefile | 2 +- test/meta/common.js | 1 + test/meta/generate_table_copy.js | 250 ++-- test/meta/generate_table_init.js | 164 ++- 9 files changed, 2502 insertions(+), 579 deletions(-) diff --git a/test/core/memory_copy.wast b/test/core/memory_copy.wast index 692e1ad85f..58973d94a5 100644 --- a/test/core/memory_copy.wast +++ b/test/core/memory_copy.wast @@ -1,5 +1,6 @@ ;; ;; Generated by ../meta/generate_memory_copy.js +;; DO NOT EDIT THIS FILE. CHANGE THE SOURCE AND REGENERATE. ;; (module diff --git a/test/core/memory_fill.wast b/test/core/memory_fill.wast index caca80b5da..99fd63ddde 100644 --- a/test/core/memory_fill.wast +++ b/test/core/memory_fill.wast @@ -1,5 +1,6 @@ ;; ;; Generated by ../meta/generate_memory_fill.js +;; DO NOT EDIT THIS FILE. CHANGE THE SOURCE AND REGENERATE. ;; (module diff --git a/test/core/memory_init.wast b/test/core/memory_init.wast index c647079d91..a001ff52ac 100644 --- a/test/core/memory_init.wast +++ b/test/core/memory_init.wast @@ -1,5 +1,6 @@ ;; ;; Generated by ../meta/generate_memory_init.js +;; DO NOT EDIT THIS FILE. CHANGE THE SOURCE AND REGENERATE. ;; (module diff --git a/test/core/table_copy.wast b/test/core/table_copy.wast index d0aa77b205..9788c3f4f4 100644 --- a/test/core/table_copy.wast +++ b/test/core/table_copy.wast @@ -1,5 +1,6 @@ ;; ;; Generated by ../meta/generate_table_copy.js +;; DO NOT EDIT THIS FILE. CHANGE THE SOURCE AND REGENERATE. ;; (module @@ -18,13 +19,16 @@ (import "a" "ef2" (func (result i32))) (import "a" "ef3" (func (result i32))) (import "a" "ef4" (func (result i32))) ;; index 4 - (table 30 30 funcref) - (elem (i32.const 2) 3 1 4 1) + (table $t0 30 30 funcref) + (table $t1 30 30 funcref) + (elem (table $t0) (i32.const 2) func 3 1 4 1) (elem funcref (ref.func 2) (ref.func 7) (ref.func 1) (ref.func 8)) - (elem (i32.const 12) 7 5 2 3 6) + (elem (table $t0) (i32.const 12) func 7 5 2 3 6) (elem funcref (ref.func 5) (ref.func 9) (ref.func 2) (ref.func 7) (ref.func 6)) + (elem (table $t1) (i32.const 3) func 1 3 1 4) + (elem (table $t1) (i32.const 11) func 6 3 2 5 7) (func (result i32) (i32.const 5)) ;; index 5 (func (result i32) (i32.const 6)) (func (result i32) (i32.const 7)) @@ -32,41 +36,73 @@ (func (result i32) (i32.const 9)) ;; index 9 (func (export "test") (nop)) - (func (export "check") (param i32) (result i32) - (call_indirect (type 0) (local.get 0))) + (func (export "check_t0") (param i32) (result i32) + (call_indirect $t0 (type 0) (local.get 0))) + (func (export "check_t1") (param i32) (result i32) + (call_indirect $t1 (type 0) (local.get 0))) ) (invoke "test") -(assert_trap (invoke "check" (i32.const 0)) "uninitialized element") -(assert_trap (invoke "check" (i32.const 1)) "uninitialized element") -(assert_return (invoke "check" (i32.const 2)) (i32.const 3)) -(assert_return (invoke "check" (i32.const 3)) (i32.const 1)) -(assert_return (invoke "check" (i32.const 4)) (i32.const 4)) -(assert_return (invoke "check" (i32.const 5)) (i32.const 1)) -(assert_trap (invoke "check" (i32.const 6)) "uninitialized element") -(assert_trap (invoke "check" (i32.const 7)) "uninitialized element") -(assert_trap (invoke "check" (i32.const 8)) "uninitialized element") -(assert_trap (invoke "check" (i32.const 9)) "uninitialized element") -(assert_trap (invoke "check" (i32.const 10)) "uninitialized element") -(assert_trap (invoke "check" (i32.const 11)) "uninitialized element") -(assert_return (invoke "check" (i32.const 12)) (i32.const 7)) -(assert_return (invoke "check" (i32.const 13)) (i32.const 5)) -(assert_return (invoke "check" (i32.const 14)) (i32.const 2)) -(assert_return (invoke "check" (i32.const 15)) (i32.const 3)) -(assert_return (invoke "check" (i32.const 16)) (i32.const 6)) -(assert_trap (invoke "check" (i32.const 17)) "uninitialized element") -(assert_trap (invoke "check" (i32.const 18)) "uninitialized element") -(assert_trap (invoke "check" (i32.const 19)) "uninitialized element") -(assert_trap (invoke "check" (i32.const 20)) "uninitialized element") -(assert_trap (invoke "check" (i32.const 21)) "uninitialized element") -(assert_trap (invoke "check" (i32.const 22)) "uninitialized element") -(assert_trap (invoke "check" (i32.const 23)) "uninitialized element") -(assert_trap (invoke "check" (i32.const 24)) "uninitialized element") -(assert_trap (invoke "check" (i32.const 25)) "uninitialized element") -(assert_trap (invoke "check" (i32.const 26)) "uninitialized element") -(assert_trap (invoke "check" (i32.const 27)) "uninitialized element") -(assert_trap (invoke "check" (i32.const 28)) "uninitialized element") -(assert_trap (invoke "check" (i32.const 29)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 0)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 1)) "uninitialized element") +(assert_return (invoke "check_t0" (i32.const 2)) (i32.const 3)) +(assert_return (invoke "check_t0" (i32.const 3)) (i32.const 1)) +(assert_return (invoke "check_t0" (i32.const 4)) (i32.const 4)) +(assert_return (invoke "check_t0" (i32.const 5)) (i32.const 1)) +(assert_trap (invoke "check_t0" (i32.const 6)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 7)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 8)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 9)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 10)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 11)) "uninitialized element") +(assert_return (invoke "check_t0" (i32.const 12)) (i32.const 7)) +(assert_return (invoke "check_t0" (i32.const 13)) (i32.const 5)) +(assert_return (invoke "check_t0" (i32.const 14)) (i32.const 2)) +(assert_return (invoke "check_t0" (i32.const 15)) (i32.const 3)) +(assert_return (invoke "check_t0" (i32.const 16)) (i32.const 6)) +(assert_trap (invoke "check_t0" (i32.const 17)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 18)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 19)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 20)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 21)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 22)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 23)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 24)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 25)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 26)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 27)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 28)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 29)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 0)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 1)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 2)) "uninitialized element") +(assert_return (invoke "check_t1" (i32.const 3)) (i32.const 1)) +(assert_return (invoke "check_t1" (i32.const 4)) (i32.const 3)) +(assert_return (invoke "check_t1" (i32.const 5)) (i32.const 1)) +(assert_return (invoke "check_t1" (i32.const 6)) (i32.const 4)) +(assert_trap (invoke "check_t1" (i32.const 7)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 8)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 9)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 10)) "uninitialized element") +(assert_return (invoke "check_t1" (i32.const 11)) (i32.const 6)) +(assert_return (invoke "check_t1" (i32.const 12)) (i32.const 3)) +(assert_return (invoke "check_t1" (i32.const 13)) (i32.const 2)) +(assert_return (invoke "check_t1" (i32.const 14)) (i32.const 5)) +(assert_return (invoke "check_t1" (i32.const 15)) (i32.const 7)) +(assert_trap (invoke "check_t1" (i32.const 16)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 17)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 18)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 19)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 20)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 21)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 22)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 23)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 24)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 25)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 26)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 27)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 28)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 29)) "uninitialized element") (module (type (func (result i32))) ;; type #0 @@ -75,55 +111,90 @@ (import "a" "ef2" (func (result i32))) (import "a" "ef3" (func (result i32))) (import "a" "ef4" (func (result i32))) ;; index 4 - (table 30 30 funcref) - (elem (i32.const 2) 3 1 4 1) + (table $t0 30 30 funcref) + (table $t1 30 30 funcref) + (elem (table $t0) (i32.const 2) func 3 1 4 1) (elem funcref (ref.func 2) (ref.func 7) (ref.func 1) (ref.func 8)) - (elem (i32.const 12) 7 5 2 3 6) + (elem (table $t0) (i32.const 12) func 7 5 2 3 6) (elem funcref (ref.func 5) (ref.func 9) (ref.func 2) (ref.func 7) (ref.func 6)) + (elem (table $t1) (i32.const 3) func 1 3 1 4) + (elem (table $t1) (i32.const 11) func 6 3 2 5 7) (func (result i32) (i32.const 5)) ;; index 5 (func (result i32) (i32.const 6)) (func (result i32) (i32.const 7)) (func (result i32) (i32.const 8)) (func (result i32) (i32.const 9)) ;; index 9 (func (export "test") - (table.copy (i32.const 13) (i32.const 2) (i32.const 3))) - (func (export "check") (param i32) (result i32) - (call_indirect (type 0) (local.get 0))) + (table.copy $t0 $t0 (i32.const 13) (i32.const 2) (i32.const 3))) + (func (export "check_t0") (param i32) (result i32) + (call_indirect $t0 (type 0) (local.get 0))) + (func (export "check_t1") (param i32) (result i32) + (call_indirect $t1 (type 0) (local.get 0))) ) (invoke "test") -(assert_trap (invoke "check" (i32.const 0)) "uninitialized element") -(assert_trap (invoke "check" (i32.const 1)) "uninitialized element") -(assert_return (invoke "check" (i32.const 2)) (i32.const 3)) -(assert_return (invoke "check" (i32.const 3)) (i32.const 1)) -(assert_return (invoke "check" (i32.const 4)) (i32.const 4)) -(assert_return (invoke "check" (i32.const 5)) (i32.const 1)) -(assert_trap (invoke "check" (i32.const 6)) "uninitialized element") -(assert_trap (invoke "check" (i32.const 7)) "uninitialized element") -(assert_trap (invoke "check" (i32.const 8)) "uninitialized element") -(assert_trap (invoke "check" (i32.const 9)) "uninitialized element") -(assert_trap (invoke "check" (i32.const 10)) "uninitialized element") -(assert_trap (invoke "check" (i32.const 11)) "uninitialized element") -(assert_return (invoke "check" (i32.const 12)) (i32.const 7)) -(assert_return (invoke "check" (i32.const 13)) (i32.const 3)) -(assert_return (invoke "check" (i32.const 14)) (i32.const 1)) -(assert_return (invoke "check" (i32.const 15)) (i32.const 4)) -(assert_return (invoke "check" (i32.const 16)) (i32.const 6)) -(assert_trap (invoke "check" (i32.const 17)) "uninitialized element") -(assert_trap (invoke "check" (i32.const 18)) "uninitialized element") -(assert_trap (invoke "check" (i32.const 19)) "uninitialized element") -(assert_trap (invoke "check" (i32.const 20)) "uninitialized element") -(assert_trap (invoke "check" (i32.const 21)) "uninitialized element") -(assert_trap (invoke "check" (i32.const 22)) "uninitialized element") -(assert_trap (invoke "check" (i32.const 23)) "uninitialized element") -(assert_trap (invoke "check" (i32.const 24)) "uninitialized element") -(assert_trap (invoke "check" (i32.const 25)) "uninitialized element") -(assert_trap (invoke "check" (i32.const 26)) "uninitialized element") -(assert_trap (invoke "check" (i32.const 27)) "uninitialized element") -(assert_trap (invoke "check" (i32.const 28)) "uninitialized element") -(assert_trap (invoke "check" (i32.const 29)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 0)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 1)) "uninitialized element") +(assert_return (invoke "check_t0" (i32.const 2)) (i32.const 3)) +(assert_return (invoke "check_t0" (i32.const 3)) (i32.const 1)) +(assert_return (invoke "check_t0" (i32.const 4)) (i32.const 4)) +(assert_return (invoke "check_t0" (i32.const 5)) (i32.const 1)) +(assert_trap (invoke "check_t0" (i32.const 6)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 7)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 8)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 9)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 10)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 11)) "uninitialized element") +(assert_return (invoke "check_t0" (i32.const 12)) (i32.const 7)) +(assert_return (invoke "check_t0" (i32.const 13)) (i32.const 3)) +(assert_return (invoke "check_t0" (i32.const 14)) (i32.const 1)) +(assert_return (invoke "check_t0" (i32.const 15)) (i32.const 4)) +(assert_return (invoke "check_t0" (i32.const 16)) (i32.const 6)) +(assert_trap (invoke "check_t0" (i32.const 17)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 18)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 19)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 20)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 21)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 22)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 23)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 24)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 25)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 26)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 27)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 28)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 29)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 0)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 1)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 2)) "uninitialized element") +(assert_return (invoke "check_t1" (i32.const 3)) (i32.const 1)) +(assert_return (invoke "check_t1" (i32.const 4)) (i32.const 3)) +(assert_return (invoke "check_t1" (i32.const 5)) (i32.const 1)) +(assert_return (invoke "check_t1" (i32.const 6)) (i32.const 4)) +(assert_trap (invoke "check_t1" (i32.const 7)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 8)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 9)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 10)) "uninitialized element") +(assert_return (invoke "check_t1" (i32.const 11)) (i32.const 6)) +(assert_return (invoke "check_t1" (i32.const 12)) (i32.const 3)) +(assert_return (invoke "check_t1" (i32.const 13)) (i32.const 2)) +(assert_return (invoke "check_t1" (i32.const 14)) (i32.const 5)) +(assert_return (invoke "check_t1" (i32.const 15)) (i32.const 7)) +(assert_trap (invoke "check_t1" (i32.const 16)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 17)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 18)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 19)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 20)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 21)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 22)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 23)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 24)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 25)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 26)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 27)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 28)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 29)) "uninitialized element") (module (type (func (result i32))) ;; type #0 @@ -132,55 +203,90 @@ (import "a" "ef2" (func (result i32))) (import "a" "ef3" (func (result i32))) (import "a" "ef4" (func (result i32))) ;; index 4 - (table 30 30 funcref) - (elem (i32.const 2) 3 1 4 1) + (table $t0 30 30 funcref) + (table $t1 30 30 funcref) + (elem (table $t0) (i32.const 2) func 3 1 4 1) (elem funcref (ref.func 2) (ref.func 7) (ref.func 1) (ref.func 8)) - (elem (i32.const 12) 7 5 2 3 6) + (elem (table $t0) (i32.const 12) func 7 5 2 3 6) (elem funcref (ref.func 5) (ref.func 9) (ref.func 2) (ref.func 7) (ref.func 6)) + (elem (table $t1) (i32.const 3) func 1 3 1 4) + (elem (table $t1) (i32.const 11) func 6 3 2 5 7) (func (result i32) (i32.const 5)) ;; index 5 (func (result i32) (i32.const 6)) (func (result i32) (i32.const 7)) (func (result i32) (i32.const 8)) (func (result i32) (i32.const 9)) ;; index 9 (func (export "test") - (table.copy (i32.const 25) (i32.const 15) (i32.const 2))) - (func (export "check") (param i32) (result i32) - (call_indirect (type 0) (local.get 0))) + (table.copy $t0 $t0 (i32.const 25) (i32.const 15) (i32.const 2))) + (func (export "check_t0") (param i32) (result i32) + (call_indirect $t0 (type 0) (local.get 0))) + (func (export "check_t1") (param i32) (result i32) + (call_indirect $t1 (type 0) (local.get 0))) ) (invoke "test") -(assert_trap (invoke "check" (i32.const 0)) "uninitialized element") -(assert_trap (invoke "check" (i32.const 1)) "uninitialized element") -(assert_return (invoke "check" (i32.const 2)) (i32.const 3)) -(assert_return (invoke "check" (i32.const 3)) (i32.const 1)) -(assert_return (invoke "check" (i32.const 4)) (i32.const 4)) -(assert_return (invoke "check" (i32.const 5)) (i32.const 1)) -(assert_trap (invoke "check" (i32.const 6)) "uninitialized element") -(assert_trap (invoke "check" (i32.const 7)) "uninitialized element") -(assert_trap (invoke "check" (i32.const 8)) "uninitialized element") -(assert_trap (invoke "check" (i32.const 9)) "uninitialized element") -(assert_trap (invoke "check" (i32.const 10)) "uninitialized element") -(assert_trap (invoke "check" (i32.const 11)) "uninitialized element") -(assert_return (invoke "check" (i32.const 12)) (i32.const 7)) -(assert_return (invoke "check" (i32.const 13)) (i32.const 5)) -(assert_return (invoke "check" (i32.const 14)) (i32.const 2)) -(assert_return (invoke "check" (i32.const 15)) (i32.const 3)) -(assert_return (invoke "check" (i32.const 16)) (i32.const 6)) -(assert_trap (invoke "check" (i32.const 17)) "uninitialized element") -(assert_trap (invoke "check" (i32.const 18)) "uninitialized element") -(assert_trap (invoke "check" (i32.const 19)) "uninitialized element") -(assert_trap (invoke "check" (i32.const 20)) "uninitialized element") -(assert_trap (invoke "check" (i32.const 21)) "uninitialized element") -(assert_trap (invoke "check" (i32.const 22)) "uninitialized element") -(assert_trap (invoke "check" (i32.const 23)) "uninitialized element") -(assert_trap (invoke "check" (i32.const 24)) "uninitialized element") -(assert_return (invoke "check" (i32.const 25)) (i32.const 3)) -(assert_return (invoke "check" (i32.const 26)) (i32.const 6)) -(assert_trap (invoke "check" (i32.const 27)) "uninitialized element") -(assert_trap (invoke "check" (i32.const 28)) "uninitialized element") -(assert_trap (invoke "check" (i32.const 29)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 0)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 1)) "uninitialized element") +(assert_return (invoke "check_t0" (i32.const 2)) (i32.const 3)) +(assert_return (invoke "check_t0" (i32.const 3)) (i32.const 1)) +(assert_return (invoke "check_t0" (i32.const 4)) (i32.const 4)) +(assert_return (invoke "check_t0" (i32.const 5)) (i32.const 1)) +(assert_trap (invoke "check_t0" (i32.const 6)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 7)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 8)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 9)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 10)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 11)) "uninitialized element") +(assert_return (invoke "check_t0" (i32.const 12)) (i32.const 7)) +(assert_return (invoke "check_t0" (i32.const 13)) (i32.const 5)) +(assert_return (invoke "check_t0" (i32.const 14)) (i32.const 2)) +(assert_return (invoke "check_t0" (i32.const 15)) (i32.const 3)) +(assert_return (invoke "check_t0" (i32.const 16)) (i32.const 6)) +(assert_trap (invoke "check_t0" (i32.const 17)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 18)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 19)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 20)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 21)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 22)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 23)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 24)) "uninitialized element") +(assert_return (invoke "check_t0" (i32.const 25)) (i32.const 3)) +(assert_return (invoke "check_t0" (i32.const 26)) (i32.const 6)) +(assert_trap (invoke "check_t0" (i32.const 27)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 28)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 29)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 0)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 1)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 2)) "uninitialized element") +(assert_return (invoke "check_t1" (i32.const 3)) (i32.const 1)) +(assert_return (invoke "check_t1" (i32.const 4)) (i32.const 3)) +(assert_return (invoke "check_t1" (i32.const 5)) (i32.const 1)) +(assert_return (invoke "check_t1" (i32.const 6)) (i32.const 4)) +(assert_trap (invoke "check_t1" (i32.const 7)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 8)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 9)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 10)) "uninitialized element") +(assert_return (invoke "check_t1" (i32.const 11)) (i32.const 6)) +(assert_return (invoke "check_t1" (i32.const 12)) (i32.const 3)) +(assert_return (invoke "check_t1" (i32.const 13)) (i32.const 2)) +(assert_return (invoke "check_t1" (i32.const 14)) (i32.const 5)) +(assert_return (invoke "check_t1" (i32.const 15)) (i32.const 7)) +(assert_trap (invoke "check_t1" (i32.const 16)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 17)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 18)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 19)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 20)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 21)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 22)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 23)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 24)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 25)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 26)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 27)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 28)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 29)) "uninitialized element") (module (type (func (result i32))) ;; type #0 @@ -189,55 +295,90 @@ (import "a" "ef2" (func (result i32))) (import "a" "ef3" (func (result i32))) (import "a" "ef4" (func (result i32))) ;; index 4 - (table 30 30 funcref) - (elem (i32.const 2) 3 1 4 1) + (table $t0 30 30 funcref) + (table $t1 30 30 funcref) + (elem (table $t0) (i32.const 2) func 3 1 4 1) (elem funcref (ref.func 2) (ref.func 7) (ref.func 1) (ref.func 8)) - (elem (i32.const 12) 7 5 2 3 6) + (elem (table $t0) (i32.const 12) func 7 5 2 3 6) (elem funcref (ref.func 5) (ref.func 9) (ref.func 2) (ref.func 7) (ref.func 6)) + (elem (table $t1) (i32.const 3) func 1 3 1 4) + (elem (table $t1) (i32.const 11) func 6 3 2 5 7) (func (result i32) (i32.const 5)) ;; index 5 (func (result i32) (i32.const 6)) (func (result i32) (i32.const 7)) (func (result i32) (i32.const 8)) (func (result i32) (i32.const 9)) ;; index 9 (func (export "test") - (table.copy (i32.const 13) (i32.const 25) (i32.const 3))) - (func (export "check") (param i32) (result i32) - (call_indirect (type 0) (local.get 0))) + (table.copy $t0 $t0 (i32.const 13) (i32.const 25) (i32.const 3))) + (func (export "check_t0") (param i32) (result i32) + (call_indirect $t0 (type 0) (local.get 0))) + (func (export "check_t1") (param i32) (result i32) + (call_indirect $t1 (type 0) (local.get 0))) ) (invoke "test") -(assert_trap (invoke "check" (i32.const 0)) "uninitialized element") -(assert_trap (invoke "check" (i32.const 1)) "uninitialized element") -(assert_return (invoke "check" (i32.const 2)) (i32.const 3)) -(assert_return (invoke "check" (i32.const 3)) (i32.const 1)) -(assert_return (invoke "check" (i32.const 4)) (i32.const 4)) -(assert_return (invoke "check" (i32.const 5)) (i32.const 1)) -(assert_trap (invoke "check" (i32.const 6)) "uninitialized element") -(assert_trap (invoke "check" (i32.const 7)) "uninitialized element") -(assert_trap (invoke "check" (i32.const 8)) "uninitialized element") -(assert_trap (invoke "check" (i32.const 9)) "uninitialized element") -(assert_trap (invoke "check" (i32.const 10)) "uninitialized element") -(assert_trap (invoke "check" (i32.const 11)) "uninitialized element") -(assert_return (invoke "check" (i32.const 12)) (i32.const 7)) -(assert_trap (invoke "check" (i32.const 13)) "uninitialized element") -(assert_trap (invoke "check" (i32.const 14)) "uninitialized element") -(assert_trap (invoke "check" (i32.const 15)) "uninitialized element") -(assert_return (invoke "check" (i32.const 16)) (i32.const 6)) -(assert_trap (invoke "check" (i32.const 17)) "uninitialized element") -(assert_trap (invoke "check" (i32.const 18)) "uninitialized element") -(assert_trap (invoke "check" (i32.const 19)) "uninitialized element") -(assert_trap (invoke "check" (i32.const 20)) "uninitialized element") -(assert_trap (invoke "check" (i32.const 21)) "uninitialized element") -(assert_trap (invoke "check" (i32.const 22)) "uninitialized element") -(assert_trap (invoke "check" (i32.const 23)) "uninitialized element") -(assert_trap (invoke "check" (i32.const 24)) "uninitialized element") -(assert_trap (invoke "check" (i32.const 25)) "uninitialized element") -(assert_trap (invoke "check" (i32.const 26)) "uninitialized element") -(assert_trap (invoke "check" (i32.const 27)) "uninitialized element") -(assert_trap (invoke "check" (i32.const 28)) "uninitialized element") -(assert_trap (invoke "check" (i32.const 29)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 0)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 1)) "uninitialized element") +(assert_return (invoke "check_t0" (i32.const 2)) (i32.const 3)) +(assert_return (invoke "check_t0" (i32.const 3)) (i32.const 1)) +(assert_return (invoke "check_t0" (i32.const 4)) (i32.const 4)) +(assert_return (invoke "check_t0" (i32.const 5)) (i32.const 1)) +(assert_trap (invoke "check_t0" (i32.const 6)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 7)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 8)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 9)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 10)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 11)) "uninitialized element") +(assert_return (invoke "check_t0" (i32.const 12)) (i32.const 7)) +(assert_trap (invoke "check_t0" (i32.const 13)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 14)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 15)) "uninitialized element") +(assert_return (invoke "check_t0" (i32.const 16)) (i32.const 6)) +(assert_trap (invoke "check_t0" (i32.const 17)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 18)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 19)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 20)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 21)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 22)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 23)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 24)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 25)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 26)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 27)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 28)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 29)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 0)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 1)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 2)) "uninitialized element") +(assert_return (invoke "check_t1" (i32.const 3)) (i32.const 1)) +(assert_return (invoke "check_t1" (i32.const 4)) (i32.const 3)) +(assert_return (invoke "check_t1" (i32.const 5)) (i32.const 1)) +(assert_return (invoke "check_t1" (i32.const 6)) (i32.const 4)) +(assert_trap (invoke "check_t1" (i32.const 7)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 8)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 9)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 10)) "uninitialized element") +(assert_return (invoke "check_t1" (i32.const 11)) (i32.const 6)) +(assert_return (invoke "check_t1" (i32.const 12)) (i32.const 3)) +(assert_return (invoke "check_t1" (i32.const 13)) (i32.const 2)) +(assert_return (invoke "check_t1" (i32.const 14)) (i32.const 5)) +(assert_return (invoke "check_t1" (i32.const 15)) (i32.const 7)) +(assert_trap (invoke "check_t1" (i32.const 16)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 17)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 18)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 19)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 20)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 21)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 22)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 23)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 24)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 25)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 26)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 27)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 28)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 29)) "uninitialized element") (module (type (func (result i32))) ;; type #0 @@ -246,55 +387,90 @@ (import "a" "ef2" (func (result i32))) (import "a" "ef3" (func (result i32))) (import "a" "ef4" (func (result i32))) ;; index 4 - (table 30 30 funcref) - (elem (i32.const 2) 3 1 4 1) + (table $t0 30 30 funcref) + (table $t1 30 30 funcref) + (elem (table $t0) (i32.const 2) func 3 1 4 1) (elem funcref (ref.func 2) (ref.func 7) (ref.func 1) (ref.func 8)) - (elem (i32.const 12) 7 5 2 3 6) + (elem (table $t0) (i32.const 12) func 7 5 2 3 6) (elem funcref (ref.func 5) (ref.func 9) (ref.func 2) (ref.func 7) (ref.func 6)) + (elem (table $t1) (i32.const 3) func 1 3 1 4) + (elem (table $t1) (i32.const 11) func 6 3 2 5 7) (func (result i32) (i32.const 5)) ;; index 5 (func (result i32) (i32.const 6)) (func (result i32) (i32.const 7)) (func (result i32) (i32.const 8)) (func (result i32) (i32.const 9)) ;; index 9 (func (export "test") - (table.copy (i32.const 20) (i32.const 22) (i32.const 4))) - (func (export "check") (param i32) (result i32) - (call_indirect (type 0) (local.get 0))) + (table.copy $t0 $t0 (i32.const 20) (i32.const 22) (i32.const 4))) + (func (export "check_t0") (param i32) (result i32) + (call_indirect $t0 (type 0) (local.get 0))) + (func (export "check_t1") (param i32) (result i32) + (call_indirect $t1 (type 0) (local.get 0))) ) (invoke "test") -(assert_trap (invoke "check" (i32.const 0)) "uninitialized element") -(assert_trap (invoke "check" (i32.const 1)) "uninitialized element") -(assert_return (invoke "check" (i32.const 2)) (i32.const 3)) -(assert_return (invoke "check" (i32.const 3)) (i32.const 1)) -(assert_return (invoke "check" (i32.const 4)) (i32.const 4)) -(assert_return (invoke "check" (i32.const 5)) (i32.const 1)) -(assert_trap (invoke "check" (i32.const 6)) "uninitialized element") -(assert_trap (invoke "check" (i32.const 7)) "uninitialized element") -(assert_trap (invoke "check" (i32.const 8)) "uninitialized element") -(assert_trap (invoke "check" (i32.const 9)) "uninitialized element") -(assert_trap (invoke "check" (i32.const 10)) "uninitialized element") -(assert_trap (invoke "check" (i32.const 11)) "uninitialized element") -(assert_return (invoke "check" (i32.const 12)) (i32.const 7)) -(assert_return (invoke "check" (i32.const 13)) (i32.const 5)) -(assert_return (invoke "check" (i32.const 14)) (i32.const 2)) -(assert_return (invoke "check" (i32.const 15)) (i32.const 3)) -(assert_return (invoke "check" (i32.const 16)) (i32.const 6)) -(assert_trap (invoke "check" (i32.const 17)) "uninitialized element") -(assert_trap (invoke "check" (i32.const 18)) "uninitialized element") -(assert_trap (invoke "check" (i32.const 19)) "uninitialized element") -(assert_trap (invoke "check" (i32.const 20)) "uninitialized element") -(assert_trap (invoke "check" (i32.const 21)) "uninitialized element") -(assert_trap (invoke "check" (i32.const 22)) "uninitialized element") -(assert_trap (invoke "check" (i32.const 23)) "uninitialized element") -(assert_trap (invoke "check" (i32.const 24)) "uninitialized element") -(assert_trap (invoke "check" (i32.const 25)) "uninitialized element") -(assert_trap (invoke "check" (i32.const 26)) "uninitialized element") -(assert_trap (invoke "check" (i32.const 27)) "uninitialized element") -(assert_trap (invoke "check" (i32.const 28)) "uninitialized element") -(assert_trap (invoke "check" (i32.const 29)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 0)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 1)) "uninitialized element") +(assert_return (invoke "check_t0" (i32.const 2)) (i32.const 3)) +(assert_return (invoke "check_t0" (i32.const 3)) (i32.const 1)) +(assert_return (invoke "check_t0" (i32.const 4)) (i32.const 4)) +(assert_return (invoke "check_t0" (i32.const 5)) (i32.const 1)) +(assert_trap (invoke "check_t0" (i32.const 6)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 7)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 8)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 9)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 10)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 11)) "uninitialized element") +(assert_return (invoke "check_t0" (i32.const 12)) (i32.const 7)) +(assert_return (invoke "check_t0" (i32.const 13)) (i32.const 5)) +(assert_return (invoke "check_t0" (i32.const 14)) (i32.const 2)) +(assert_return (invoke "check_t0" (i32.const 15)) (i32.const 3)) +(assert_return (invoke "check_t0" (i32.const 16)) (i32.const 6)) +(assert_trap (invoke "check_t0" (i32.const 17)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 18)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 19)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 20)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 21)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 22)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 23)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 24)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 25)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 26)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 27)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 28)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 29)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 0)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 1)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 2)) "uninitialized element") +(assert_return (invoke "check_t1" (i32.const 3)) (i32.const 1)) +(assert_return (invoke "check_t1" (i32.const 4)) (i32.const 3)) +(assert_return (invoke "check_t1" (i32.const 5)) (i32.const 1)) +(assert_return (invoke "check_t1" (i32.const 6)) (i32.const 4)) +(assert_trap (invoke "check_t1" (i32.const 7)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 8)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 9)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 10)) "uninitialized element") +(assert_return (invoke "check_t1" (i32.const 11)) (i32.const 6)) +(assert_return (invoke "check_t1" (i32.const 12)) (i32.const 3)) +(assert_return (invoke "check_t1" (i32.const 13)) (i32.const 2)) +(assert_return (invoke "check_t1" (i32.const 14)) (i32.const 5)) +(assert_return (invoke "check_t1" (i32.const 15)) (i32.const 7)) +(assert_trap (invoke "check_t1" (i32.const 16)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 17)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 18)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 19)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 20)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 21)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 22)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 23)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 24)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 25)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 26)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 27)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 28)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 29)) "uninitialized element") (module (type (func (result i32))) ;; type #0 @@ -303,55 +479,90 @@ (import "a" "ef2" (func (result i32))) (import "a" "ef3" (func (result i32))) (import "a" "ef4" (func (result i32))) ;; index 4 - (table 30 30 funcref) - (elem (i32.const 2) 3 1 4 1) + (table $t0 30 30 funcref) + (table $t1 30 30 funcref) + (elem (table $t0) (i32.const 2) func 3 1 4 1) (elem funcref (ref.func 2) (ref.func 7) (ref.func 1) (ref.func 8)) - (elem (i32.const 12) 7 5 2 3 6) + (elem (table $t0) (i32.const 12) func 7 5 2 3 6) (elem funcref (ref.func 5) (ref.func 9) (ref.func 2) (ref.func 7) (ref.func 6)) + (elem (table $t1) (i32.const 3) func 1 3 1 4) + (elem (table $t1) (i32.const 11) func 6 3 2 5 7) (func (result i32) (i32.const 5)) ;; index 5 (func (result i32) (i32.const 6)) (func (result i32) (i32.const 7)) (func (result i32) (i32.const 8)) (func (result i32) (i32.const 9)) ;; index 9 (func (export "test") - (table.copy (i32.const 25) (i32.const 1) (i32.const 3))) - (func (export "check") (param i32) (result i32) - (call_indirect (type 0) (local.get 0))) + (table.copy $t0 $t0 (i32.const 25) (i32.const 1) (i32.const 3))) + (func (export "check_t0") (param i32) (result i32) + (call_indirect $t0 (type 0) (local.get 0))) + (func (export "check_t1") (param i32) (result i32) + (call_indirect $t1 (type 0) (local.get 0))) ) (invoke "test") -(assert_trap (invoke "check" (i32.const 0)) "uninitialized element") -(assert_trap (invoke "check" (i32.const 1)) "uninitialized element") -(assert_return (invoke "check" (i32.const 2)) (i32.const 3)) -(assert_return (invoke "check" (i32.const 3)) (i32.const 1)) -(assert_return (invoke "check" (i32.const 4)) (i32.const 4)) -(assert_return (invoke "check" (i32.const 5)) (i32.const 1)) -(assert_trap (invoke "check" (i32.const 6)) "uninitialized element") -(assert_trap (invoke "check" (i32.const 7)) "uninitialized element") -(assert_trap (invoke "check" (i32.const 8)) "uninitialized element") -(assert_trap (invoke "check" (i32.const 9)) "uninitialized element") -(assert_trap (invoke "check" (i32.const 10)) "uninitialized element") -(assert_trap (invoke "check" (i32.const 11)) "uninitialized element") -(assert_return (invoke "check" (i32.const 12)) (i32.const 7)) -(assert_return (invoke "check" (i32.const 13)) (i32.const 5)) -(assert_return (invoke "check" (i32.const 14)) (i32.const 2)) -(assert_return (invoke "check" (i32.const 15)) (i32.const 3)) -(assert_return (invoke "check" (i32.const 16)) (i32.const 6)) -(assert_trap (invoke "check" (i32.const 17)) "uninitialized element") -(assert_trap (invoke "check" (i32.const 18)) "uninitialized element") -(assert_trap (invoke "check" (i32.const 19)) "uninitialized element") -(assert_trap (invoke "check" (i32.const 20)) "uninitialized element") -(assert_trap (invoke "check" (i32.const 21)) "uninitialized element") -(assert_trap (invoke "check" (i32.const 22)) "uninitialized element") -(assert_trap (invoke "check" (i32.const 23)) "uninitialized element") -(assert_trap (invoke "check" (i32.const 24)) "uninitialized element") -(assert_trap (invoke "check" (i32.const 25)) "uninitialized element") -(assert_return (invoke "check" (i32.const 26)) (i32.const 3)) -(assert_return (invoke "check" (i32.const 27)) (i32.const 1)) -(assert_trap (invoke "check" (i32.const 28)) "uninitialized element") -(assert_trap (invoke "check" (i32.const 29)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 0)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 1)) "uninitialized element") +(assert_return (invoke "check_t0" (i32.const 2)) (i32.const 3)) +(assert_return (invoke "check_t0" (i32.const 3)) (i32.const 1)) +(assert_return (invoke "check_t0" (i32.const 4)) (i32.const 4)) +(assert_return (invoke "check_t0" (i32.const 5)) (i32.const 1)) +(assert_trap (invoke "check_t0" (i32.const 6)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 7)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 8)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 9)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 10)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 11)) "uninitialized element") +(assert_return (invoke "check_t0" (i32.const 12)) (i32.const 7)) +(assert_return (invoke "check_t0" (i32.const 13)) (i32.const 5)) +(assert_return (invoke "check_t0" (i32.const 14)) (i32.const 2)) +(assert_return (invoke "check_t0" (i32.const 15)) (i32.const 3)) +(assert_return (invoke "check_t0" (i32.const 16)) (i32.const 6)) +(assert_trap (invoke "check_t0" (i32.const 17)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 18)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 19)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 20)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 21)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 22)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 23)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 24)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 25)) "uninitialized element") +(assert_return (invoke "check_t0" (i32.const 26)) (i32.const 3)) +(assert_return (invoke "check_t0" (i32.const 27)) (i32.const 1)) +(assert_trap (invoke "check_t0" (i32.const 28)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 29)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 0)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 1)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 2)) "uninitialized element") +(assert_return (invoke "check_t1" (i32.const 3)) (i32.const 1)) +(assert_return (invoke "check_t1" (i32.const 4)) (i32.const 3)) +(assert_return (invoke "check_t1" (i32.const 5)) (i32.const 1)) +(assert_return (invoke "check_t1" (i32.const 6)) (i32.const 4)) +(assert_trap (invoke "check_t1" (i32.const 7)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 8)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 9)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 10)) "uninitialized element") +(assert_return (invoke "check_t1" (i32.const 11)) (i32.const 6)) +(assert_return (invoke "check_t1" (i32.const 12)) (i32.const 3)) +(assert_return (invoke "check_t1" (i32.const 13)) (i32.const 2)) +(assert_return (invoke "check_t1" (i32.const 14)) (i32.const 5)) +(assert_return (invoke "check_t1" (i32.const 15)) (i32.const 7)) +(assert_trap (invoke "check_t1" (i32.const 16)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 17)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 18)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 19)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 20)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 21)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 22)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 23)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 24)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 25)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 26)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 27)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 28)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 29)) "uninitialized element") (module (type (func (result i32))) ;; type #0 @@ -360,55 +571,90 @@ (import "a" "ef2" (func (result i32))) (import "a" "ef3" (func (result i32))) (import "a" "ef4" (func (result i32))) ;; index 4 - (table 30 30 funcref) - (elem (i32.const 2) 3 1 4 1) + (table $t0 30 30 funcref) + (table $t1 30 30 funcref) + (elem (table $t0) (i32.const 2) func 3 1 4 1) (elem funcref (ref.func 2) (ref.func 7) (ref.func 1) (ref.func 8)) - (elem (i32.const 12) 7 5 2 3 6) + (elem (table $t0) (i32.const 12) func 7 5 2 3 6) (elem funcref (ref.func 5) (ref.func 9) (ref.func 2) (ref.func 7) (ref.func 6)) + (elem (table $t1) (i32.const 3) func 1 3 1 4) + (elem (table $t1) (i32.const 11) func 6 3 2 5 7) (func (result i32) (i32.const 5)) ;; index 5 (func (result i32) (i32.const 6)) (func (result i32) (i32.const 7)) (func (result i32) (i32.const 8)) (func (result i32) (i32.const 9)) ;; index 9 (func (export "test") - (table.copy (i32.const 10) (i32.const 12) (i32.const 7))) - (func (export "check") (param i32) (result i32) - (call_indirect (type 0) (local.get 0))) + (table.copy $t0 $t0 (i32.const 10) (i32.const 12) (i32.const 7))) + (func (export "check_t0") (param i32) (result i32) + (call_indirect $t0 (type 0) (local.get 0))) + (func (export "check_t1") (param i32) (result i32) + (call_indirect $t1 (type 0) (local.get 0))) ) (invoke "test") -(assert_trap (invoke "check" (i32.const 0)) "uninitialized element") -(assert_trap (invoke "check" (i32.const 1)) "uninitialized element") -(assert_return (invoke "check" (i32.const 2)) (i32.const 3)) -(assert_return (invoke "check" (i32.const 3)) (i32.const 1)) -(assert_return (invoke "check" (i32.const 4)) (i32.const 4)) -(assert_return (invoke "check" (i32.const 5)) (i32.const 1)) -(assert_trap (invoke "check" (i32.const 6)) "uninitialized element") -(assert_trap (invoke "check" (i32.const 7)) "uninitialized element") -(assert_trap (invoke "check" (i32.const 8)) "uninitialized element") -(assert_trap (invoke "check" (i32.const 9)) "uninitialized element") -(assert_return (invoke "check" (i32.const 10)) (i32.const 7)) -(assert_return (invoke "check" (i32.const 11)) (i32.const 5)) -(assert_return (invoke "check" (i32.const 12)) (i32.const 2)) -(assert_return (invoke "check" (i32.const 13)) (i32.const 3)) -(assert_return (invoke "check" (i32.const 14)) (i32.const 6)) -(assert_trap (invoke "check" (i32.const 15)) "uninitialized element") -(assert_trap (invoke "check" (i32.const 16)) "uninitialized element") -(assert_trap (invoke "check" (i32.const 17)) "uninitialized element") -(assert_trap (invoke "check" (i32.const 18)) "uninitialized element") -(assert_trap (invoke "check" (i32.const 19)) "uninitialized element") -(assert_trap (invoke "check" (i32.const 20)) "uninitialized element") -(assert_trap (invoke "check" (i32.const 21)) "uninitialized element") -(assert_trap (invoke "check" (i32.const 22)) "uninitialized element") -(assert_trap (invoke "check" (i32.const 23)) "uninitialized element") -(assert_trap (invoke "check" (i32.const 24)) "uninitialized element") -(assert_trap (invoke "check" (i32.const 25)) "uninitialized element") -(assert_trap (invoke "check" (i32.const 26)) "uninitialized element") -(assert_trap (invoke "check" (i32.const 27)) "uninitialized element") -(assert_trap (invoke "check" (i32.const 28)) "uninitialized element") -(assert_trap (invoke "check" (i32.const 29)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 0)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 1)) "uninitialized element") +(assert_return (invoke "check_t0" (i32.const 2)) (i32.const 3)) +(assert_return (invoke "check_t0" (i32.const 3)) (i32.const 1)) +(assert_return (invoke "check_t0" (i32.const 4)) (i32.const 4)) +(assert_return (invoke "check_t0" (i32.const 5)) (i32.const 1)) +(assert_trap (invoke "check_t0" (i32.const 6)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 7)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 8)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 9)) "uninitialized element") +(assert_return (invoke "check_t0" (i32.const 10)) (i32.const 7)) +(assert_return (invoke "check_t0" (i32.const 11)) (i32.const 5)) +(assert_return (invoke "check_t0" (i32.const 12)) (i32.const 2)) +(assert_return (invoke "check_t0" (i32.const 13)) (i32.const 3)) +(assert_return (invoke "check_t0" (i32.const 14)) (i32.const 6)) +(assert_trap (invoke "check_t0" (i32.const 15)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 16)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 17)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 18)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 19)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 20)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 21)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 22)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 23)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 24)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 25)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 26)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 27)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 28)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 29)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 0)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 1)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 2)) "uninitialized element") +(assert_return (invoke "check_t1" (i32.const 3)) (i32.const 1)) +(assert_return (invoke "check_t1" (i32.const 4)) (i32.const 3)) +(assert_return (invoke "check_t1" (i32.const 5)) (i32.const 1)) +(assert_return (invoke "check_t1" (i32.const 6)) (i32.const 4)) +(assert_trap (invoke "check_t1" (i32.const 7)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 8)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 9)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 10)) "uninitialized element") +(assert_return (invoke "check_t1" (i32.const 11)) (i32.const 6)) +(assert_return (invoke "check_t1" (i32.const 12)) (i32.const 3)) +(assert_return (invoke "check_t1" (i32.const 13)) (i32.const 2)) +(assert_return (invoke "check_t1" (i32.const 14)) (i32.const 5)) +(assert_return (invoke "check_t1" (i32.const 15)) (i32.const 7)) +(assert_trap (invoke "check_t1" (i32.const 16)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 17)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 18)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 19)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 20)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 21)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 22)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 23)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 24)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 25)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 26)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 27)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 28)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 29)) "uninitialized element") (module (type (func (result i32))) ;; type #0 @@ -417,62 +663,1293 @@ (import "a" "ef2" (func (result i32))) (import "a" "ef3" (func (result i32))) (import "a" "ef4" (func (result i32))) ;; index 4 - (table 30 30 funcref) - (elem (i32.const 2) 3 1 4 1) + (table $t0 30 30 funcref) + (table $t1 30 30 funcref) + (elem (table $t0) (i32.const 2) func 3 1 4 1) (elem funcref (ref.func 2) (ref.func 7) (ref.func 1) (ref.func 8)) - (elem (i32.const 12) 7 5 2 3 6) + (elem (table $t0) (i32.const 12) func 7 5 2 3 6) (elem funcref (ref.func 5) (ref.func 9) (ref.func 2) (ref.func 7) (ref.func 6)) + (elem (table $t1) (i32.const 3) func 1 3 1 4) + (elem (table $t1) (i32.const 11) func 6 3 2 5 7) (func (result i32) (i32.const 5)) ;; index 5 (func (result i32) (i32.const 6)) (func (result i32) (i32.const 7)) (func (result i32) (i32.const 8)) (func (result i32) (i32.const 9)) ;; index 9 (func (export "test") - (table.copy (i32.const 12) (i32.const 10) (i32.const 7))) - (func (export "check") (param i32) (result i32) - (call_indirect (type 0) (local.get 0))) + (table.copy $t0 $t0 (i32.const 12) (i32.const 10) (i32.const 7))) + (func (export "check_t0") (param i32) (result i32) + (call_indirect $t0 (type 0) (local.get 0))) + (func (export "check_t1") (param i32) (result i32) + (call_indirect $t1 (type 0) (local.get 0))) ) (invoke "test") -(assert_trap (invoke "check" (i32.const 0)) "uninitialized element") -(assert_trap (invoke "check" (i32.const 1)) "uninitialized element") -(assert_return (invoke "check" (i32.const 2)) (i32.const 3)) -(assert_return (invoke "check" (i32.const 3)) (i32.const 1)) -(assert_return (invoke "check" (i32.const 4)) (i32.const 4)) -(assert_return (invoke "check" (i32.const 5)) (i32.const 1)) -(assert_trap (invoke "check" (i32.const 6)) "uninitialized element") -(assert_trap (invoke "check" (i32.const 7)) "uninitialized element") -(assert_trap (invoke "check" (i32.const 8)) "uninitialized element") -(assert_trap (invoke "check" (i32.const 9)) "uninitialized element") -(assert_trap (invoke "check" (i32.const 10)) "uninitialized element") -(assert_trap (invoke "check" (i32.const 11)) "uninitialized element") -(assert_trap (invoke "check" (i32.const 12)) "uninitialized element") -(assert_trap (invoke "check" (i32.const 13)) "uninitialized element") -(assert_return (invoke "check" (i32.const 14)) (i32.const 7)) -(assert_return (invoke "check" (i32.const 15)) (i32.const 5)) -(assert_return (invoke "check" (i32.const 16)) (i32.const 2)) -(assert_return (invoke "check" (i32.const 17)) (i32.const 3)) -(assert_return (invoke "check" (i32.const 18)) (i32.const 6)) -(assert_trap (invoke "check" (i32.const 19)) "uninitialized element") -(assert_trap (invoke "check" (i32.const 20)) "uninitialized element") -(assert_trap (invoke "check" (i32.const 21)) "uninitialized element") -(assert_trap (invoke "check" (i32.const 22)) "uninitialized element") -(assert_trap (invoke "check" (i32.const 23)) "uninitialized element") -(assert_trap (invoke "check" (i32.const 24)) "uninitialized element") -(assert_trap (invoke "check" (i32.const 25)) "uninitialized element") -(assert_trap (invoke "check" (i32.const 26)) "uninitialized element") -(assert_trap (invoke "check" (i32.const 27)) "uninitialized element") -(assert_trap (invoke "check" (i32.const 28)) "uninitialized element") -(assert_trap (invoke "check" (i32.const 29)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 0)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 1)) "uninitialized element") +(assert_return (invoke "check_t0" (i32.const 2)) (i32.const 3)) +(assert_return (invoke "check_t0" (i32.const 3)) (i32.const 1)) +(assert_return (invoke "check_t0" (i32.const 4)) (i32.const 4)) +(assert_return (invoke "check_t0" (i32.const 5)) (i32.const 1)) +(assert_trap (invoke "check_t0" (i32.const 6)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 7)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 8)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 9)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 10)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 11)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 12)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 13)) "uninitialized element") +(assert_return (invoke "check_t0" (i32.const 14)) (i32.const 7)) +(assert_return (invoke "check_t0" (i32.const 15)) (i32.const 5)) +(assert_return (invoke "check_t0" (i32.const 16)) (i32.const 2)) +(assert_return (invoke "check_t0" (i32.const 17)) (i32.const 3)) +(assert_return (invoke "check_t0" (i32.const 18)) (i32.const 6)) +(assert_trap (invoke "check_t0" (i32.const 19)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 20)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 21)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 22)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 23)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 24)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 25)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 26)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 27)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 28)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 29)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 0)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 1)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 2)) "uninitialized element") +(assert_return (invoke "check_t1" (i32.const 3)) (i32.const 1)) +(assert_return (invoke "check_t1" (i32.const 4)) (i32.const 3)) +(assert_return (invoke "check_t1" (i32.const 5)) (i32.const 1)) +(assert_return (invoke "check_t1" (i32.const 6)) (i32.const 4)) +(assert_trap (invoke "check_t1" (i32.const 7)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 8)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 9)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 10)) "uninitialized element") +(assert_return (invoke "check_t1" (i32.const 11)) (i32.const 6)) +(assert_return (invoke "check_t1" (i32.const 12)) (i32.const 3)) +(assert_return (invoke "check_t1" (i32.const 13)) (i32.const 2)) +(assert_return (invoke "check_t1" (i32.const 14)) (i32.const 5)) +(assert_return (invoke "check_t1" (i32.const 15)) (i32.const 7)) +(assert_trap (invoke "check_t1" (i32.const 16)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 17)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 18)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 19)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 20)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 21)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 22)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 23)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 24)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 25)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 26)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 27)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 28)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 29)) "uninitialized element") (module - (table 30 30 funcref) - (elem (i32.const 2) 3 1 4 1) + (type (func (result i32))) ;; type #0 + (import "a" "ef0" (func (result i32))) ;; index 0 + (import "a" "ef1" (func (result i32))) + (import "a" "ef2" (func (result i32))) + (import "a" "ef3" (func (result i32))) + (import "a" "ef4" (func (result i32))) ;; index 4 + (table $t0 30 30 funcref) + (table $t1 30 30 funcref) + (elem (table $t0) (i32.const 2) func 3 1 4 1) + (elem funcref + (ref.func 2) (ref.func 7) (ref.func 1) (ref.func 8)) + (elem (table $t0) (i32.const 12) func 7 5 2 3 6) + (elem funcref + (ref.func 5) (ref.func 9) (ref.func 2) (ref.func 7) (ref.func 6)) + (elem (table $t1) (i32.const 3) func 1 3 1 4) + (elem (table $t1) (i32.const 11) func 6 3 2 5 7) + (func (result i32) (i32.const 5)) ;; index 5 + (func (result i32) (i32.const 6)) + (func (result i32) (i32.const 7)) + (func (result i32) (i32.const 8)) + (func (result i32) (i32.const 9)) ;; index 9 + (func (export "test") + (table.copy $t1 $t0 (i32.const 10) (i32.const 0) (i32.const 20))) + (func (export "check_t0") (param i32) (result i32) + (call_indirect $t0 (type 0) (local.get 0))) + (func (export "check_t1") (param i32) (result i32) + (call_indirect $t1 (type 0) (local.get 0))) +) + +(invoke "test") +(assert_trap (invoke "check_t0" (i32.const 0)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 1)) "uninitialized element") +(assert_return (invoke "check_t0" (i32.const 2)) (i32.const 3)) +(assert_return (invoke "check_t0" (i32.const 3)) (i32.const 1)) +(assert_return (invoke "check_t0" (i32.const 4)) (i32.const 4)) +(assert_return (invoke "check_t0" (i32.const 5)) (i32.const 1)) +(assert_trap (invoke "check_t0" (i32.const 6)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 7)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 8)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 9)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 10)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 11)) "uninitialized element") +(assert_return (invoke "check_t0" (i32.const 12)) (i32.const 7)) +(assert_return (invoke "check_t0" (i32.const 13)) (i32.const 5)) +(assert_return (invoke "check_t0" (i32.const 14)) (i32.const 2)) +(assert_return (invoke "check_t0" (i32.const 15)) (i32.const 3)) +(assert_return (invoke "check_t0" (i32.const 16)) (i32.const 6)) +(assert_trap (invoke "check_t0" (i32.const 17)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 18)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 19)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 20)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 21)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 22)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 23)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 24)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 25)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 26)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 27)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 28)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 29)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 0)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 1)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 2)) "uninitialized element") +(assert_return (invoke "check_t1" (i32.const 3)) (i32.const 1)) +(assert_return (invoke "check_t1" (i32.const 4)) (i32.const 3)) +(assert_return (invoke "check_t1" (i32.const 5)) (i32.const 1)) +(assert_return (invoke "check_t1" (i32.const 6)) (i32.const 4)) +(assert_trap (invoke "check_t1" (i32.const 7)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 8)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 9)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 10)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 11)) "uninitialized element") +(assert_return (invoke "check_t1" (i32.const 12)) (i32.const 3)) +(assert_return (invoke "check_t1" (i32.const 13)) (i32.const 1)) +(assert_return (invoke "check_t1" (i32.const 14)) (i32.const 4)) +(assert_return (invoke "check_t1" (i32.const 15)) (i32.const 1)) +(assert_trap (invoke "check_t1" (i32.const 16)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 17)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 18)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 19)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 20)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 21)) "uninitialized element") +(assert_return (invoke "check_t1" (i32.const 22)) (i32.const 7)) +(assert_return (invoke "check_t1" (i32.const 23)) (i32.const 5)) +(assert_return (invoke "check_t1" (i32.const 24)) (i32.const 2)) +(assert_return (invoke "check_t1" (i32.const 25)) (i32.const 3)) +(assert_return (invoke "check_t1" (i32.const 26)) (i32.const 6)) +(assert_trap (invoke "check_t1" (i32.const 27)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 28)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 29)) "uninitialized element") + +(module + (type (func (result i32))) ;; type #0 + (import "a" "ef0" (func (result i32))) ;; index 0 + (import "a" "ef1" (func (result i32))) + (import "a" "ef2" (func (result i32))) + (import "a" "ef3" (func (result i32))) + (import "a" "ef4" (func (result i32))) ;; index 4 + (table $t0 30 30 funcref) + (table $t1 30 30 funcref) + (elem (table $t1) (i32.const 2) func 3 1 4 1) + (elem funcref + (ref.func 2) (ref.func 7) (ref.func 1) (ref.func 8)) + (elem (table $t1) (i32.const 12) func 7 5 2 3 6) + (elem funcref + (ref.func 5) (ref.func 9) (ref.func 2) (ref.func 7) (ref.func 6)) + (elem (table $t0) (i32.const 3) func 1 3 1 4) + (elem (table $t0) (i32.const 11) func 6 3 2 5 7) + (func (result i32) (i32.const 5)) ;; index 5 + (func (result i32) (i32.const 6)) + (func (result i32) (i32.const 7)) + (func (result i32) (i32.const 8)) + (func (result i32) (i32.const 9)) ;; index 9 + (func (export "test") + (nop)) + (func (export "check_t0") (param i32) (result i32) + (call_indirect $t1 (type 0) (local.get 0))) + (func (export "check_t1") (param i32) (result i32) + (call_indirect $t0 (type 0) (local.get 0))) +) + +(invoke "test") +(assert_trap (invoke "check_t0" (i32.const 0)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 1)) "uninitialized element") +(assert_return (invoke "check_t0" (i32.const 2)) (i32.const 3)) +(assert_return (invoke "check_t0" (i32.const 3)) (i32.const 1)) +(assert_return (invoke "check_t0" (i32.const 4)) (i32.const 4)) +(assert_return (invoke "check_t0" (i32.const 5)) (i32.const 1)) +(assert_trap (invoke "check_t0" (i32.const 6)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 7)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 8)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 9)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 10)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 11)) "uninitialized element") +(assert_return (invoke "check_t0" (i32.const 12)) (i32.const 7)) +(assert_return (invoke "check_t0" (i32.const 13)) (i32.const 5)) +(assert_return (invoke "check_t0" (i32.const 14)) (i32.const 2)) +(assert_return (invoke "check_t0" (i32.const 15)) (i32.const 3)) +(assert_return (invoke "check_t0" (i32.const 16)) (i32.const 6)) +(assert_trap (invoke "check_t0" (i32.const 17)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 18)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 19)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 20)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 21)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 22)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 23)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 24)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 25)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 26)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 27)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 28)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 29)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 0)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 1)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 2)) "uninitialized element") +(assert_return (invoke "check_t1" (i32.const 3)) (i32.const 1)) +(assert_return (invoke "check_t1" (i32.const 4)) (i32.const 3)) +(assert_return (invoke "check_t1" (i32.const 5)) (i32.const 1)) +(assert_return (invoke "check_t1" (i32.const 6)) (i32.const 4)) +(assert_trap (invoke "check_t1" (i32.const 7)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 8)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 9)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 10)) "uninitialized element") +(assert_return (invoke "check_t1" (i32.const 11)) (i32.const 6)) +(assert_return (invoke "check_t1" (i32.const 12)) (i32.const 3)) +(assert_return (invoke "check_t1" (i32.const 13)) (i32.const 2)) +(assert_return (invoke "check_t1" (i32.const 14)) (i32.const 5)) +(assert_return (invoke "check_t1" (i32.const 15)) (i32.const 7)) +(assert_trap (invoke "check_t1" (i32.const 16)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 17)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 18)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 19)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 20)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 21)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 22)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 23)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 24)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 25)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 26)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 27)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 28)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 29)) "uninitialized element") + +(module + (type (func (result i32))) ;; type #0 + (import "a" "ef0" (func (result i32))) ;; index 0 + (import "a" "ef1" (func (result i32))) + (import "a" "ef2" (func (result i32))) + (import "a" "ef3" (func (result i32))) + (import "a" "ef4" (func (result i32))) ;; index 4 + (table $t0 30 30 funcref) + (table $t1 30 30 funcref) + (elem (table $t1) (i32.const 2) func 3 1 4 1) + (elem funcref + (ref.func 2) (ref.func 7) (ref.func 1) (ref.func 8)) + (elem (table $t1) (i32.const 12) func 7 5 2 3 6) + (elem funcref + (ref.func 5) (ref.func 9) (ref.func 2) (ref.func 7) (ref.func 6)) + (elem (table $t0) (i32.const 3) func 1 3 1 4) + (elem (table $t0) (i32.const 11) func 6 3 2 5 7) + (func (result i32) (i32.const 5)) ;; index 5 + (func (result i32) (i32.const 6)) + (func (result i32) (i32.const 7)) + (func (result i32) (i32.const 8)) + (func (result i32) (i32.const 9)) ;; index 9 + (func (export "test") + (table.copy $t1 $t1 (i32.const 13) (i32.const 2) (i32.const 3))) + (func (export "check_t0") (param i32) (result i32) + (call_indirect $t1 (type 0) (local.get 0))) + (func (export "check_t1") (param i32) (result i32) + (call_indirect $t0 (type 0) (local.get 0))) +) + +(invoke "test") +(assert_trap (invoke "check_t0" (i32.const 0)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 1)) "uninitialized element") +(assert_return (invoke "check_t0" (i32.const 2)) (i32.const 3)) +(assert_return (invoke "check_t0" (i32.const 3)) (i32.const 1)) +(assert_return (invoke "check_t0" (i32.const 4)) (i32.const 4)) +(assert_return (invoke "check_t0" (i32.const 5)) (i32.const 1)) +(assert_trap (invoke "check_t0" (i32.const 6)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 7)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 8)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 9)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 10)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 11)) "uninitialized element") +(assert_return (invoke "check_t0" (i32.const 12)) (i32.const 7)) +(assert_return (invoke "check_t0" (i32.const 13)) (i32.const 3)) +(assert_return (invoke "check_t0" (i32.const 14)) (i32.const 1)) +(assert_return (invoke "check_t0" (i32.const 15)) (i32.const 4)) +(assert_return (invoke "check_t0" (i32.const 16)) (i32.const 6)) +(assert_trap (invoke "check_t0" (i32.const 17)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 18)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 19)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 20)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 21)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 22)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 23)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 24)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 25)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 26)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 27)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 28)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 29)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 0)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 1)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 2)) "uninitialized element") +(assert_return (invoke "check_t1" (i32.const 3)) (i32.const 1)) +(assert_return (invoke "check_t1" (i32.const 4)) (i32.const 3)) +(assert_return (invoke "check_t1" (i32.const 5)) (i32.const 1)) +(assert_return (invoke "check_t1" (i32.const 6)) (i32.const 4)) +(assert_trap (invoke "check_t1" (i32.const 7)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 8)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 9)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 10)) "uninitialized element") +(assert_return (invoke "check_t1" (i32.const 11)) (i32.const 6)) +(assert_return (invoke "check_t1" (i32.const 12)) (i32.const 3)) +(assert_return (invoke "check_t1" (i32.const 13)) (i32.const 2)) +(assert_return (invoke "check_t1" (i32.const 14)) (i32.const 5)) +(assert_return (invoke "check_t1" (i32.const 15)) (i32.const 7)) +(assert_trap (invoke "check_t1" (i32.const 16)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 17)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 18)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 19)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 20)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 21)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 22)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 23)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 24)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 25)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 26)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 27)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 28)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 29)) "uninitialized element") + +(module + (type (func (result i32))) ;; type #0 + (import "a" "ef0" (func (result i32))) ;; index 0 + (import "a" "ef1" (func (result i32))) + (import "a" "ef2" (func (result i32))) + (import "a" "ef3" (func (result i32))) + (import "a" "ef4" (func (result i32))) ;; index 4 + (table $t0 30 30 funcref) + (table $t1 30 30 funcref) + (elem (table $t1) (i32.const 2) func 3 1 4 1) + (elem funcref + (ref.func 2) (ref.func 7) (ref.func 1) (ref.func 8)) + (elem (table $t1) (i32.const 12) func 7 5 2 3 6) + (elem funcref + (ref.func 5) (ref.func 9) (ref.func 2) (ref.func 7) (ref.func 6)) + (elem (table $t0) (i32.const 3) func 1 3 1 4) + (elem (table $t0) (i32.const 11) func 6 3 2 5 7) + (func (result i32) (i32.const 5)) ;; index 5 + (func (result i32) (i32.const 6)) + (func (result i32) (i32.const 7)) + (func (result i32) (i32.const 8)) + (func (result i32) (i32.const 9)) ;; index 9 + (func (export "test") + (table.copy $t1 $t1 (i32.const 25) (i32.const 15) (i32.const 2))) + (func (export "check_t0") (param i32) (result i32) + (call_indirect $t1 (type 0) (local.get 0))) + (func (export "check_t1") (param i32) (result i32) + (call_indirect $t0 (type 0) (local.get 0))) +) + +(invoke "test") +(assert_trap (invoke "check_t0" (i32.const 0)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 1)) "uninitialized element") +(assert_return (invoke "check_t0" (i32.const 2)) (i32.const 3)) +(assert_return (invoke "check_t0" (i32.const 3)) (i32.const 1)) +(assert_return (invoke "check_t0" (i32.const 4)) (i32.const 4)) +(assert_return (invoke "check_t0" (i32.const 5)) (i32.const 1)) +(assert_trap (invoke "check_t0" (i32.const 6)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 7)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 8)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 9)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 10)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 11)) "uninitialized element") +(assert_return (invoke "check_t0" (i32.const 12)) (i32.const 7)) +(assert_return (invoke "check_t0" (i32.const 13)) (i32.const 5)) +(assert_return (invoke "check_t0" (i32.const 14)) (i32.const 2)) +(assert_return (invoke "check_t0" (i32.const 15)) (i32.const 3)) +(assert_return (invoke "check_t0" (i32.const 16)) (i32.const 6)) +(assert_trap (invoke "check_t0" (i32.const 17)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 18)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 19)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 20)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 21)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 22)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 23)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 24)) "uninitialized element") +(assert_return (invoke "check_t0" (i32.const 25)) (i32.const 3)) +(assert_return (invoke "check_t0" (i32.const 26)) (i32.const 6)) +(assert_trap (invoke "check_t0" (i32.const 27)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 28)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 29)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 0)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 1)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 2)) "uninitialized element") +(assert_return (invoke "check_t1" (i32.const 3)) (i32.const 1)) +(assert_return (invoke "check_t1" (i32.const 4)) (i32.const 3)) +(assert_return (invoke "check_t1" (i32.const 5)) (i32.const 1)) +(assert_return (invoke "check_t1" (i32.const 6)) (i32.const 4)) +(assert_trap (invoke "check_t1" (i32.const 7)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 8)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 9)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 10)) "uninitialized element") +(assert_return (invoke "check_t1" (i32.const 11)) (i32.const 6)) +(assert_return (invoke "check_t1" (i32.const 12)) (i32.const 3)) +(assert_return (invoke "check_t1" (i32.const 13)) (i32.const 2)) +(assert_return (invoke "check_t1" (i32.const 14)) (i32.const 5)) +(assert_return (invoke "check_t1" (i32.const 15)) (i32.const 7)) +(assert_trap (invoke "check_t1" (i32.const 16)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 17)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 18)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 19)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 20)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 21)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 22)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 23)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 24)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 25)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 26)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 27)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 28)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 29)) "uninitialized element") + +(module + (type (func (result i32))) ;; type #0 + (import "a" "ef0" (func (result i32))) ;; index 0 + (import "a" "ef1" (func (result i32))) + (import "a" "ef2" (func (result i32))) + (import "a" "ef3" (func (result i32))) + (import "a" "ef4" (func (result i32))) ;; index 4 + (table $t0 30 30 funcref) + (table $t1 30 30 funcref) + (elem (table $t1) (i32.const 2) func 3 1 4 1) + (elem funcref + (ref.func 2) (ref.func 7) (ref.func 1) (ref.func 8)) + (elem (table $t1) (i32.const 12) func 7 5 2 3 6) + (elem funcref + (ref.func 5) (ref.func 9) (ref.func 2) (ref.func 7) (ref.func 6)) + (elem (table $t0) (i32.const 3) func 1 3 1 4) + (elem (table $t0) (i32.const 11) func 6 3 2 5 7) + (func (result i32) (i32.const 5)) ;; index 5 + (func (result i32) (i32.const 6)) + (func (result i32) (i32.const 7)) + (func (result i32) (i32.const 8)) + (func (result i32) (i32.const 9)) ;; index 9 + (func (export "test") + (table.copy $t1 $t1 (i32.const 13) (i32.const 25) (i32.const 3))) + (func (export "check_t0") (param i32) (result i32) + (call_indirect $t1 (type 0) (local.get 0))) + (func (export "check_t1") (param i32) (result i32) + (call_indirect $t0 (type 0) (local.get 0))) +) + +(invoke "test") +(assert_trap (invoke "check_t0" (i32.const 0)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 1)) "uninitialized element") +(assert_return (invoke "check_t0" (i32.const 2)) (i32.const 3)) +(assert_return (invoke "check_t0" (i32.const 3)) (i32.const 1)) +(assert_return (invoke "check_t0" (i32.const 4)) (i32.const 4)) +(assert_return (invoke "check_t0" (i32.const 5)) (i32.const 1)) +(assert_trap (invoke "check_t0" (i32.const 6)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 7)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 8)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 9)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 10)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 11)) "uninitialized element") +(assert_return (invoke "check_t0" (i32.const 12)) (i32.const 7)) +(assert_trap (invoke "check_t0" (i32.const 13)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 14)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 15)) "uninitialized element") +(assert_return (invoke "check_t0" (i32.const 16)) (i32.const 6)) +(assert_trap (invoke "check_t0" (i32.const 17)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 18)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 19)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 20)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 21)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 22)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 23)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 24)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 25)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 26)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 27)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 28)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 29)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 0)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 1)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 2)) "uninitialized element") +(assert_return (invoke "check_t1" (i32.const 3)) (i32.const 1)) +(assert_return (invoke "check_t1" (i32.const 4)) (i32.const 3)) +(assert_return (invoke "check_t1" (i32.const 5)) (i32.const 1)) +(assert_return (invoke "check_t1" (i32.const 6)) (i32.const 4)) +(assert_trap (invoke "check_t1" (i32.const 7)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 8)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 9)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 10)) "uninitialized element") +(assert_return (invoke "check_t1" (i32.const 11)) (i32.const 6)) +(assert_return (invoke "check_t1" (i32.const 12)) (i32.const 3)) +(assert_return (invoke "check_t1" (i32.const 13)) (i32.const 2)) +(assert_return (invoke "check_t1" (i32.const 14)) (i32.const 5)) +(assert_return (invoke "check_t1" (i32.const 15)) (i32.const 7)) +(assert_trap (invoke "check_t1" (i32.const 16)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 17)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 18)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 19)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 20)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 21)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 22)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 23)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 24)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 25)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 26)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 27)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 28)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 29)) "uninitialized element") + +(module + (type (func (result i32))) ;; type #0 + (import "a" "ef0" (func (result i32))) ;; index 0 + (import "a" "ef1" (func (result i32))) + (import "a" "ef2" (func (result i32))) + (import "a" "ef3" (func (result i32))) + (import "a" "ef4" (func (result i32))) ;; index 4 + (table $t0 30 30 funcref) + (table $t1 30 30 funcref) + (elem (table $t1) (i32.const 2) func 3 1 4 1) + (elem funcref + (ref.func 2) (ref.func 7) (ref.func 1) (ref.func 8)) + (elem (table $t1) (i32.const 12) func 7 5 2 3 6) + (elem funcref + (ref.func 5) (ref.func 9) (ref.func 2) (ref.func 7) (ref.func 6)) + (elem (table $t0) (i32.const 3) func 1 3 1 4) + (elem (table $t0) (i32.const 11) func 6 3 2 5 7) + (func (result i32) (i32.const 5)) ;; index 5 + (func (result i32) (i32.const 6)) + (func (result i32) (i32.const 7)) + (func (result i32) (i32.const 8)) + (func (result i32) (i32.const 9)) ;; index 9 + (func (export "test") + (table.copy $t1 $t1 (i32.const 20) (i32.const 22) (i32.const 4))) + (func (export "check_t0") (param i32) (result i32) + (call_indirect $t1 (type 0) (local.get 0))) + (func (export "check_t1") (param i32) (result i32) + (call_indirect $t0 (type 0) (local.get 0))) +) + +(invoke "test") +(assert_trap (invoke "check_t0" (i32.const 0)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 1)) "uninitialized element") +(assert_return (invoke "check_t0" (i32.const 2)) (i32.const 3)) +(assert_return (invoke "check_t0" (i32.const 3)) (i32.const 1)) +(assert_return (invoke "check_t0" (i32.const 4)) (i32.const 4)) +(assert_return (invoke "check_t0" (i32.const 5)) (i32.const 1)) +(assert_trap (invoke "check_t0" (i32.const 6)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 7)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 8)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 9)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 10)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 11)) "uninitialized element") +(assert_return (invoke "check_t0" (i32.const 12)) (i32.const 7)) +(assert_return (invoke "check_t0" (i32.const 13)) (i32.const 5)) +(assert_return (invoke "check_t0" (i32.const 14)) (i32.const 2)) +(assert_return (invoke "check_t0" (i32.const 15)) (i32.const 3)) +(assert_return (invoke "check_t0" (i32.const 16)) (i32.const 6)) +(assert_trap (invoke "check_t0" (i32.const 17)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 18)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 19)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 20)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 21)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 22)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 23)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 24)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 25)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 26)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 27)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 28)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 29)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 0)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 1)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 2)) "uninitialized element") +(assert_return (invoke "check_t1" (i32.const 3)) (i32.const 1)) +(assert_return (invoke "check_t1" (i32.const 4)) (i32.const 3)) +(assert_return (invoke "check_t1" (i32.const 5)) (i32.const 1)) +(assert_return (invoke "check_t1" (i32.const 6)) (i32.const 4)) +(assert_trap (invoke "check_t1" (i32.const 7)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 8)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 9)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 10)) "uninitialized element") +(assert_return (invoke "check_t1" (i32.const 11)) (i32.const 6)) +(assert_return (invoke "check_t1" (i32.const 12)) (i32.const 3)) +(assert_return (invoke "check_t1" (i32.const 13)) (i32.const 2)) +(assert_return (invoke "check_t1" (i32.const 14)) (i32.const 5)) +(assert_return (invoke "check_t1" (i32.const 15)) (i32.const 7)) +(assert_trap (invoke "check_t1" (i32.const 16)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 17)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 18)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 19)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 20)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 21)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 22)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 23)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 24)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 25)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 26)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 27)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 28)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 29)) "uninitialized element") + +(module + (type (func (result i32))) ;; type #0 + (import "a" "ef0" (func (result i32))) ;; index 0 + (import "a" "ef1" (func (result i32))) + (import "a" "ef2" (func (result i32))) + (import "a" "ef3" (func (result i32))) + (import "a" "ef4" (func (result i32))) ;; index 4 + (table $t0 30 30 funcref) + (table $t1 30 30 funcref) + (elem (table $t1) (i32.const 2) func 3 1 4 1) + (elem funcref + (ref.func 2) (ref.func 7) (ref.func 1) (ref.func 8)) + (elem (table $t1) (i32.const 12) func 7 5 2 3 6) + (elem funcref + (ref.func 5) (ref.func 9) (ref.func 2) (ref.func 7) (ref.func 6)) + (elem (table $t0) (i32.const 3) func 1 3 1 4) + (elem (table $t0) (i32.const 11) func 6 3 2 5 7) + (func (result i32) (i32.const 5)) ;; index 5 + (func (result i32) (i32.const 6)) + (func (result i32) (i32.const 7)) + (func (result i32) (i32.const 8)) + (func (result i32) (i32.const 9)) ;; index 9 + (func (export "test") + (table.copy $t1 $t1 (i32.const 25) (i32.const 1) (i32.const 3))) + (func (export "check_t0") (param i32) (result i32) + (call_indirect $t1 (type 0) (local.get 0))) + (func (export "check_t1") (param i32) (result i32) + (call_indirect $t0 (type 0) (local.get 0))) +) + +(invoke "test") +(assert_trap (invoke "check_t0" (i32.const 0)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 1)) "uninitialized element") +(assert_return (invoke "check_t0" (i32.const 2)) (i32.const 3)) +(assert_return (invoke "check_t0" (i32.const 3)) (i32.const 1)) +(assert_return (invoke "check_t0" (i32.const 4)) (i32.const 4)) +(assert_return (invoke "check_t0" (i32.const 5)) (i32.const 1)) +(assert_trap (invoke "check_t0" (i32.const 6)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 7)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 8)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 9)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 10)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 11)) "uninitialized element") +(assert_return (invoke "check_t0" (i32.const 12)) (i32.const 7)) +(assert_return (invoke "check_t0" (i32.const 13)) (i32.const 5)) +(assert_return (invoke "check_t0" (i32.const 14)) (i32.const 2)) +(assert_return (invoke "check_t0" (i32.const 15)) (i32.const 3)) +(assert_return (invoke "check_t0" (i32.const 16)) (i32.const 6)) +(assert_trap (invoke "check_t0" (i32.const 17)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 18)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 19)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 20)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 21)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 22)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 23)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 24)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 25)) "uninitialized element") +(assert_return (invoke "check_t0" (i32.const 26)) (i32.const 3)) +(assert_return (invoke "check_t0" (i32.const 27)) (i32.const 1)) +(assert_trap (invoke "check_t0" (i32.const 28)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 29)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 0)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 1)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 2)) "uninitialized element") +(assert_return (invoke "check_t1" (i32.const 3)) (i32.const 1)) +(assert_return (invoke "check_t1" (i32.const 4)) (i32.const 3)) +(assert_return (invoke "check_t1" (i32.const 5)) (i32.const 1)) +(assert_return (invoke "check_t1" (i32.const 6)) (i32.const 4)) +(assert_trap (invoke "check_t1" (i32.const 7)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 8)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 9)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 10)) "uninitialized element") +(assert_return (invoke "check_t1" (i32.const 11)) (i32.const 6)) +(assert_return (invoke "check_t1" (i32.const 12)) (i32.const 3)) +(assert_return (invoke "check_t1" (i32.const 13)) (i32.const 2)) +(assert_return (invoke "check_t1" (i32.const 14)) (i32.const 5)) +(assert_return (invoke "check_t1" (i32.const 15)) (i32.const 7)) +(assert_trap (invoke "check_t1" (i32.const 16)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 17)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 18)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 19)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 20)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 21)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 22)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 23)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 24)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 25)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 26)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 27)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 28)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 29)) "uninitialized element") + +(module + (type (func (result i32))) ;; type #0 + (import "a" "ef0" (func (result i32))) ;; index 0 + (import "a" "ef1" (func (result i32))) + (import "a" "ef2" (func (result i32))) + (import "a" "ef3" (func (result i32))) + (import "a" "ef4" (func (result i32))) ;; index 4 + (table $t0 30 30 funcref) + (table $t1 30 30 funcref) + (elem (table $t1) (i32.const 2) func 3 1 4 1) + (elem funcref + (ref.func 2) (ref.func 7) (ref.func 1) (ref.func 8)) + (elem (table $t1) (i32.const 12) func 7 5 2 3 6) + (elem funcref + (ref.func 5) (ref.func 9) (ref.func 2) (ref.func 7) (ref.func 6)) + (elem (table $t0) (i32.const 3) func 1 3 1 4) + (elem (table $t0) (i32.const 11) func 6 3 2 5 7) + (func (result i32) (i32.const 5)) ;; index 5 + (func (result i32) (i32.const 6)) + (func (result i32) (i32.const 7)) + (func (result i32) (i32.const 8)) + (func (result i32) (i32.const 9)) ;; index 9 + (func (export "test") + (table.copy $t1 $t1 (i32.const 10) (i32.const 12) (i32.const 7))) + (func (export "check_t0") (param i32) (result i32) + (call_indirect $t1 (type 0) (local.get 0))) + (func (export "check_t1") (param i32) (result i32) + (call_indirect $t0 (type 0) (local.get 0))) +) + +(invoke "test") +(assert_trap (invoke "check_t0" (i32.const 0)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 1)) "uninitialized element") +(assert_return (invoke "check_t0" (i32.const 2)) (i32.const 3)) +(assert_return (invoke "check_t0" (i32.const 3)) (i32.const 1)) +(assert_return (invoke "check_t0" (i32.const 4)) (i32.const 4)) +(assert_return (invoke "check_t0" (i32.const 5)) (i32.const 1)) +(assert_trap (invoke "check_t0" (i32.const 6)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 7)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 8)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 9)) "uninitialized element") +(assert_return (invoke "check_t0" (i32.const 10)) (i32.const 7)) +(assert_return (invoke "check_t0" (i32.const 11)) (i32.const 5)) +(assert_return (invoke "check_t0" (i32.const 12)) (i32.const 2)) +(assert_return (invoke "check_t0" (i32.const 13)) (i32.const 3)) +(assert_return (invoke "check_t0" (i32.const 14)) (i32.const 6)) +(assert_trap (invoke "check_t0" (i32.const 15)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 16)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 17)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 18)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 19)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 20)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 21)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 22)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 23)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 24)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 25)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 26)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 27)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 28)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 29)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 0)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 1)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 2)) "uninitialized element") +(assert_return (invoke "check_t1" (i32.const 3)) (i32.const 1)) +(assert_return (invoke "check_t1" (i32.const 4)) (i32.const 3)) +(assert_return (invoke "check_t1" (i32.const 5)) (i32.const 1)) +(assert_return (invoke "check_t1" (i32.const 6)) (i32.const 4)) +(assert_trap (invoke "check_t1" (i32.const 7)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 8)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 9)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 10)) "uninitialized element") +(assert_return (invoke "check_t1" (i32.const 11)) (i32.const 6)) +(assert_return (invoke "check_t1" (i32.const 12)) (i32.const 3)) +(assert_return (invoke "check_t1" (i32.const 13)) (i32.const 2)) +(assert_return (invoke "check_t1" (i32.const 14)) (i32.const 5)) +(assert_return (invoke "check_t1" (i32.const 15)) (i32.const 7)) +(assert_trap (invoke "check_t1" (i32.const 16)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 17)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 18)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 19)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 20)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 21)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 22)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 23)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 24)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 25)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 26)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 27)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 28)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 29)) "uninitialized element") + +(module + (type (func (result i32))) ;; type #0 + (import "a" "ef0" (func (result i32))) ;; index 0 + (import "a" "ef1" (func (result i32))) + (import "a" "ef2" (func (result i32))) + (import "a" "ef3" (func (result i32))) + (import "a" "ef4" (func (result i32))) ;; index 4 + (table $t0 30 30 funcref) + (table $t1 30 30 funcref) + (elem (table $t1) (i32.const 2) func 3 1 4 1) + (elem funcref + (ref.func 2) (ref.func 7) (ref.func 1) (ref.func 8)) + (elem (table $t1) (i32.const 12) func 7 5 2 3 6) + (elem funcref + (ref.func 5) (ref.func 9) (ref.func 2) (ref.func 7) (ref.func 6)) + (elem (table $t0) (i32.const 3) func 1 3 1 4) + (elem (table $t0) (i32.const 11) func 6 3 2 5 7) + (func (result i32) (i32.const 5)) ;; index 5 + (func (result i32) (i32.const 6)) + (func (result i32) (i32.const 7)) + (func (result i32) (i32.const 8)) + (func (result i32) (i32.const 9)) ;; index 9 + (func (export "test") + (table.copy $t1 $t1 (i32.const 12) (i32.const 10) (i32.const 7))) + (func (export "check_t0") (param i32) (result i32) + (call_indirect $t1 (type 0) (local.get 0))) + (func (export "check_t1") (param i32) (result i32) + (call_indirect $t0 (type 0) (local.get 0))) +) + +(invoke "test") +(assert_trap (invoke "check_t0" (i32.const 0)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 1)) "uninitialized element") +(assert_return (invoke "check_t0" (i32.const 2)) (i32.const 3)) +(assert_return (invoke "check_t0" (i32.const 3)) (i32.const 1)) +(assert_return (invoke "check_t0" (i32.const 4)) (i32.const 4)) +(assert_return (invoke "check_t0" (i32.const 5)) (i32.const 1)) +(assert_trap (invoke "check_t0" (i32.const 6)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 7)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 8)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 9)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 10)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 11)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 12)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 13)) "uninitialized element") +(assert_return (invoke "check_t0" (i32.const 14)) (i32.const 7)) +(assert_return (invoke "check_t0" (i32.const 15)) (i32.const 5)) +(assert_return (invoke "check_t0" (i32.const 16)) (i32.const 2)) +(assert_return (invoke "check_t0" (i32.const 17)) (i32.const 3)) +(assert_return (invoke "check_t0" (i32.const 18)) (i32.const 6)) +(assert_trap (invoke "check_t0" (i32.const 19)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 20)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 21)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 22)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 23)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 24)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 25)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 26)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 27)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 28)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 29)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 0)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 1)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 2)) "uninitialized element") +(assert_return (invoke "check_t1" (i32.const 3)) (i32.const 1)) +(assert_return (invoke "check_t1" (i32.const 4)) (i32.const 3)) +(assert_return (invoke "check_t1" (i32.const 5)) (i32.const 1)) +(assert_return (invoke "check_t1" (i32.const 6)) (i32.const 4)) +(assert_trap (invoke "check_t1" (i32.const 7)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 8)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 9)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 10)) "uninitialized element") +(assert_return (invoke "check_t1" (i32.const 11)) (i32.const 6)) +(assert_return (invoke "check_t1" (i32.const 12)) (i32.const 3)) +(assert_return (invoke "check_t1" (i32.const 13)) (i32.const 2)) +(assert_return (invoke "check_t1" (i32.const 14)) (i32.const 5)) +(assert_return (invoke "check_t1" (i32.const 15)) (i32.const 7)) +(assert_trap (invoke "check_t1" (i32.const 16)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 17)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 18)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 19)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 20)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 21)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 22)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 23)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 24)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 25)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 26)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 27)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 28)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 29)) "uninitialized element") + +(module + (type (func (result i32))) ;; type #0 + (import "a" "ef0" (func (result i32))) ;; index 0 + (import "a" "ef1" (func (result i32))) + (import "a" "ef2" (func (result i32))) + (import "a" "ef3" (func (result i32))) + (import "a" "ef4" (func (result i32))) ;; index 4 + (table $t0 30 30 funcref) + (table $t1 30 30 funcref) + (elem (table $t1) (i32.const 2) func 3 1 4 1) + (elem funcref + (ref.func 2) (ref.func 7) (ref.func 1) (ref.func 8)) + (elem (table $t1) (i32.const 12) func 7 5 2 3 6) + (elem funcref + (ref.func 5) (ref.func 9) (ref.func 2) (ref.func 7) (ref.func 6)) + (elem (table $t0) (i32.const 3) func 1 3 1 4) + (elem (table $t0) (i32.const 11) func 6 3 2 5 7) + (func (result i32) (i32.const 5)) ;; index 5 + (func (result i32) (i32.const 6)) + (func (result i32) (i32.const 7)) + (func (result i32) (i32.const 8)) + (func (result i32) (i32.const 9)) ;; index 9 + (func (export "test") + (table.copy $t0 $t1 (i32.const 10) (i32.const 0) (i32.const 20))) + (func (export "check_t0") (param i32) (result i32) + (call_indirect $t1 (type 0) (local.get 0))) + (func (export "check_t1") (param i32) (result i32) + (call_indirect $t0 (type 0) (local.get 0))) +) + +(invoke "test") +(assert_trap (invoke "check_t0" (i32.const 0)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 1)) "uninitialized element") +(assert_return (invoke "check_t0" (i32.const 2)) (i32.const 3)) +(assert_return (invoke "check_t0" (i32.const 3)) (i32.const 1)) +(assert_return (invoke "check_t0" (i32.const 4)) (i32.const 4)) +(assert_return (invoke "check_t0" (i32.const 5)) (i32.const 1)) +(assert_trap (invoke "check_t0" (i32.const 6)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 7)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 8)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 9)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 10)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 11)) "uninitialized element") +(assert_return (invoke "check_t0" (i32.const 12)) (i32.const 7)) +(assert_return (invoke "check_t0" (i32.const 13)) (i32.const 5)) +(assert_return (invoke "check_t0" (i32.const 14)) (i32.const 2)) +(assert_return (invoke "check_t0" (i32.const 15)) (i32.const 3)) +(assert_return (invoke "check_t0" (i32.const 16)) (i32.const 6)) +(assert_trap (invoke "check_t0" (i32.const 17)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 18)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 19)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 20)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 21)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 22)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 23)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 24)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 25)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 26)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 27)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 28)) "uninitialized element") +(assert_trap (invoke "check_t0" (i32.const 29)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 0)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 1)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 2)) "uninitialized element") +(assert_return (invoke "check_t1" (i32.const 3)) (i32.const 1)) +(assert_return (invoke "check_t1" (i32.const 4)) (i32.const 3)) +(assert_return (invoke "check_t1" (i32.const 5)) (i32.const 1)) +(assert_return (invoke "check_t1" (i32.const 6)) (i32.const 4)) +(assert_trap (invoke "check_t1" (i32.const 7)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 8)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 9)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 10)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 11)) "uninitialized element") +(assert_return (invoke "check_t1" (i32.const 12)) (i32.const 3)) +(assert_return (invoke "check_t1" (i32.const 13)) (i32.const 1)) +(assert_return (invoke "check_t1" (i32.const 14)) (i32.const 4)) +(assert_return (invoke "check_t1" (i32.const 15)) (i32.const 1)) +(assert_trap (invoke "check_t1" (i32.const 16)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 17)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 18)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 19)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 20)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 21)) "uninitialized element") +(assert_return (invoke "check_t1" (i32.const 22)) (i32.const 7)) +(assert_return (invoke "check_t1" (i32.const 23)) (i32.const 5)) +(assert_return (invoke "check_t1" (i32.const 24)) (i32.const 2)) +(assert_return (invoke "check_t1" (i32.const 25)) (i32.const 3)) +(assert_return (invoke "check_t1" (i32.const 26)) (i32.const 6)) +(assert_trap (invoke "check_t1" (i32.const 27)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 28)) "uninitialized element") +(assert_trap (invoke "check_t1" (i32.const 29)) "uninitialized element") + +(module + (table $t0 30 30 funcref) + (table $t1 30 30 funcref) + (elem (table $t0) (i32.const 2) func 3 1 4 1) + (elem funcref + (ref.func 2) (ref.func 7) (ref.func 1) (ref.func 8)) + (elem (table $t0) (i32.const 12) func 7 5 2 3 6) + (elem funcref + (ref.func 5) (ref.func 9) (ref.func 2) (ref.func 7) (ref.func 6)) + (func (result i32) (i32.const 0)) + (func (result i32) (i32.const 1)) + (func (result i32) (i32.const 2)) + (func (result i32) (i32.const 3)) + (func (result i32) (i32.const 4)) + (func (result i32) (i32.const 5)) + (func (result i32) (i32.const 6)) + (func (result i32) (i32.const 7)) + (func (result i32) (i32.const 8)) + (func (result i32) (i32.const 9)) + (func (export "test") + (table.copy $t0 $t0 (i32.const 28) (i32.const 1) (i32.const 3)) + )) + +(assert_trap (invoke "test") "out of bounds") + +(module + (table $t0 30 30 funcref) + (table $t1 30 30 funcref) + (elem (table $t0) (i32.const 2) func 3 1 4 1) + (elem funcref + (ref.func 2) (ref.func 7) (ref.func 1) (ref.func 8)) + (elem (table $t0) (i32.const 12) func 7 5 2 3 6) + (elem funcref + (ref.func 5) (ref.func 9) (ref.func 2) (ref.func 7) (ref.func 6)) + (func (result i32) (i32.const 0)) + (func (result i32) (i32.const 1)) + (func (result i32) (i32.const 2)) + (func (result i32) (i32.const 3)) + (func (result i32) (i32.const 4)) + (func (result i32) (i32.const 5)) + (func (result i32) (i32.const 6)) + (func (result i32) (i32.const 7)) + (func (result i32) (i32.const 8)) + (func (result i32) (i32.const 9)) + (func (export "test") + (table.copy $t0 $t0 (i32.const 0xFFFFFFFE) (i32.const 1) (i32.const 2)) + )) + +(assert_trap (invoke "test") "out of bounds") + +(module + (table $t0 30 30 funcref) + (table $t1 30 30 funcref) + (elem (table $t0) (i32.const 2) func 3 1 4 1) + (elem funcref + (ref.func 2) (ref.func 7) (ref.func 1) (ref.func 8)) + (elem (table $t0) (i32.const 12) func 7 5 2 3 6) + (elem funcref + (ref.func 5) (ref.func 9) (ref.func 2) (ref.func 7) (ref.func 6)) + (func (result i32) (i32.const 0)) + (func (result i32) (i32.const 1)) + (func (result i32) (i32.const 2)) + (func (result i32) (i32.const 3)) + (func (result i32) (i32.const 4)) + (func (result i32) (i32.const 5)) + (func (result i32) (i32.const 6)) + (func (result i32) (i32.const 7)) + (func (result i32) (i32.const 8)) + (func (result i32) (i32.const 9)) + (func (export "test") + (table.copy $t0 $t0 (i32.const 15) (i32.const 25) (i32.const 6)) + )) + +(assert_trap (invoke "test") "out of bounds") + +(module + (table $t0 30 30 funcref) + (table $t1 30 30 funcref) + (elem (table $t0) (i32.const 2) func 3 1 4 1) + (elem funcref + (ref.func 2) (ref.func 7) (ref.func 1) (ref.func 8)) + (elem (table $t0) (i32.const 12) func 7 5 2 3 6) + (elem funcref + (ref.func 5) (ref.func 9) (ref.func 2) (ref.func 7) (ref.func 6)) + (func (result i32) (i32.const 0)) + (func (result i32) (i32.const 1)) + (func (result i32) (i32.const 2)) + (func (result i32) (i32.const 3)) + (func (result i32) (i32.const 4)) + (func (result i32) (i32.const 5)) + (func (result i32) (i32.const 6)) + (func (result i32) (i32.const 7)) + (func (result i32) (i32.const 8)) + (func (result i32) (i32.const 9)) + (func (export "test") + (table.copy $t0 $t0 (i32.const 15) (i32.const 0xFFFFFFFE) (i32.const 2)) + )) + +(assert_trap (invoke "test") "out of bounds") + +(module + (table $t0 30 30 funcref) + (table $t1 30 30 funcref) + (elem (table $t0) (i32.const 2) func 3 1 4 1) + (elem funcref + (ref.func 2) (ref.func 7) (ref.func 1) (ref.func 8)) + (elem (table $t0) (i32.const 12) func 7 5 2 3 6) + (elem funcref + (ref.func 5) (ref.func 9) (ref.func 2) (ref.func 7) (ref.func 6)) + (func (result i32) (i32.const 0)) + (func (result i32) (i32.const 1)) + (func (result i32) (i32.const 2)) + (func (result i32) (i32.const 3)) + (func (result i32) (i32.const 4)) + (func (result i32) (i32.const 5)) + (func (result i32) (i32.const 6)) + (func (result i32) (i32.const 7)) + (func (result i32) (i32.const 8)) + (func (result i32) (i32.const 9)) + (func (export "test") + (table.copy $t0 $t0 (i32.const 15) (i32.const 25) (i32.const 0)) + )) + +(invoke "test") + +(module + (table $t0 30 30 funcref) + (table $t1 30 30 funcref) + (elem (table $t0) (i32.const 2) func 3 1 4 1) + (elem funcref + (ref.func 2) (ref.func 7) (ref.func 1) (ref.func 8)) + (elem (table $t0) (i32.const 12) func 7 5 2 3 6) + (elem funcref + (ref.func 5) (ref.func 9) (ref.func 2) (ref.func 7) (ref.func 6)) + (func (result i32) (i32.const 0)) + (func (result i32) (i32.const 1)) + (func (result i32) (i32.const 2)) + (func (result i32) (i32.const 3)) + (func (result i32) (i32.const 4)) + (func (result i32) (i32.const 5)) + (func (result i32) (i32.const 6)) + (func (result i32) (i32.const 7)) + (func (result i32) (i32.const 8)) + (func (result i32) (i32.const 9)) + (func (export "test") + (table.copy $t0 $t0 (i32.const 30) (i32.const 15) (i32.const 0)) + )) + +(invoke "test") + +(module + (table $t0 30 30 funcref) + (table $t1 30 30 funcref) + (elem (table $t0) (i32.const 2) func 3 1 4 1) + (elem funcref + (ref.func 2) (ref.func 7) (ref.func 1) (ref.func 8)) + (elem (table $t0) (i32.const 12) func 7 5 2 3 6) + (elem funcref + (ref.func 5) (ref.func 9) (ref.func 2) (ref.func 7) (ref.func 6)) + (func (result i32) (i32.const 0)) + (func (result i32) (i32.const 1)) + (func (result i32) (i32.const 2)) + (func (result i32) (i32.const 3)) + (func (result i32) (i32.const 4)) + (func (result i32) (i32.const 5)) + (func (result i32) (i32.const 6)) + (func (result i32) (i32.const 7)) + (func (result i32) (i32.const 8)) + (func (result i32) (i32.const 9)) + (func (export "test") + (table.copy $t0 $t0 (i32.const 31) (i32.const 15) (i32.const 0)) + )) + +(assert_trap (invoke "test") "out of bounds") + +(module + (table $t0 30 30 funcref) + (table $t1 30 30 funcref) + (elem (table $t0) (i32.const 2) func 3 1 4 1) + (elem funcref + (ref.func 2) (ref.func 7) (ref.func 1) (ref.func 8)) + (elem (table $t0) (i32.const 12) func 7 5 2 3 6) + (elem funcref + (ref.func 5) (ref.func 9) (ref.func 2) (ref.func 7) (ref.func 6)) + (func (result i32) (i32.const 0)) + (func (result i32) (i32.const 1)) + (func (result i32) (i32.const 2)) + (func (result i32) (i32.const 3)) + (func (result i32) (i32.const 4)) + (func (result i32) (i32.const 5)) + (func (result i32) (i32.const 6)) + (func (result i32) (i32.const 7)) + (func (result i32) (i32.const 8)) + (func (result i32) (i32.const 9)) + (func (export "test") + (table.copy $t0 $t0 (i32.const 15) (i32.const 30) (i32.const 0)) + )) + +(invoke "test") + +(module + (table $t0 30 30 funcref) + (table $t1 30 30 funcref) + (elem (table $t0) (i32.const 2) func 3 1 4 1) + (elem funcref + (ref.func 2) (ref.func 7) (ref.func 1) (ref.func 8)) + (elem (table $t0) (i32.const 12) func 7 5 2 3 6) + (elem funcref + (ref.func 5) (ref.func 9) (ref.func 2) (ref.func 7) (ref.func 6)) + (func (result i32) (i32.const 0)) + (func (result i32) (i32.const 1)) + (func (result i32) (i32.const 2)) + (func (result i32) (i32.const 3)) + (func (result i32) (i32.const 4)) + (func (result i32) (i32.const 5)) + (func (result i32) (i32.const 6)) + (func (result i32) (i32.const 7)) + (func (result i32) (i32.const 8)) + (func (result i32) (i32.const 9)) + (func (export "test") + (table.copy $t0 $t0 (i32.const 15) (i32.const 31) (i32.const 0)) + )) + +(assert_trap (invoke "test") "out of bounds") + +(module + (table $t0 30 30 funcref) + (table $t1 30 30 funcref) + (elem (table $t0) (i32.const 2) func 3 1 4 1) + (elem funcref + (ref.func 2) (ref.func 7) (ref.func 1) (ref.func 8)) + (elem (table $t0) (i32.const 12) func 7 5 2 3 6) + (elem funcref + (ref.func 5) (ref.func 9) (ref.func 2) (ref.func 7) (ref.func 6)) + (func (result i32) (i32.const 0)) + (func (result i32) (i32.const 1)) + (func (result i32) (i32.const 2)) + (func (result i32) (i32.const 3)) + (func (result i32) (i32.const 4)) + (func (result i32) (i32.const 5)) + (func (result i32) (i32.const 6)) + (func (result i32) (i32.const 7)) + (func (result i32) (i32.const 8)) + (func (result i32) (i32.const 9)) + (func (export "test") + (table.copy $t0 $t0 (i32.const 30) (i32.const 30) (i32.const 0)) + )) + +(invoke "test") + +(module + (table $t0 30 30 funcref) + (table $t1 30 30 funcref) + (elem (table $t0) (i32.const 2) func 3 1 4 1) + (elem funcref + (ref.func 2) (ref.func 7) (ref.func 1) (ref.func 8)) + (elem (table $t0) (i32.const 12) func 7 5 2 3 6) + (elem funcref + (ref.func 5) (ref.func 9) (ref.func 2) (ref.func 7) (ref.func 6)) + (func (result i32) (i32.const 0)) + (func (result i32) (i32.const 1)) + (func (result i32) (i32.const 2)) + (func (result i32) (i32.const 3)) + (func (result i32) (i32.const 4)) + (func (result i32) (i32.const 5)) + (func (result i32) (i32.const 6)) + (func (result i32) (i32.const 7)) + (func (result i32) (i32.const 8)) + (func (result i32) (i32.const 9)) + (func (export "test") + (table.copy $t0 $t0 (i32.const 31) (i32.const 31) (i32.const 0)) + )) + +(assert_trap (invoke "test") "out of bounds") + +(module + (table $t0 30 30 funcref) + (table $t1 30 30 funcref) + (elem (table $t0) (i32.const 2) func 3 1 4 1) (elem funcref (ref.func 2) (ref.func 7) (ref.func 1) (ref.func 8)) - (elem (i32.const 12) 7 5 2 3 6) + (elem (table $t0) (i32.const 12) func 7 5 2 3 6) (elem funcref (ref.func 5) (ref.func 9) (ref.func 2) (ref.func 7) (ref.func 6)) (func (result i32) (i32.const 0)) @@ -486,17 +1963,18 @@ (func (result i32) (i32.const 8)) (func (result i32) (i32.const 9)) (func (export "test") - (table.copy (i32.const 28) (i32.const 1) (i32.const 3)) + (table.copy $t1 $t0 (i32.const 28) (i32.const 1) (i32.const 3)) )) (assert_trap (invoke "test") "out of bounds") (module - (table 30 30 funcref) - (elem (i32.const 2) 3 1 4 1) + (table $t0 30 30 funcref) + (table $t1 30 30 funcref) + (elem (table $t0) (i32.const 2) func 3 1 4 1) (elem funcref (ref.func 2) (ref.func 7) (ref.func 1) (ref.func 8)) - (elem (i32.const 12) 7 5 2 3 6) + (elem (table $t0) (i32.const 12) func 7 5 2 3 6) (elem funcref (ref.func 5) (ref.func 9) (ref.func 2) (ref.func 7) (ref.func 6)) (func (result i32) (i32.const 0)) @@ -510,17 +1988,18 @@ (func (result i32) (i32.const 8)) (func (result i32) (i32.const 9)) (func (export "test") - (table.copy (i32.const 0xFFFFFFFE) (i32.const 1) (i32.const 2)) + (table.copy $t1 $t0 (i32.const 0xFFFFFFFE) (i32.const 1) (i32.const 2)) )) (assert_trap (invoke "test") "out of bounds") (module - (table 30 30 funcref) - (elem (i32.const 2) 3 1 4 1) + (table $t0 30 30 funcref) + (table $t1 30 30 funcref) + (elem (table $t0) (i32.const 2) func 3 1 4 1) (elem funcref (ref.func 2) (ref.func 7) (ref.func 1) (ref.func 8)) - (elem (i32.const 12) 7 5 2 3 6) + (elem (table $t0) (i32.const 12) func 7 5 2 3 6) (elem funcref (ref.func 5) (ref.func 9) (ref.func 2) (ref.func 7) (ref.func 6)) (func (result i32) (i32.const 0)) @@ -534,17 +2013,18 @@ (func (result i32) (i32.const 8)) (func (result i32) (i32.const 9)) (func (export "test") - (table.copy (i32.const 15) (i32.const 25) (i32.const 6)) + (table.copy $t1 $t0 (i32.const 15) (i32.const 25) (i32.const 6)) )) (assert_trap (invoke "test") "out of bounds") (module - (table 30 30 funcref) - (elem (i32.const 2) 3 1 4 1) + (table $t0 30 30 funcref) + (table $t1 30 30 funcref) + (elem (table $t0) (i32.const 2) func 3 1 4 1) (elem funcref (ref.func 2) (ref.func 7) (ref.func 1) (ref.func 8)) - (elem (i32.const 12) 7 5 2 3 6) + (elem (table $t0) (i32.const 12) func 7 5 2 3 6) (elem funcref (ref.func 5) (ref.func 9) (ref.func 2) (ref.func 7) (ref.func 6)) (func (result i32) (i32.const 0)) @@ -558,17 +2038,18 @@ (func (result i32) (i32.const 8)) (func (result i32) (i32.const 9)) (func (export "test") - (table.copy (i32.const 15) (i32.const 0xFFFFFFFE) (i32.const 2)) + (table.copy $t1 $t0 (i32.const 15) (i32.const 0xFFFFFFFE) (i32.const 2)) )) (assert_trap (invoke "test") "out of bounds") (module - (table 30 30 funcref) - (elem (i32.const 2) 3 1 4 1) + (table $t0 30 30 funcref) + (table $t1 30 30 funcref) + (elem (table $t0) (i32.const 2) func 3 1 4 1) (elem funcref (ref.func 2) (ref.func 7) (ref.func 1) (ref.func 8)) - (elem (i32.const 12) 7 5 2 3 6) + (elem (table $t0) (i32.const 12) func 7 5 2 3 6) (elem funcref (ref.func 5) (ref.func 9) (ref.func 2) (ref.func 7) (ref.func 6)) (func (result i32) (i32.const 0)) @@ -582,17 +2063,18 @@ (func (result i32) (i32.const 8)) (func (result i32) (i32.const 9)) (func (export "test") - (table.copy (i32.const 15) (i32.const 25) (i32.const 0)) + (table.copy $t1 $t0 (i32.const 15) (i32.const 25) (i32.const 0)) )) (invoke "test") (module - (table 30 30 funcref) - (elem (i32.const 2) 3 1 4 1) + (table $t0 30 30 funcref) + (table $t1 30 30 funcref) + (elem (table $t0) (i32.const 2) func 3 1 4 1) (elem funcref (ref.func 2) (ref.func 7) (ref.func 1) (ref.func 8)) - (elem (i32.const 12) 7 5 2 3 6) + (elem (table $t0) (i32.const 12) func 7 5 2 3 6) (elem funcref (ref.func 5) (ref.func 9) (ref.func 2) (ref.func 7) (ref.func 6)) (func (result i32) (i32.const 0)) @@ -606,17 +2088,18 @@ (func (result i32) (i32.const 8)) (func (result i32) (i32.const 9)) (func (export "test") - (table.copy (i32.const 30) (i32.const 15) (i32.const 0)) + (table.copy $t1 $t0 (i32.const 30) (i32.const 15) (i32.const 0)) )) (invoke "test") (module - (table 30 30 funcref) - (elem (i32.const 2) 3 1 4 1) + (table $t0 30 30 funcref) + (table $t1 30 30 funcref) + (elem (table $t0) (i32.const 2) func 3 1 4 1) (elem funcref (ref.func 2) (ref.func 7) (ref.func 1) (ref.func 8)) - (elem (i32.const 12) 7 5 2 3 6) + (elem (table $t0) (i32.const 12) func 7 5 2 3 6) (elem funcref (ref.func 5) (ref.func 9) (ref.func 2) (ref.func 7) (ref.func 6)) (func (result i32) (i32.const 0)) @@ -630,17 +2113,18 @@ (func (result i32) (i32.const 8)) (func (result i32) (i32.const 9)) (func (export "test") - (table.copy (i32.const 31) (i32.const 15) (i32.const 0)) + (table.copy $t1 $t0 (i32.const 31) (i32.const 15) (i32.const 0)) )) (assert_trap (invoke "test") "out of bounds") (module - (table 30 30 funcref) - (elem (i32.const 2) 3 1 4 1) + (table $t0 30 30 funcref) + (table $t1 30 30 funcref) + (elem (table $t0) (i32.const 2) func 3 1 4 1) (elem funcref (ref.func 2) (ref.func 7) (ref.func 1) (ref.func 8)) - (elem (i32.const 12) 7 5 2 3 6) + (elem (table $t0) (i32.const 12) func 7 5 2 3 6) (elem funcref (ref.func 5) (ref.func 9) (ref.func 2) (ref.func 7) (ref.func 6)) (func (result i32) (i32.const 0)) @@ -654,17 +2138,18 @@ (func (result i32) (i32.const 8)) (func (result i32) (i32.const 9)) (func (export "test") - (table.copy (i32.const 15) (i32.const 30) (i32.const 0)) + (table.copy $t1 $t0 (i32.const 15) (i32.const 30) (i32.const 0)) )) (invoke "test") (module - (table 30 30 funcref) - (elem (i32.const 2) 3 1 4 1) + (table $t0 30 30 funcref) + (table $t1 30 30 funcref) + (elem (table $t0) (i32.const 2) func 3 1 4 1) (elem funcref (ref.func 2) (ref.func 7) (ref.func 1) (ref.func 8)) - (elem (i32.const 12) 7 5 2 3 6) + (elem (table $t0) (i32.const 12) func 7 5 2 3 6) (elem funcref (ref.func 5) (ref.func 9) (ref.func 2) (ref.func 7) (ref.func 6)) (func (result i32) (i32.const 0)) @@ -678,17 +2163,18 @@ (func (result i32) (i32.const 8)) (func (result i32) (i32.const 9)) (func (export "test") - (table.copy (i32.const 15) (i32.const 31) (i32.const 0)) + (table.copy $t1 $t0 (i32.const 15) (i32.const 31) (i32.const 0)) )) (assert_trap (invoke "test") "out of bounds") (module - (table 30 30 funcref) - (elem (i32.const 2) 3 1 4 1) + (table $t0 30 30 funcref) + (table $t1 30 30 funcref) + (elem (table $t0) (i32.const 2) func 3 1 4 1) (elem funcref (ref.func 2) (ref.func 7) (ref.func 1) (ref.func 8)) - (elem (i32.const 12) 7 5 2 3 6) + (elem (table $t0) (i32.const 12) func 7 5 2 3 6) (elem funcref (ref.func 5) (ref.func 9) (ref.func 2) (ref.func 7) (ref.func 6)) (func (result i32) (i32.const 0)) @@ -702,17 +2188,18 @@ (func (result i32) (i32.const 8)) (func (result i32) (i32.const 9)) (func (export "test") - (table.copy (i32.const 30) (i32.const 30) (i32.const 0)) + (table.copy $t1 $t0 (i32.const 30) (i32.const 30) (i32.const 0)) )) (invoke "test") (module - (table 30 30 funcref) - (elem (i32.const 2) 3 1 4 1) + (table $t0 30 30 funcref) + (table $t1 30 30 funcref) + (elem (table $t0) (i32.const 2) func 3 1 4 1) (elem funcref (ref.func 2) (ref.func 7) (ref.func 1) (ref.func 8)) - (elem (i32.const 12) 7 5 2 3 6) + (elem (table $t0) (i32.const 12) func 7 5 2 3 6) (elem funcref (ref.func 5) (ref.func 9) (ref.func 2) (ref.func 7) (ref.func 6)) (func (result i32) (i32.const 0)) @@ -726,7 +2213,7 @@ (func (result i32) (i32.const 8)) (func (result i32) (i32.const 9)) (func (export "test") - (table.copy (i32.const 31) (i32.const 31) (i32.const 0)) + (table.copy $t1 $t0 (i32.const 31) (i32.const 31) (i32.const 0)) )) (assert_trap (invoke "test") "out of bounds") diff --git a/test/core/table_init.wast b/test/core/table_init.wast index 80eaf065d8..a711007c26 100644 --- a/test/core/table_init.wast +++ b/test/core/table_init.wast @@ -1,5 +1,6 @@ ;; ;; Generated by ../meta/generate_table_init.js +;; DO NOT EDIT THIS FILE. CHANGE THE SOURCE AND REGENERATE. ;; (module @@ -18,11 +19,12 @@ (import "a" "ef2" (func (result i32))) (import "a" "ef3" (func (result i32))) (import "a" "ef4" (func (result i32))) ;; index 4 - (table 30 30 funcref) - (elem (i32.const 2) 3 1 4 1) + (table $t0 30 30 funcref) + (table $t1 30 30 funcref) + (elem (table $t0) (i32.const 2) func 3 1 4 1) (elem funcref (ref.func 2) (ref.func 7) (ref.func 1) (ref.func 8)) - (elem (i32.const 12) 7 5 2 3 6) + (elem (table $t0) (i32.const 12) func 7 5 2 3 6) (elem funcref (ref.func 5) (ref.func 9) (ref.func 2) (ref.func 7) (ref.func 6)) (func (result i32) (i32.const 5)) ;; index 5 @@ -31,9 +33,9 @@ (func (result i32) (i32.const 8)) (func (result i32) (i32.const 9)) ;; index 9 (func (export "test") - (table.init 1 (i32.const 7) (i32.const 0) (i32.const 4))) + (table.init $t0 1 (i32.const 7) (i32.const 0) (i32.const 4))) (func (export "check") (param i32) (result i32) - (call_indirect (type 0) (local.get 0))) + (call_indirect $t0 (type 0) (local.get 0))) ) (invoke "test") @@ -75,11 +77,12 @@ (import "a" "ef2" (func (result i32))) (import "a" "ef3" (func (result i32))) (import "a" "ef4" (func (result i32))) ;; index 4 - (table 30 30 funcref) - (elem (i32.const 2) 3 1 4 1) + (table $t0 30 30 funcref) + (table $t1 30 30 funcref) + (elem (table $t0) (i32.const 2) func 3 1 4 1) (elem funcref (ref.func 2) (ref.func 7) (ref.func 1) (ref.func 8)) - (elem (i32.const 12) 7 5 2 3 6) + (elem (table $t0) (i32.const 12) func 7 5 2 3 6) (elem funcref (ref.func 5) (ref.func 9) (ref.func 2) (ref.func 7) (ref.func 6)) (func (result i32) (i32.const 5)) ;; index 5 @@ -88,9 +91,9 @@ (func (result i32) (i32.const 8)) (func (result i32) (i32.const 9)) ;; index 9 (func (export "test") - (table.init 3 (i32.const 15) (i32.const 1) (i32.const 3))) + (table.init $t0 3 (i32.const 15) (i32.const 1) (i32.const 3))) (func (export "check") (param i32) (result i32) - (call_indirect (type 0) (local.get 0))) + (call_indirect $t0 (type 0) (local.get 0))) ) (invoke "test") @@ -132,11 +135,12 @@ (import "a" "ef2" (func (result i32))) (import "a" "ef3" (func (result i32))) (import "a" "ef4" (func (result i32))) ;; index 4 - (table 30 30 funcref) - (elem (i32.const 2) 3 1 4 1) + (table $t0 30 30 funcref) + (table $t1 30 30 funcref) + (elem (table $t0) (i32.const 2) func 3 1 4 1) (elem funcref (ref.func 2) (ref.func 7) (ref.func 1) (ref.func 8)) - (elem (i32.const 12) 7 5 2 3 6) + (elem (table $t0) (i32.const 12) func 7 5 2 3 6) (elem funcref (ref.func 5) (ref.func 9) (ref.func 2) (ref.func 7) (ref.func 6)) (func (result i32) (i32.const 5)) ;; index 5 @@ -145,17 +149,199 @@ (func (result i32) (i32.const 8)) (func (result i32) (i32.const 9)) ;; index 9 (func (export "test") - (table.init 1 (i32.const 7) (i32.const 0) (i32.const 4)) - (elem.drop 1) - (table.init 3 (i32.const 15) (i32.const 1) (i32.const 3)) - (elem.drop 3) - (table.copy (i32.const 20) (i32.const 15) (i32.const 5)) - (table.copy (i32.const 21) (i32.const 29) (i32.const 1)) - (table.copy (i32.const 24) (i32.const 10) (i32.const 1)) - (table.copy (i32.const 13) (i32.const 11) (i32.const 4)) - (table.copy (i32.const 19) (i32.const 20) (i32.const 5))) + (table.init $t0 1 (i32.const 7) (i32.const 0) (i32.const 4)) + (elem.drop 1) + (table.init $t0 3 (i32.const 15) (i32.const 1) (i32.const 3)) + (elem.drop 3) + (table.copy $t0 0 (i32.const 20) (i32.const 15) (i32.const 5)) + (table.copy $t0 0 (i32.const 21) (i32.const 29) (i32.const 1)) + (table.copy $t0 0 (i32.const 24) (i32.const 10) (i32.const 1)) + (table.copy $t0 0 (i32.const 13) (i32.const 11) (i32.const 4)) + (table.copy $t0 0 (i32.const 19) (i32.const 20) (i32.const 5))) + (func (export "check") (param i32) (result i32) + (call_indirect $t0 (type 0) (local.get 0))) +) + +(invoke "test") +(assert_trap (invoke "check" (i32.const 0)) "uninitialized element") +(assert_trap (invoke "check" (i32.const 1)) "uninitialized element") +(assert_return (invoke "check" (i32.const 2)) (i32.const 3)) +(assert_return (invoke "check" (i32.const 3)) (i32.const 1)) +(assert_return (invoke "check" (i32.const 4)) (i32.const 4)) +(assert_return (invoke "check" (i32.const 5)) (i32.const 1)) +(assert_trap (invoke "check" (i32.const 6)) "uninitialized element") +(assert_return (invoke "check" (i32.const 7)) (i32.const 2)) +(assert_return (invoke "check" (i32.const 8)) (i32.const 7)) +(assert_return (invoke "check" (i32.const 9)) (i32.const 1)) +(assert_return (invoke "check" (i32.const 10)) (i32.const 8)) +(assert_trap (invoke "check" (i32.const 11)) "uninitialized element") +(assert_return (invoke "check" (i32.const 12)) (i32.const 7)) +(assert_trap (invoke "check" (i32.const 13)) "uninitialized element") +(assert_return (invoke "check" (i32.const 14)) (i32.const 7)) +(assert_return (invoke "check" (i32.const 15)) (i32.const 5)) +(assert_return (invoke "check" (i32.const 16)) (i32.const 2)) +(assert_return (invoke "check" (i32.const 17)) (i32.const 7)) +(assert_trap (invoke "check" (i32.const 18)) "uninitialized element") +(assert_return (invoke "check" (i32.const 19)) (i32.const 9)) +(assert_trap (invoke "check" (i32.const 20)) "uninitialized element") +(assert_return (invoke "check" (i32.const 21)) (i32.const 7)) +(assert_trap (invoke "check" (i32.const 22)) "uninitialized element") +(assert_return (invoke "check" (i32.const 23)) (i32.const 8)) +(assert_return (invoke "check" (i32.const 24)) (i32.const 8)) +(assert_trap (invoke "check" (i32.const 25)) "uninitialized element") +(assert_trap (invoke "check" (i32.const 26)) "uninitialized element") +(assert_trap (invoke "check" (i32.const 27)) "uninitialized element") +(assert_trap (invoke "check" (i32.const 28)) "uninitialized element") +(assert_trap (invoke "check" (i32.const 29)) "uninitialized element") + +(module + (type (func (result i32))) ;; type #0 + (import "a" "ef0" (func (result i32))) ;; index 0 + (import "a" "ef1" (func (result i32))) + (import "a" "ef2" (func (result i32))) + (import "a" "ef3" (func (result i32))) + (import "a" "ef4" (func (result i32))) ;; index 4 + (table $t0 30 30 funcref) + (table $t1 30 30 funcref) + (elem (table $t1) (i32.const 2) func 3 1 4 1) + (elem funcref + (ref.func 2) (ref.func 7) (ref.func 1) (ref.func 8)) + (elem (table $t1) (i32.const 12) func 7 5 2 3 6) + (elem funcref + (ref.func 5) (ref.func 9) (ref.func 2) (ref.func 7) (ref.func 6)) + (func (result i32) (i32.const 5)) ;; index 5 + (func (result i32) (i32.const 6)) + (func (result i32) (i32.const 7)) + (func (result i32) (i32.const 8)) + (func (result i32) (i32.const 9)) ;; index 9 + (func (export "test") + (table.init $t1 1 (i32.const 7) (i32.const 0) (i32.const 4))) + (func (export "check") (param i32) (result i32) + (call_indirect $t1 (type 0) (local.get 0))) +) + +(invoke "test") +(assert_trap (invoke "check" (i32.const 0)) "uninitialized element") +(assert_trap (invoke "check" (i32.const 1)) "uninitialized element") +(assert_return (invoke "check" (i32.const 2)) (i32.const 3)) +(assert_return (invoke "check" (i32.const 3)) (i32.const 1)) +(assert_return (invoke "check" (i32.const 4)) (i32.const 4)) +(assert_return (invoke "check" (i32.const 5)) (i32.const 1)) +(assert_trap (invoke "check" (i32.const 6)) "uninitialized element") +(assert_return (invoke "check" (i32.const 7)) (i32.const 2)) +(assert_return (invoke "check" (i32.const 8)) (i32.const 7)) +(assert_return (invoke "check" (i32.const 9)) (i32.const 1)) +(assert_return (invoke "check" (i32.const 10)) (i32.const 8)) +(assert_trap (invoke "check" (i32.const 11)) "uninitialized element") +(assert_return (invoke "check" (i32.const 12)) (i32.const 7)) +(assert_return (invoke "check" (i32.const 13)) (i32.const 5)) +(assert_return (invoke "check" (i32.const 14)) (i32.const 2)) +(assert_return (invoke "check" (i32.const 15)) (i32.const 3)) +(assert_return (invoke "check" (i32.const 16)) (i32.const 6)) +(assert_trap (invoke "check" (i32.const 17)) "uninitialized element") +(assert_trap (invoke "check" (i32.const 18)) "uninitialized element") +(assert_trap (invoke "check" (i32.const 19)) "uninitialized element") +(assert_trap (invoke "check" (i32.const 20)) "uninitialized element") +(assert_trap (invoke "check" (i32.const 21)) "uninitialized element") +(assert_trap (invoke "check" (i32.const 22)) "uninitialized element") +(assert_trap (invoke "check" (i32.const 23)) "uninitialized element") +(assert_trap (invoke "check" (i32.const 24)) "uninitialized element") +(assert_trap (invoke "check" (i32.const 25)) "uninitialized element") +(assert_trap (invoke "check" (i32.const 26)) "uninitialized element") +(assert_trap (invoke "check" (i32.const 27)) "uninitialized element") +(assert_trap (invoke "check" (i32.const 28)) "uninitialized element") +(assert_trap (invoke "check" (i32.const 29)) "uninitialized element") + +(module + (type (func (result i32))) ;; type #0 + (import "a" "ef0" (func (result i32))) ;; index 0 + (import "a" "ef1" (func (result i32))) + (import "a" "ef2" (func (result i32))) + (import "a" "ef3" (func (result i32))) + (import "a" "ef4" (func (result i32))) ;; index 4 + (table $t0 30 30 funcref) + (table $t1 30 30 funcref) + (elem (table $t1) (i32.const 2) func 3 1 4 1) + (elem funcref + (ref.func 2) (ref.func 7) (ref.func 1) (ref.func 8)) + (elem (table $t1) (i32.const 12) func 7 5 2 3 6) + (elem funcref + (ref.func 5) (ref.func 9) (ref.func 2) (ref.func 7) (ref.func 6)) + (func (result i32) (i32.const 5)) ;; index 5 + (func (result i32) (i32.const 6)) + (func (result i32) (i32.const 7)) + (func (result i32) (i32.const 8)) + (func (result i32) (i32.const 9)) ;; index 9 + (func (export "test") + (table.init $t1 3 (i32.const 15) (i32.const 1) (i32.const 3))) + (func (export "check") (param i32) (result i32) + (call_indirect $t1 (type 0) (local.get 0))) +) + +(invoke "test") +(assert_trap (invoke "check" (i32.const 0)) "uninitialized element") +(assert_trap (invoke "check" (i32.const 1)) "uninitialized element") +(assert_return (invoke "check" (i32.const 2)) (i32.const 3)) +(assert_return (invoke "check" (i32.const 3)) (i32.const 1)) +(assert_return (invoke "check" (i32.const 4)) (i32.const 4)) +(assert_return (invoke "check" (i32.const 5)) (i32.const 1)) +(assert_trap (invoke "check" (i32.const 6)) "uninitialized element") +(assert_trap (invoke "check" (i32.const 7)) "uninitialized element") +(assert_trap (invoke "check" (i32.const 8)) "uninitialized element") +(assert_trap (invoke "check" (i32.const 9)) "uninitialized element") +(assert_trap (invoke "check" (i32.const 10)) "uninitialized element") +(assert_trap (invoke "check" (i32.const 11)) "uninitialized element") +(assert_return (invoke "check" (i32.const 12)) (i32.const 7)) +(assert_return (invoke "check" (i32.const 13)) (i32.const 5)) +(assert_return (invoke "check" (i32.const 14)) (i32.const 2)) +(assert_return (invoke "check" (i32.const 15)) (i32.const 9)) +(assert_return (invoke "check" (i32.const 16)) (i32.const 2)) +(assert_return (invoke "check" (i32.const 17)) (i32.const 7)) +(assert_trap (invoke "check" (i32.const 18)) "uninitialized element") +(assert_trap (invoke "check" (i32.const 19)) "uninitialized element") +(assert_trap (invoke "check" (i32.const 20)) "uninitialized element") +(assert_trap (invoke "check" (i32.const 21)) "uninitialized element") +(assert_trap (invoke "check" (i32.const 22)) "uninitialized element") +(assert_trap (invoke "check" (i32.const 23)) "uninitialized element") +(assert_trap (invoke "check" (i32.const 24)) "uninitialized element") +(assert_trap (invoke "check" (i32.const 25)) "uninitialized element") +(assert_trap (invoke "check" (i32.const 26)) "uninitialized element") +(assert_trap (invoke "check" (i32.const 27)) "uninitialized element") +(assert_trap (invoke "check" (i32.const 28)) "uninitialized element") +(assert_trap (invoke "check" (i32.const 29)) "uninitialized element") + +(module + (type (func (result i32))) ;; type #0 + (import "a" "ef0" (func (result i32))) ;; index 0 + (import "a" "ef1" (func (result i32))) + (import "a" "ef2" (func (result i32))) + (import "a" "ef3" (func (result i32))) + (import "a" "ef4" (func (result i32))) ;; index 4 + (table $t0 30 30 funcref) + (table $t1 30 30 funcref) + (elem (table $t1) (i32.const 2) func 3 1 4 1) + (elem funcref + (ref.func 2) (ref.func 7) (ref.func 1) (ref.func 8)) + (elem (table $t1) (i32.const 12) func 7 5 2 3 6) + (elem funcref + (ref.func 5) (ref.func 9) (ref.func 2) (ref.func 7) (ref.func 6)) + (func (result i32) (i32.const 5)) ;; index 5 + (func (result i32) (i32.const 6)) + (func (result i32) (i32.const 7)) + (func (result i32) (i32.const 8)) + (func (result i32) (i32.const 9)) ;; index 9 + (func (export "test") + (table.init $t1 1 (i32.const 7) (i32.const 0) (i32.const 4)) + (elem.drop 1) + (table.init $t1 3 (i32.const 15) (i32.const 1) (i32.const 3)) + (elem.drop 3) + (table.copy $t1 1 (i32.const 20) (i32.const 15) (i32.const 5)) + (table.copy $t1 1 (i32.const 21) (i32.const 29) (i32.const 1)) + (table.copy $t1 1 (i32.const 24) (i32.const 10) (i32.const 1)) + (table.copy $t1 1 (i32.const 13) (i32.const 11) (i32.const 4)) + (table.copy $t1 1 (i32.const 19) (i32.const 20) (i32.const 5))) (func (export "check") (param i32) (result i32) - (call_indirect (type 0) (local.get 0))) + (call_indirect $t1 (type 0) (local.get 0))) ) (invoke "test") @@ -219,11 +405,12 @@ (module - (table 30 30 funcref) - (elem (i32.const 2) 3 1 4 1) + (table $t0 30 30 funcref) + (table $t1 28 28 funcref) + (elem (table $t0) (i32.const 2) func 3 1 4 1) (elem funcref (ref.func 2) (ref.func 7) (ref.func 1) (ref.func 8)) - (elem (i32.const 12) 7 5 2 3 6) + (elem (table $t0) (i32.const 12) func 7 5 2 3 6) (elem funcref (ref.func 5) (ref.func 9) (ref.func 2) (ref.func 7) (ref.func 6)) (func (result i32) (i32.const 0)) @@ -242,11 +429,12 @@ (invoke "test") (module - (table 30 30 funcref) - (elem (i32.const 2) 3 1 4 1) + (table $t0 30 30 funcref) + (table $t1 28 28 funcref) + (elem (table $t0) (i32.const 2) func 3 1 4 1) (elem funcref (ref.func 2) (ref.func 7) (ref.func 1) (ref.func 8)) - (elem (i32.const 12) 7 5 2 3 6) + (elem (table $t0) (i32.const 12) func 7 5 2 3 6) (elem funcref (ref.func 5) (ref.func 9) (ref.func 2) (ref.func 7) (ref.func 6)) (func (result i32) (i32.const 0)) @@ -265,11 +453,12 @@ (assert_trap (invoke "test") "out of bounds") (module - (table 30 30 funcref) - (elem (i32.const 2) 3 1 4 1) + (table $t0 30 30 funcref) + (table $t1 28 28 funcref) + (elem (table $t0) (i32.const 2) func 3 1 4 1) (elem funcref (ref.func 2) (ref.func 7) (ref.func 1) (ref.func 8)) - (elem (i32.const 12) 7 5 2 3 6) + (elem (table $t0) (i32.const 12) func 7 5 2 3 6) (elem funcref (ref.func 5) (ref.func 9) (ref.func 2) (ref.func 7) (ref.func 6)) (func (result i32) (i32.const 0)) @@ -288,11 +477,12 @@ (invoke "test") (module - (table 30 30 funcref) - (elem (i32.const 2) 3 1 4 1) + (table $t0 30 30 funcref) + (table $t1 28 28 funcref) + (elem (table $t0) (i32.const 2) func 3 1 4 1) (elem funcref (ref.func 2) (ref.func 7) (ref.func 1) (ref.func 8)) - (elem (i32.const 12) 7 5 2 3 6) + (elem (table $t0) (i32.const 12) func 7 5 2 3 6) (elem funcref (ref.func 5) (ref.func 9) (ref.func 2) (ref.func 7) (ref.func 6)) (func (result i32) (i32.const 0)) @@ -311,11 +501,12 @@ (invoke "test") (module - (table 30 30 funcref) - (elem (i32.const 2) 3 1 4 1) + (table $t0 30 30 funcref) + (table $t1 28 28 funcref) + (elem (table $t0) (i32.const 2) func 3 1 4 1) (elem funcref (ref.func 2) (ref.func 7) (ref.func 1) (ref.func 8)) - (elem (i32.const 12) 7 5 2 3 6) + (elem (table $t0) (i32.const 12) func 7 5 2 3 6) (elem funcref (ref.func 5) (ref.func 9) (ref.func 2) (ref.func 7) (ref.func 6)) (func (result i32) (i32.const 0)) @@ -334,11 +525,12 @@ (assert_trap (invoke "test") "out of bounds") (module - (table 30 30 funcref) - (elem (i32.const 2) 3 1 4 1) + (table $t0 30 30 funcref) + (table $t1 28 28 funcref) + (elem (table $t0) (i32.const 2) func 3 1 4 1) (elem funcref (ref.func 2) (ref.func 7) (ref.func 1) (ref.func 8)) - (elem (i32.const 12) 7 5 2 3 6) + (elem (table $t0) (i32.const 12) func 7 5 2 3 6) (elem funcref (ref.func 5) (ref.func 9) (ref.func 2) (ref.func 7) (ref.func 6)) (func (result i32) (i32.const 0)) @@ -357,11 +549,12 @@ (assert_trap (invoke "test") "out of bounds") (module - (table 30 30 funcref) - (elem (i32.const 2) 3 1 4 1) + (table $t0 30 30 funcref) + (table $t1 28 28 funcref) + (elem (table $t0) (i32.const 2) func 3 1 4 1) (elem funcref (ref.func 2) (ref.func 7) (ref.func 1) (ref.func 8)) - (elem (i32.const 12) 7 5 2 3 6) + (elem (table $t0) (i32.const 12) func 7 5 2 3 6) (elem funcref (ref.func 5) (ref.func 9) (ref.func 2) (ref.func 7) (ref.func 6)) (func (result i32) (i32.const 0)) @@ -380,11 +573,180 @@ (assert_trap (invoke "test") "out of bounds") (module - (table 30 30 funcref) - (elem (i32.const 2) 3 1 4 1) + (table $t0 30 30 funcref) + (table $t1 28 28 funcref) + (elem (table $t0) (i32.const 2) func 3 1 4 1) + (elem funcref + (ref.func 2) (ref.func 7) (ref.func 1) (ref.func 8)) + (elem (table $t0) (i32.const 12) func 7 5 2 3 6) + (elem funcref + (ref.func 5) (ref.func 9) (ref.func 2) (ref.func 7) (ref.func 6)) + (func (result i32) (i32.const 0)) + (func (result i32) (i32.const 1)) + (func (result i32) (i32.const 2)) + (func (result i32) (i32.const 3)) + (func (result i32) (i32.const 4)) + (func (result i32) (i32.const 5)) + (func (result i32) (i32.const 6)) + (func (result i32) (i32.const 7)) + (func (result i32) (i32.const 8)) + (func (result i32) (i32.const 9)) + (func (export "test") + (table.init $t0 1 (i32.const 28) (i32.const 1) (i32.const 3)) + )) +(assert_trap (invoke "test") "out of bounds") + +(module + (table $t0 30 30 funcref) + (table $t1 28 28 funcref) + (elem (table $t0) (i32.const 2) func 3 1 4 1) + (elem funcref + (ref.func 2) (ref.func 7) (ref.func 1) (ref.func 8)) + (elem (table $t0) (i32.const 12) func 7 5 2 3 6) + (elem funcref + (ref.func 5) (ref.func 9) (ref.func 2) (ref.func 7) (ref.func 6)) + (func (result i32) (i32.const 0)) + (func (result i32) (i32.const 1)) + (func (result i32) (i32.const 2)) + (func (result i32) (i32.const 3)) + (func (result i32) (i32.const 4)) + (func (result i32) (i32.const 5)) + (func (result i32) (i32.const 6)) + (func (result i32) (i32.const 7)) + (func (result i32) (i32.const 8)) + (func (result i32) (i32.const 9)) + (func (export "test") + (table.init $t0 1 (i32.const 12) (i32.const 4) (i32.const 0)) + )) +(invoke "test") + +(module + (table $t0 30 30 funcref) + (table $t1 28 28 funcref) + (elem (table $t0) (i32.const 2) func 3 1 4 1) + (elem funcref + (ref.func 2) (ref.func 7) (ref.func 1) (ref.func 8)) + (elem (table $t0) (i32.const 12) func 7 5 2 3 6) + (elem funcref + (ref.func 5) (ref.func 9) (ref.func 2) (ref.func 7) (ref.func 6)) + (func (result i32) (i32.const 0)) + (func (result i32) (i32.const 1)) + (func (result i32) (i32.const 2)) + (func (result i32) (i32.const 3)) + (func (result i32) (i32.const 4)) + (func (result i32) (i32.const 5)) + (func (result i32) (i32.const 6)) + (func (result i32) (i32.const 7)) + (func (result i32) (i32.const 8)) + (func (result i32) (i32.const 9)) + (func (export "test") + (table.init $t0 1 (i32.const 12) (i32.const 5) (i32.const 0)) + )) +(assert_trap (invoke "test") "out of bounds") + +(module + (table $t0 30 30 funcref) + (table $t1 28 28 funcref) + (elem (table $t0) (i32.const 2) func 3 1 4 1) + (elem funcref + (ref.func 2) (ref.func 7) (ref.func 1) (ref.func 8)) + (elem (table $t0) (i32.const 12) func 7 5 2 3 6) + (elem funcref + (ref.func 5) (ref.func 9) (ref.func 2) (ref.func 7) (ref.func 6)) + (func (result i32) (i32.const 0)) + (func (result i32) (i32.const 1)) + (func (result i32) (i32.const 2)) + (func (result i32) (i32.const 3)) + (func (result i32) (i32.const 4)) + (func (result i32) (i32.const 5)) + (func (result i32) (i32.const 6)) + (func (result i32) (i32.const 7)) + (func (result i32) (i32.const 8)) + (func (result i32) (i32.const 9)) + (func (export "test") + (table.init $t0 1 (i32.const 30) (i32.const 2) (i32.const 0)) + )) +(invoke "test") + +(module + (table $t0 30 30 funcref) + (table $t1 28 28 funcref) + (elem (table $t0) (i32.const 2) func 3 1 4 1) + (elem funcref + (ref.func 2) (ref.func 7) (ref.func 1) (ref.func 8)) + (elem (table $t0) (i32.const 12) func 7 5 2 3 6) + (elem funcref + (ref.func 5) (ref.func 9) (ref.func 2) (ref.func 7) (ref.func 6)) + (func (result i32) (i32.const 0)) + (func (result i32) (i32.const 1)) + (func (result i32) (i32.const 2)) + (func (result i32) (i32.const 3)) + (func (result i32) (i32.const 4)) + (func (result i32) (i32.const 5)) + (func (result i32) (i32.const 6)) + (func (result i32) (i32.const 7)) + (func (result i32) (i32.const 8)) + (func (result i32) (i32.const 9)) + (func (export "test") + (table.init $t0 1 (i32.const 31) (i32.const 2) (i32.const 0)) + )) +(assert_trap (invoke "test") "out of bounds") + +(module + (table $t0 30 30 funcref) + (table $t1 28 28 funcref) + (elem (table $t0) (i32.const 2) func 3 1 4 1) + (elem funcref + (ref.func 2) (ref.func 7) (ref.func 1) (ref.func 8)) + (elem (table $t0) (i32.const 12) func 7 5 2 3 6) + (elem funcref + (ref.func 5) (ref.func 9) (ref.func 2) (ref.func 7) (ref.func 6)) + (func (result i32) (i32.const 0)) + (func (result i32) (i32.const 1)) + (func (result i32) (i32.const 2)) + (func (result i32) (i32.const 3)) + (func (result i32) (i32.const 4)) + (func (result i32) (i32.const 5)) + (func (result i32) (i32.const 6)) + (func (result i32) (i32.const 7)) + (func (result i32) (i32.const 8)) + (func (result i32) (i32.const 9)) + (func (export "test") + (table.init $t0 1 (i32.const 30) (i32.const 4) (i32.const 0)) + )) +(invoke "test") + +(module + (table $t0 30 30 funcref) + (table $t1 28 28 funcref) + (elem (table $t0) (i32.const 2) func 3 1 4 1) + (elem funcref + (ref.func 2) (ref.func 7) (ref.func 1) (ref.func 8)) + (elem (table $t0) (i32.const 12) func 7 5 2 3 6) + (elem funcref + (ref.func 5) (ref.func 9) (ref.func 2) (ref.func 7) (ref.func 6)) + (func (result i32) (i32.const 0)) + (func (result i32) (i32.const 1)) + (func (result i32) (i32.const 2)) + (func (result i32) (i32.const 3)) + (func (result i32) (i32.const 4)) + (func (result i32) (i32.const 5)) + (func (result i32) (i32.const 6)) + (func (result i32) (i32.const 7)) + (func (result i32) (i32.const 8)) + (func (result i32) (i32.const 9)) + (func (export "test") + (table.init $t0 1 (i32.const 31) (i32.const 5) (i32.const 0)) + )) +(assert_trap (invoke "test") "out of bounds") + +(module + (table $t0 30 30 funcref) + (table $t1 28 28 funcref) + (elem (table $t1) (i32.const 2) func 3 1 4 1) (elem funcref (ref.func 2) (ref.func 7) (ref.func 1) (ref.func 8)) - (elem (i32.const 12) 7 5 2 3 6) + (elem (table $t1) (i32.const 12) func 7 5 2 3 6) (elem funcref (ref.func 5) (ref.func 9) (ref.func 2) (ref.func 7) (ref.func 6)) (func (result i32) (i32.const 0)) @@ -398,16 +760,17 @@ (func (result i32) (i32.const 8)) (func (result i32) (i32.const 9)) (func (export "test") - (table.init 1 (i32.const 28) (i32.const 1) (i32.const 3)) + (table.init $t1 1 (i32.const 26) (i32.const 1) (i32.const 3)) )) (assert_trap (invoke "test") "out of bounds") (module - (table 30 30 funcref) - (elem (i32.const 2) 3 1 4 1) + (table $t0 30 30 funcref) + (table $t1 28 28 funcref) + (elem (table $t1) (i32.const 2) func 3 1 4 1) (elem funcref (ref.func 2) (ref.func 7) (ref.func 1) (ref.func 8)) - (elem (i32.const 12) 7 5 2 3 6) + (elem (table $t1) (i32.const 12) func 7 5 2 3 6) (elem funcref (ref.func 5) (ref.func 9) (ref.func 2) (ref.func 7) (ref.func 6)) (func (result i32) (i32.const 0)) @@ -421,16 +784,17 @@ (func (result i32) (i32.const 8)) (func (result i32) (i32.const 9)) (func (export "test") - (table.init 1 (i32.const 12) (i32.const 4) (i32.const 0)) + (table.init $t1 1 (i32.const 12) (i32.const 4) (i32.const 0)) )) (invoke "test") (module - (table 30 30 funcref) - (elem (i32.const 2) 3 1 4 1) + (table $t0 30 30 funcref) + (table $t1 28 28 funcref) + (elem (table $t1) (i32.const 2) func 3 1 4 1) (elem funcref (ref.func 2) (ref.func 7) (ref.func 1) (ref.func 8)) - (elem (i32.const 12) 7 5 2 3 6) + (elem (table $t1) (i32.const 12) func 7 5 2 3 6) (elem funcref (ref.func 5) (ref.func 9) (ref.func 2) (ref.func 7) (ref.func 6)) (func (result i32) (i32.const 0)) @@ -444,16 +808,17 @@ (func (result i32) (i32.const 8)) (func (result i32) (i32.const 9)) (func (export "test") - (table.init 1 (i32.const 12) (i32.const 5) (i32.const 0)) + (table.init $t1 1 (i32.const 12) (i32.const 5) (i32.const 0)) )) (assert_trap (invoke "test") "out of bounds") (module - (table 30 30 funcref) - (elem (i32.const 2) 3 1 4 1) + (table $t0 30 30 funcref) + (table $t1 28 28 funcref) + (elem (table $t1) (i32.const 2) func 3 1 4 1) (elem funcref (ref.func 2) (ref.func 7) (ref.func 1) (ref.func 8)) - (elem (i32.const 12) 7 5 2 3 6) + (elem (table $t1) (i32.const 12) func 7 5 2 3 6) (elem funcref (ref.func 5) (ref.func 9) (ref.func 2) (ref.func 7) (ref.func 6)) (func (result i32) (i32.const 0)) @@ -467,16 +832,17 @@ (func (result i32) (i32.const 8)) (func (result i32) (i32.const 9)) (func (export "test") - (table.init 1 (i32.const 30) (i32.const 2) (i32.const 0)) + (table.init $t1 1 (i32.const 28) (i32.const 2) (i32.const 0)) )) (invoke "test") (module - (table 30 30 funcref) - (elem (i32.const 2) 3 1 4 1) + (table $t0 30 30 funcref) + (table $t1 28 28 funcref) + (elem (table $t1) (i32.const 2) func 3 1 4 1) (elem funcref (ref.func 2) (ref.func 7) (ref.func 1) (ref.func 8)) - (elem (i32.const 12) 7 5 2 3 6) + (elem (table $t1) (i32.const 12) func 7 5 2 3 6) (elem funcref (ref.func 5) (ref.func 9) (ref.func 2) (ref.func 7) (ref.func 6)) (func (result i32) (i32.const 0)) @@ -490,16 +856,17 @@ (func (result i32) (i32.const 8)) (func (result i32) (i32.const 9)) (func (export "test") - (table.init 1 (i32.const 31) (i32.const 2) (i32.const 0)) + (table.init $t1 1 (i32.const 29) (i32.const 2) (i32.const 0)) )) (assert_trap (invoke "test") "out of bounds") (module - (table 30 30 funcref) - (elem (i32.const 2) 3 1 4 1) + (table $t0 30 30 funcref) + (table $t1 28 28 funcref) + (elem (table $t1) (i32.const 2) func 3 1 4 1) (elem funcref (ref.func 2) (ref.func 7) (ref.func 1) (ref.func 8)) - (elem (i32.const 12) 7 5 2 3 6) + (elem (table $t1) (i32.const 12) func 7 5 2 3 6) (elem funcref (ref.func 5) (ref.func 9) (ref.func 2) (ref.func 7) (ref.func 6)) (func (result i32) (i32.const 0)) @@ -513,16 +880,17 @@ (func (result i32) (i32.const 8)) (func (result i32) (i32.const 9)) (func (export "test") - (table.init 1 (i32.const 30) (i32.const 4) (i32.const 0)) + (table.init $t1 1 (i32.const 28) (i32.const 4) (i32.const 0)) )) (invoke "test") (module - (table 30 30 funcref) - (elem (i32.const 2) 3 1 4 1) + (table $t0 30 30 funcref) + (table $t1 28 28 funcref) + (elem (table $t1) (i32.const 2) func 3 1 4 1) (elem funcref (ref.func 2) (ref.func 7) (ref.func 1) (ref.func 8)) - (elem (i32.const 12) 7 5 2 3 6) + (elem (table $t1) (i32.const 12) func 7 5 2 3 6) (elem funcref (ref.func 5) (ref.func 9) (ref.func 2) (ref.func 7) (ref.func 6)) (func (result i32) (i32.const 0)) @@ -536,7 +904,7 @@ (func (result i32) (i32.const 8)) (func (result i32) (i32.const 9)) (func (export "test") - (table.init 1 (i32.const 31) (i32.const 5) (i32.const 0)) + (table.init $t1 1 (i32.const 29) (i32.const 5) (i32.const 0)) )) (assert_trap (invoke "test") "out of bounds") diff --git a/test/meta/Makefile b/test/meta/Makefile index 7f9e680552..20e9adb2f5 100644 --- a/test/meta/Makefile +++ b/test/meta/Makefile @@ -1,7 +1,7 @@ SHARED_MEM=false # SpiderMonkey shell -JSSHELL=~/m-i/js/src/build-debug/dist/bin/js -e 'const WITH_SHARED_MEMORY=$(SHARED_MEM);' -f common.js +JSSHELL=~/mozilla-central/js/src/build-debug/dist/bin/js -e 'const WITH_SHARED_MEMORY=$(SHARED_MEM);' -f common.js # Node.js #JSSHELL=./noderun.sh $(SHARED_MEM) diff --git a/test/meta/common.js b/test/meta/common.js index 16d80726a6..9a277e44f2 100644 --- a/test/meta/common.js +++ b/test/meta/common.js @@ -3,6 +3,7 @@ const PAGESIZE = 65536; function print_origin(origin) { print(";;"); print(";; Generated by ../meta/" + origin); + print(";; DO NOT EDIT THIS FILE. CHANGE THE SOURCE AND REGENERATE."); print(";;"); } diff --git a/test/meta/generate_table_copy.js b/test/meta/generate_table_copy.js index 867189445e..63aa53b06b 100644 --- a/test/meta/generate_table_copy.js +++ b/test/meta/generate_table_copy.js @@ -26,7 +26,7 @@ function emit_a() { // value 0 to 9 indicating the function called, or will throw an exception if // the table entry is empty. -function emit_b(insn) { +function emit_b(insn, t0, t1) { print( ` (module @@ -36,13 +36,16 @@ function emit_b(insn) { (import "a" "ef2" (func (result i32))) (import "a" "ef3" (func (result i32))) (import "a" "ef4" (func (result i32))) ;; index 4 - (table 30 30 funcref) - (elem (i32.const 2) 3 1 4 1) + (table $t0 30 30 funcref) + (table $t1 30 30 funcref) + (elem (table $t${t0}) (i32.const 2) func 3 1 4 1) (elem funcref (ref.func 2) (ref.func 7) (ref.func 1) (ref.func 8)) - (elem (i32.const 12) 7 5 2 3 6) + (elem (table $t${t0}) (i32.const 12) func 7 5 2 3 6) (elem funcref (ref.func 5) (ref.func 9) (ref.func 2) (ref.func 7) (ref.func 6)) + (elem (table $t${t1}) (i32.const 3) func 1 3 1 4) + (elem (table $t${t1}) (i32.const 11) func 6 3 2 5 7) (func (result i32) (i32.const 5)) ;; index 5 (func (result i32) (i32.const 6)) (func (result i32) (i32.const 7)) @@ -50,8 +53,10 @@ function emit_b(insn) { (func (result i32) (i32.const 9)) ;; index 9 (func (export "test") ${insn}) - (func (export "check") (param i32) (result i32) - (call_indirect (type 0) (local.get 0))) + (func (export "check_t0") (param i32) (result i32) + (call_indirect $t${t0} (type 0) (local.get 0))) + (func (export "check_t1") (param i32) (result i32) + (call_indirect $t${t1} (type 0) (local.get 0))) ) `); } @@ -60,16 +65,29 @@ function emit_b(insn) { // given |instruction| to modify the table, and then probes the table by making // indirect calls, one for each element of |expected_result_vector|. The // results are compared to those in the vector. +// +// "dest_table" may be t0 or t1. -function tab_test(instruction, expected_result_vector) { - emit_b(instruction); +function tab_test(args, t0, t1, dest_table, expected_t0, expected_t1) { + if (typeof args != "string") + emit_b("(nop)", t0, t1); + else + emit_b(`(table.copy $t${dest_table} $t${t0} ${args})`, t0, t1); print(`(invoke "test")`); - for (let i = 0; i < expected_result_vector.length; i++) { - let expected = expected_result_vector[i]; + for (let i = 0; i < expected_t0.length; i++) { + let expected = expected_t0[i]; if (expected === undefined) { - print(`(assert_trap (invoke "check" (i32.const ${i})) "uninitialized element")`); + print(`(assert_trap (invoke "check_t0" (i32.const ${i})) "uninitialized element")`); } else { - print(`(assert_return (invoke "check" (i32.const ${i})) (i32.const ${expected}))`); + print(`(assert_return (invoke "check_t0" (i32.const ${i})) (i32.const ${expected}))`); + } + } + for (let i = 0; i < expected_t1.length; i++) { + let expected = expected_t1[i]; + if (expected === undefined) { + print(`(assert_trap (invoke "check_t1" (i32.const ${i})) "uninitialized element")`); + } else { + print(`(assert_return (invoke "check_t1" (i32.const ${i})) (i32.const ${expected}))`); } } } @@ -80,38 +98,59 @@ emit_a(); // to count through the vector entries when debugging. let e = undefined; -// This just gives the initial state of the table, with its active -// initialisers applied -tab_test("(nop)", - [e,e,3,1,4, 1,e,e,e,e, e,e,7,5,2, 3,6,e,e,e, e,e,e,e,e, e,e,e,e,e]); - -// Copy non-null over non-null -tab_test("(table.copy (i32.const 13) (i32.const 2) (i32.const 3))", - [e,e,3,1,4, 1,e,e,e,e, e,e,7,3,1, 4,6,e,e,e, e,e,e,e,e, e,e,e,e,e]); - -// Copy non-null over null -tab_test("(table.copy (i32.const 25) (i32.const 15) (i32.const 2))", - [e,e,3,1,4, 1,e,e,e,e, e,e,7,5,2, 3,6,e,e,e, e,e,e,e,e, 3,6,e,e,e]); - -// Copy null over non-null -tab_test("(table.copy (i32.const 13) (i32.const 25) (i32.const 3))", - [e,e,3,1,4, 1,e,e,e,e, e,e,7,e,e, e,6,e,e,e, e,e,e,e,e, e,e,e,e,e]); - -// Copy null over null -tab_test("(table.copy (i32.const 20) (i32.const 22) (i32.const 4))", - [e,e,3,1,4, 1,e,e,e,e, e,e,7,5,2, 3,6,e,e,e, e,e,e,e,e, e,e,e,e,e]); - -// Copy null and non-null entries, non overlapping -tab_test("(table.copy (i32.const 25) (i32.const 1) (i32.const 3))", - [e,e,3,1,4, 1,e,e,e,e, e,e,7,5,2, 3,6,e,e,e, e,e,e,e,e, e,3,1,e,e]); - -// Copy null and non-null entries, overlapping, backwards -tab_test("(table.copy (i32.const 10) (i32.const 12) (i32.const 7))", - [e,e,3,1,4, 1,e,e,e,e, 7,5,2,3,6, e,e,e,e,e, e,e,e,e,e, e,e,e,e,e]); - -// Copy null and non-null entries, overlapping, forwards -tab_test("(table.copy (i32.const 12) (i32.const 10) (i32.const 7))", - [e,e,3,1,4, 1,e,e,e,e, e,e,e,e,7, 5,2,3,6,e, e,e,e,e,e, e,e,e,e,e]); +for ( let table of [0,1] ) { + let other_table = (table + 1) % 2; + + // Tests for copying in a single table. + + // This just gives the initial state of the table, with its active + // initialisers applied + tab_test(false, table, other_table, table, + [e,e,3,1,4, 1,e,e,e,e, e,e,7,5,2, 3,6,e,e,e, e,e,e,e,e, e,e,e,e,e], + [e,e,e,1,3, 1,4,e,e,e, e,6,3,2,5, 7,e,e,e,e, e,e,e,e,e, e,e,e,e,e]); + + // Copy non-null over non-null + tab_test("(i32.const 13) (i32.const 2) (i32.const 3)", table, other_table, table, + [e,e,3,1,4, 1,e,e,e,e, e,e,7,3,1, 4,6,e,e,e, e,e,e,e,e, e,e,e,e,e], + [e,e,e,1,3, 1,4,e,e,e, e,6,3,2,5, 7,e,e,e,e, e,e,e,e,e, e,e,e,e,e]); + + // Copy non-null over null + tab_test("(i32.const 25) (i32.const 15) (i32.const 2)", table, other_table, table, + [e,e,3,1,4, 1,e,e,e,e, e,e,7,5,2, 3,6,e,e,e, e,e,e,e,e, 3,6,e,e,e], + [e,e,e,1,3, 1,4,e,e,e, e,6,3,2,5, 7,e,e,e,e, e,e,e,e,e, e,e,e,e,e]); + + // Copy null over non-null + tab_test("(i32.const 13) (i32.const 25) (i32.const 3)", table, other_table, table, + [e,e,3,1,4, 1,e,e,e,e, e,e,7,e,e, e,6,e,e,e, e,e,e,e,e, e,e,e,e,e], + [e,e,e,1,3, 1,4,e,e,e, e,6,3,2,5, 7,e,e,e,e, e,e,e,e,e, e,e,e,e,e]); + + // Copy null over null + tab_test("(i32.const 20) (i32.const 22) (i32.const 4)", table, other_table, table, + [e,e,3,1,4, 1,e,e,e,e, e,e,7,5,2, 3,6,e,e,e, e,e,e,e,e, e,e,e,e,e], + [e,e,e,1,3, 1,4,e,e,e, e,6,3,2,5, 7,e,e,e,e, e,e,e,e,e, e,e,e,e,e]); + + // Copy null and non-null entries, non overlapping + tab_test("(i32.const 25) (i32.const 1) (i32.const 3)", table, other_table, table, + [e,e,3,1,4, 1,e,e,e,e, e,e,7,5,2, 3,6,e,e,e, e,e,e,e,e, e,3,1,e,e], + [e,e,e,1,3, 1,4,e,e,e, e,6,3,2,5, 7,e,e,e,e, e,e,e,e,e, e,e,e,e,e]); + + // Copy null and non-null entries, overlapping, backwards + tab_test("(i32.const 10) (i32.const 12) (i32.const 7)", table, other_table, table, + [e,e,3,1,4, 1,e,e,e,e, 7,5,2,3,6, e,e,e,e,e, e,e,e,e,e, e,e,e,e,e], + [e,e,e,1,3, 1,4,e,e,e, e,6,3,2,5, 7,e,e,e,e, e,e,e,e,e, e,e,e,e,e]); + + // Copy null and non-null entries, overlapping, forwards + tab_test("(i32.const 12) (i32.const 10) (i32.const 7)", table, other_table, table, + [e,e,3,1,4, 1,e,e,e,e, e,e,e,e,7, 5,2,3,6,e, e,e,e,e,e, e,e,e,e,e], + [e,e,e,1,3, 1,4,e,e,e, e,6,3,2,5, 7,e,e,e,e, e,e,e,e,e, e,e,e,e,e]); + + // Tests for copying from one table to the other. Here, overlap and copy + // direction don't matter. + + tab_test("(i32.const 10) (i32.const 0) (i32.const 20)", table, other_table, other_table, + [e,e,3,1,4, 1,e,e,e,e, e,e,7,5,2, 3,6,e,e,e, e,e,e,e,e, e,e,e,e,e], + [e,e,e,1,3, 1,4,e,e,e, e,e,3,1,4, 1,e,e,e,e, e,e,7,5,2, 3,6,e,e,e]); +} // Out-of-bounds checks. @@ -119,11 +158,12 @@ function do_test(insn1, insn2, errText) { print(` (module - (table 30 30 funcref) - (elem (i32.const 2) 3 1 4 1) + (table $t0 30 30 funcref) + (table $t1 30 30 funcref) + (elem (table $t0) (i32.const 2) func 3 1 4 1) (elem funcref (ref.func 2) (ref.func 7) (ref.func 1) (ref.func 8)) - (elem (i32.const 12) 7 5 2 3 6) + (elem (table $t0) (i32.const 12) func 7 5 2 3 6) (elem funcref (ref.func 5) (ref.func 9) (ref.func 2) (ref.func 7) (ref.func 6)) (func (result i32) (i32.const 0)) @@ -156,63 +196,65 @@ function tab_test_nofail(insn1, insn2) { do_test(insn1, insn2, undefined, undefined); } -// Here we test the boundary-failure cases. The table's valid indices are 0..29 -// inclusive. - -// copy: dst range invalid -tab_test2("(table.copy (i32.const 28) (i32.const 1) (i32.const 3))", - "", - "out of bounds"); - -// copy: dst wraparound end of 32 bit offset space -tab_test2("(table.copy (i32.const 0xFFFFFFFE) (i32.const 1) (i32.const 2))", - "", - "out of bounds"); - -// copy: src range invalid -tab_test2("(table.copy (i32.const 15) (i32.const 25) (i32.const 6))", - "", - "out of bounds"); - -// copy: src wraparound end of 32 bit offset space -tab_test2("(table.copy (i32.const 15) (i32.const 0xFFFFFFFE) (i32.const 2))", - "", - "out of bounds"); - -// copy: zero length with both offsets in-bounds is OK -tab_test_nofail( - "(table.copy (i32.const 15) (i32.const 25) (i32.const 0))", - ""); - -// copy: zero length with dst offset out of bounds at the end of the table is allowed -tab_test2("(table.copy (i32.const 30) (i32.const 15) (i32.const 0))", - "", - undefined); - -// copy: zero length with dst offset out of bounds past the end of the table is not allowed -tab_test2("(table.copy (i32.const 31) (i32.const 15) (i32.const 0))", - "", - "out of bounds"); - -// copy: zero length with src offset out of bounds at the end of the table is allowed -tab_test2("(table.copy (i32.const 15) (i32.const 30) (i32.const 0))", - "", - undefined); - -// copy: zero length with src offset out of bounds past the end of the table is not allowed -tab_test2("(table.copy (i32.const 15) (i32.const 31) (i32.const 0))", - "", - "out of bounds"); - -// copy: zero length with both dst and src offset out of bounds at the end of the table is allowed -tab_test2("(table.copy (i32.const 30) (i32.const 30) (i32.const 0))", - "", - undefined); - -// copy: zero length with both dst and src offset out of bounds past the end of the table is not allowed -tab_test2("(table.copy (i32.const 31) (i32.const 31) (i32.const 0))", - "", - "out of bounds"); +for ( let dest of ["$t0","$t1"] ) { + // Here we test the boundary-failure cases. The table's valid indices are 0..29 + // inclusive. + + // copy: dst range invalid + tab_test2(`(table.copy ${dest} $t0 (i32.const 28) (i32.const 1) (i32.const 3))`, + "", + "out of bounds"); + + // copy: dst wraparound end of 32 bit offset space + tab_test2(`(table.copy ${dest} $t0 (i32.const 0xFFFFFFFE) (i32.const 1) (i32.const 2))`, + "", + "out of bounds"); + + // copy: src range invalid + tab_test2(`(table.copy ${dest} $t0 (i32.const 15) (i32.const 25) (i32.const 6))`, + "", + "out of bounds"); + + // copy: src wraparound end of 32 bit offset space + tab_test2(`(table.copy ${dest} $t0 (i32.const 15) (i32.const 0xFFFFFFFE) (i32.const 2))`, + "", + "out of bounds"); + + // copy: zero length with both offsets in-bounds is OK + tab_test_nofail( + `(table.copy ${dest} $t0 (i32.const 15) (i32.const 25) (i32.const 0))`, + ""); + + // copy: zero length with dst offset out of bounds at the end of the table is allowed + tab_test2(`(table.copy ${dest} $t0 (i32.const 30) (i32.const 15) (i32.const 0))`, + "", + undefined); + + // copy: zero length with dst offset out of bounds past the end of the table is not allowed + tab_test2(`(table.copy ${dest} $t0 (i32.const 31) (i32.const 15) (i32.const 0))`, + "", + "out of bounds"); + + // copy: zero length with src offset out of bounds at the end of the table is allowed + tab_test2(`(table.copy ${dest} $t0 (i32.const 15) (i32.const 30) (i32.const 0))`, + "", + undefined); + + // copy: zero length with src offset out of bounds past the end of the table is not allowed + tab_test2(`(table.copy ${dest} $t0 (i32.const 15) (i32.const 31) (i32.const 0))`, + "", + "out of bounds"); + + // copy: zero length with both dst and src offset out of bounds at the end of the table is allowed + tab_test2(`(table.copy ${dest} $t0 (i32.const 30) (i32.const 30) (i32.const 0))`, + "", + undefined); + + // copy: zero length with both dst and src offset out of bounds past the end of the table is not allowed + tab_test2(`(table.copy ${dest} $t0 (i32.const 31) (i32.const 31) (i32.const 0))`, + "", + "out of bounds"); +} // table.copy: out of bounds of the table for the source or target, but should // perform the operation up to the appropriate bound. Major cases: diff --git a/test/meta/generate_table_init.js b/test/meta/generate_table_init.js index 9329d937d7..4bdef68017 100644 --- a/test/meta/generate_table_init.js +++ b/test/meta/generate_table_init.js @@ -26,7 +26,7 @@ function emit_a() { // value 0 to 9 indicating the function called, or will throw an exception if // the table entry is empty. -function emit_b(insn) { +function emit_b(insn, table) { print( ` (module @@ -36,11 +36,12 @@ function emit_b(insn) { (import "a" "ef2" (func (result i32))) (import "a" "ef3" (func (result i32))) (import "a" "ef4" (func (result i32))) ;; index 4 - (table 30 30 funcref) - (elem (i32.const 2) 3 1 4 1) + (table $t0 30 30 funcref) + (table $t1 30 30 funcref) + (elem (table $t${table}) (i32.const 2) func 3 1 4 1) (elem funcref (ref.func 2) (ref.func 7) (ref.func 1) (ref.func 8)) - (elem (i32.const 12) 7 5 2 3 6) + (elem (table $t${table}) (i32.const 12) func 7 5 2 3 6) (elem funcref (ref.func 5) (ref.func 9) (ref.func 2) (ref.func 7) (ref.func 6)) (func (result i32) (i32.const 5)) ;; index 5 @@ -51,7 +52,7 @@ function emit_b(insn) { (func (export "test") ${insn}) (func (export "check") (param i32) (result i32) - (call_indirect (type 0) (local.get 0))) + (call_indirect $t${table} (type 0) (local.get 0))) ) `); } @@ -61,8 +62,8 @@ function emit_b(insn) { // indirect calls, one for each element of |expected_result_vector|. The // results are compared to those in the vector. -function tab_test(instruction, expected_result_vector) { - emit_b(instruction); +function tab_test(instruction, table, expected_result_vector) { + emit_b(instruction, table); print(`(invoke "test")`); for (let i = 0; i < expected_result_vector.length; i++) { let expected = expected_result_vector[i]; @@ -80,26 +81,31 @@ emit_a(); // to count through the vector entries when debugging. let e = undefined; -// Passive init that overwrites all-null entries -tab_test("(table.init 1 (i32.const 7) (i32.const 0) (i32.const 4))", - [e,e,3,1,4, 1,e,2,7,1, 8,e,7,5,2, 3,6,e,e,e, e,e,e,e,e, e,e,e,e,e]); - -// Passive init that overwrites existing active-init-created entries -tab_test("(table.init 3 (i32.const 15) (i32.const 1) (i32.const 3))", - [e,e,3,1,4, 1,e,e,e,e, e,e,7,5,2, 9,2,7,e,e, e,e,e,e,e, e,e,e,e,e]); - -// Perform active and passive initialisation and then multiple copies -tab_test(`(table.init 1 (i32.const 7) (i32.const 0) (i32.const 4)) - (elem.drop 1) - (table.init 3 (i32.const 15) (i32.const 1) (i32.const 3)) - (elem.drop 3) - (table.copy (i32.const 20) (i32.const 15) (i32.const 5)) - (table.copy (i32.const 21) (i32.const 29) (i32.const 1)) - (table.copy (i32.const 24) (i32.const 10) (i32.const 1)) - (table.copy (i32.const 13) (i32.const 11) (i32.const 4)) - (table.copy (i32.const 19) (i32.const 20) (i32.const 5))`, - [e,e,3,1,4, 1,e,2,7,1, 8,e,7,e,7, 5,2,7,e,9, e,7,e,8,8, e,e,e,e,e]); - +for ( let table of [0, 1] ) { + // Passive init that overwrites all-null entries + tab_test(`(table.init $t${table} 1 (i32.const 7) (i32.const 0) (i32.const 4))`, + table, + [e,e,3,1,4, 1,e,2,7,1, 8,e,7,5,2, 3,6,e,e,e, e,e,e,e,e, e,e,e,e,e]); + + // Passive init that overwrites existing active-init-created entries + tab_test(`(table.init $t${table} 3 (i32.const 15) (i32.const 1) (i32.const 3))`, + table, + [e,e,3,1,4, 1,e,e,e,e, e,e,7,5,2, 9,2,7,e,e, e,e,e,e,e, e,e,e,e,e]); + + // Perform active and passive initialisation and then multiple copies + tab_test( + `(table.init $t${table} 1 (i32.const 7) (i32.const 0) (i32.const 4)) + (elem.drop 1) + (table.init $t${table} 3 (i32.const 15) (i32.const 1) (i32.const 3)) + (elem.drop 3) + (table.copy $t${table} ${table} (i32.const 20) (i32.const 15) (i32.const 5)) + (table.copy $t${table} ${table} (i32.const 21) (i32.const 29) (i32.const 1)) + (table.copy $t${table} ${table} (i32.const 24) (i32.const 10) (i32.const 1)) + (table.copy $t${table} ${table} (i32.const 13) (i32.const 11) (i32.const 4)) + (table.copy $t${table} ${table} (i32.const 19) (i32.const 20) (i32.const 5))`, + table, + [e,e,3,1,4, 1,e,2,7,1, 8,e,7,e,7, 5,2,7,e,9, e,7,e,8,8, e,e,e,e,e]); +} // elem.drop requires a table, minimally print( @@ -141,15 +147,19 @@ print( "unknown table 0") `); -function do_test(insn1, insn2, errText) +let tab0_len = 30; +let tab1_len = 28; + +function do_test(insn1, insn2, table, errText) { print(` (module - (table 30 30 funcref) - (elem (i32.const 2) 3 1 4 1) + (table $t0 ${tab0_len} ${tab0_len} funcref) + (table $t1 ${tab1_len} ${tab1_len} funcref) + (elem (table $t${table}) (i32.const 2) func 3 1 4 1) (elem funcref (ref.func 2) (ref.func 7) (ref.func 1) (ref.func 8)) - (elem (i32.const 12) 7 5 2 3 6) + (elem (table $t${table}) (i32.const 12) func 7 5 2 3 6) (elem funcref (ref.func 5) (ref.func 9) (ref.func 2) (ref.func 7) (ref.func 6)) (func (result i32) (i32.const 0)) @@ -173,20 +183,20 @@ function do_test(insn1, insn2, errText) } } -function tab_test1(insn1, errText) { - do_test(insn1, "", errText); +function tab_test1(insn1, table, errText) { + do_test(insn1, "", table, errText); } function tab_test2(insn1, insn2, errText) { - do_test(insn1, insn2, errText); + do_test(insn1, insn2, 0, errText); } // drop with elem seg ix indicating an active segment -tab_test1("(elem.drop 2)", +tab_test1("(elem.drop 2)", 0, undefined); // init with elem seg ix indicating an active segment -tab_test1("(table.init 2 (i32.const 12) (i32.const 1) (i32.const 1))", +tab_test1("(table.init 2 (i32.const 12) (i32.const 1) (i32.const 1))", 0, "out of bounds"); // init, using an elem seg ix more than once is OK @@ -206,46 +216,58 @@ tab_test2("(elem.drop 1)", "out of bounds"); // init: seg ix is valid passive, but length to copy > len of seg -tab_test1("(table.init 1 (i32.const 12) (i32.const 0) (i32.const 5))", +tab_test1("(table.init 1 (i32.const 12) (i32.const 0) (i32.const 5))", 0, "out of bounds"); // init: seg ix is valid passive, but implies copying beyond end of seg -tab_test1("(table.init 1 (i32.const 12) (i32.const 2) (i32.const 3))", +tab_test1("(table.init 1 (i32.const 12) (i32.const 2) (i32.const 3))", 0, "out of bounds"); -// init: seg ix is valid passive, but implies copying beyond end of dst -tab_test1("(table.init 1 (i32.const 28) (i32.const 1) (i32.const 3))", - "out of bounds"); - -// init: seg ix is valid passive, zero len, and src offset out of bounds at the -// end of the table - this is allowed -tab_test1("(table.init 1 (i32.const 12) (i32.const 4) (i32.const 0))", - undefined); - -// init: seg ix is valid passive, zero len, and src offset out of bounds past the -// end of the table - this is not allowed -tab_test1("(table.init 1 (i32.const 12) (i32.const 5) (i32.const 0))", - "out of bounds"); - -// init: seg ix is valid passive, zero len, and dst offset out of bounds at the -// end of the table - this is allowed -tab_test1("(table.init 1 (i32.const 30) (i32.const 2) (i32.const 0))", - undefined); - -// init: seg ix is valid passive, zero len, and dst offset out of bounds past the -// end of the table - this is not allowed -tab_test1("(table.init 1 (i32.const 31) (i32.const 2) (i32.const 0))", - "out of bounds"); - -// init: seg ix is valid passive, zero len, and dst and src offsets out of bounds -// at the end of the table - this is allowed -tab_test1("(table.init 1 (i32.const 30) (i32.const 4) (i32.const 0))", - undefined); - -// init: seg ix is valid passive, zero len, and src/dst offset out of bounds past the -// end of the table - this is not allowed -tab_test1("(table.init 1 (i32.const 31) (i32.const 5) (i32.const 0))", - "out of bounds"); +// Tables are of different length with t1 shorter than t0, to test that we're not +// using t0's limit for t1's bound + +for ( let [table, oobval] of [[0,30],[1,28]] ) { + // init: seg ix is valid passive, but implies copying beyond end of dst + tab_test1(`(table.init $t${table} 1 (i32.const ${oobval-2}) (i32.const 1) (i32.const 3))`, + table, + "out of bounds"); + + // init: seg ix is valid passive, zero len, and src offset out of bounds at the + // end of the table - this is allowed + tab_test1(`(table.init $t${table} 1 (i32.const 12) (i32.const 4) (i32.const 0))`, + table, + undefined); + + // init: seg ix is valid passive, zero len, and src offset out of bounds past the + // end of the table - this is not allowed + tab_test1(`(table.init $t${table} 1 (i32.const 12) (i32.const 5) (i32.const 0))`, + table, + "out of bounds"); + + // init: seg ix is valid passive, zero len, and dst offset out of bounds at the + // end of the table - this is allowed + tab_test1(`(table.init $t${table} 1 (i32.const ${oobval}) (i32.const 2) (i32.const 0))`, + table, + undefined); + + // init: seg ix is valid passive, zero len, and dst offset out of bounds past the + // end of the table - this is not allowed + tab_test1(`(table.init $t${table} 1 (i32.const ${oobval+1}) (i32.const 2) (i32.const 0))`, + table, + "out of bounds"); + + // init: seg ix is valid passive, zero len, and dst and src offsets out of bounds + // at the end of the table - this is allowed + tab_test1(`(table.init $t${table} 1 (i32.const ${oobval}) (i32.const 4) (i32.const 0))`, + table, + undefined); + + // init: seg ix is valid passive, zero len, and src/dst offset out of bounds past the + // end of the table - this is not allowed + tab_test1(`(table.init $t${table} 1 (i32.const ${oobval+1}) (i32.const 5) (i32.const 0))`, + table, + "out of bounds"); +} // invalid argument types { From 9f6a39f9a045d2b688de7495e3006f514e638dc7 Mon Sep 17 00:00:00 2001 From: Andreas Rossberg Date: Thu, 2 Apr 2020 14:27:27 +0200 Subject: [PATCH 156/199] Merge fixups --- test/core/binary.wast | 2 +- test/core/table.wast | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/test/core/binary.wast b/test/core/binary.wast index 4dd5d10a5f..91cdd3598b 100644 --- a/test/core/binary.wast +++ b/test/core/binary.wast @@ -1077,7 +1077,7 @@ ;; function 0 "\02\00" "\0b") ;; end - "invalid reference type") + "malformed reference type") ;; passive element segment containing opcode ref.func (module binary diff --git a/test/core/table.wast b/test/core/table.wast index 0bc43ca60c..0bd04f5cc4 100644 --- a/test/core/table.wast +++ b/test/core/table.wast @@ -8,8 +8,8 @@ (module (table 0 65536 funcref)) (module (table 0 0xffff_ffff funcref)) -(assert_invalid (module (table 0 funcref) (table 0 funcref)) "multiple tables") -(assert_invalid (module (table (import "spectest" "table") 0 funcref) (table 0 funcref)) "multiple tables") +(module (table 0 funcref) (table 0 funcref)) +(module (table (import "spectest" "table") 0 funcref) (table 0 funcref)) (assert_invalid (module (elem (i32.const 0))) "unknown table") (assert_invalid (module (elem (i32.const 0) $f) (func $f)) "unknown table") From c0f30ca46279ccd114b2f64b2b939ff60107e6ba Mon Sep 17 00:00:00 2001 From: Ryan Hunt Date: Fri, 3 Apr 2020 00:30:10 -0500 Subject: [PATCH 157/199] [test] Update JS harnesses to match interpreter harness (#86) --- test/harness/async_index.js | 42 ++++++++++++++++++++++++++++++--- test/harness/sync_index.js | 47 ++++++++++++++++++++++++++++++++----- 2 files changed, 80 insertions(+), 9 deletions(-) diff --git a/test/harness/async_index.js b/test/harness/async_index.js index 3189ff1a70..094999254c 100644 --- a/test/harness/async_index.js +++ b/test/harness/async_index.js @@ -52,6 +52,22 @@ const EXPECT_INVALID = false; /* DATA **********************************************************************/ +let hostrefs = {}; +let hostsym = Symbol("hostref"); +function hostref(s) { + if (! (s in hostrefs)) hostrefs[s] = {[hostsym]: s}; + return hostrefs[s]; +} +function is_hostref(x) { + return (x !== null && hostsym in x) ? 1 : 0; +} +function is_funcref(x) { + return typeof x === "function" ? 1 : 0; +} +function eq_ref(x, y) { + return x === y ? 1 : 0; +} + // Default imports. var registry = {}; @@ -67,6 +83,10 @@ function reinitializeRegistry() { chain = chain.then(_ => { let spectest = { + hostref: hostref, + is_hostref: is_hostref, + is_funcref: is_funcref, + eq_ref: eq_ref, print: console.log.bind(console), print_i32: console.log.bind(console), print_i32_f32: console.log.bind(console), @@ -180,9 +200,9 @@ function instance(bytes, imports, valid = true) { return chain; } -function exports(name, instance) { +function exports(instance) { return instance.then(inst => { - return { [name]: inst.exports }; + return { module: inst.exports, spectest: registry.spectest }; }); } @@ -243,7 +263,23 @@ function assert_return(action, expected) { .then( values => { uniqueTest(_ => { - assert_equals(values[0], expected, loc); + let actual = values[0]; + switch (expected) { + case "nan:canonical": + case "nan:arithmetic": + // Note that JS can't reliably distinguish different NaN values, + // so there's no good way to test that it's a canonical NaN. + assert_true(Number.isNaN(actual), `expected NaN, observed ${actual}.`); + return; + case "ref.func": + assert_true(typeof actual === "function", `expected Wasm function, got ${actual}`); + return; + case "ref.any": + assert_true(actual !== null, `expected Wasm reference, got ${actual}`); + return; + default: + assert_equals(actual, expected); + } }, test); }, error => { diff --git a/test/harness/sync_index.js b/test/harness/sync_index.js index ec919b7e60..a060e446ef 100644 --- a/test/harness/sync_index.js +++ b/test/harness/sync_index.js @@ -66,6 +66,22 @@ const EXPECT_INVALID = false; /* DATA **********************************************************************/ +let hostrefs = {}; +let hostsym = Symbol("hostref"); +function hostref(s) { + if (! (s in hostrefs)) hostrefs[s] = {[hostsym]: s}; + return hostrefs[s]; +} +function is_hostref(x) { + return (x !== null && hostsym in x) ? 1 : 0; +} +function is_funcref(x) { + return typeof x === "function" ? 1 : 0; +} +function eq_ref(x, y) { + return x === y ? 1 : 0; +} + let $$; // Default imports. @@ -77,6 +93,10 @@ function reinitializeRegistry() { return; let spectest = { + hostref: hostref, + is_hostref: is_hostref, + is_funcref: is_funcref, + eq_ref: eq_ref, print: console.log.bind(console), print_i32: console.log.bind(console), print_i32_f32: console.log.bind(console), @@ -228,13 +248,13 @@ function get(instance, name) { return ValueResult((v instanceof WebAssembly.Global) ? v.value : v); } -function exports(name, instance) { +function exports(instance) { _assert(instance instanceof Result); if (instance.isError()) return instance; - return ValueResult({ [name]: instance.value.exports }); + return ValueResult({ module: instance.value.exports, spectest: registry.spectest }); } function run(action) { @@ -320,11 +340,26 @@ function assert_return(action, expected) { uniqueTest(() => { assert_true(!result.isError(), `expected success result, got: ${result.value}.`); - if (!result.isError()) { - assert_equals(result.value, expected); - }; + let actual = result.value; + switch (expected) { + case "nan:canonical": + case "nan:arithmetic": + // Note that JS can't reliably distinguish different NaN values, + // so there's no good way to test that it's a canonical NaN. + assert_true(Number.isNaN(actual), `expected NaN, observed ${actual}.`); + return; + case "ref.func": + assert_true(typeof actual === "function", `expected Wasm function, got ${actual}`); + return; + case "ref.any": + assert_true(actual !== null, `expected Wasm reference, got ${actual}`); + return; + default: + assert_equals(actual, expected); + } + }, "A wast module that must return a particular value."); -}; +} function assert_return_nan(action) { let result = action(); From 551e8761352eb0b3f36879342d360cc0f1b69950 Mon Sep 17 00:00:00 2001 From: Andreas Rossberg Date: Thu, 7 May 2020 09:38:24 +0200 Subject: [PATCH 158/199] Remove subtyping (#87) Per the vote on #69, this PR removes subtyping from the proposal. List of changes: * Syntax: - remove `nullref` type - rename `anyref` type to `externref` - extend `ref.null` and `ref.is_null` instructions with new immediate of the form `func` or `extern` (this will later have to generalise to a `constype` per the [typed references proposal](https://github.com/WebAssembly/function-references)) * Typing rules: - `ref.null`, `ref.is_null`: determine reference type based on new immediate - `select`, `call_indirect`, `table.copy`, `table.init`: drop subtyping - `br_table`: revert to rule requiring same label types - `elem` segment: drop subtyping - `global` import: drop subtyping (link time) * Remove subtyping rules and bottom type. * Revert typing algorithm (interpreter and spec appendix). * JS API: - remove `"nullref"` - rename `"anyref"` to `"externref"` * Scripts: - rename `ref` result to `ref.extern` - rename `ref.host` value to `ref.extern` - drop subtyping from invocation type check * JS translation: - extend harness with separate eq functions for each ref type * Adjust tests: - apply syntax changes - remove tests for subtyping - change tests exercising subtyping in other ways --- document/core/appendix/algorithm.rst | 47 ++++--- document/core/appendix/index-instructions.rst | 4 +- document/core/appendix/index-rules.rst | 4 - document/core/appendix/index-types.rst | 5 +- document/core/appendix/properties.rst | 34 ++--- document/core/binary/instructions.rst | 4 +- document/core/binary/types.rst | 3 +- document/core/exec/instructions.rst | 22 ++-- document/core/exec/modules.rst | 26 ++-- document/core/exec/runtime.rst | 22 ++-- document/core/syntax/instructions.rst | 4 +- document/core/syntax/types.rst | 18 +-- document/core/text/instructions.rst | 4 +- document/core/text/types.rst | 7 +- document/core/util/macros.def | 15 +-- document/core/valid/instructions.rst | 64 ++++------ document/core/valid/modules.rst | 10 +- document/core/valid/types.rst | 117 +---------------- document/js-api/index.bs | 20 +-- interpreter/README.md | 13 +- interpreter/binary/decode.ml | 7 +- interpreter/binary/encode.ml | 8 +- interpreter/exec/eval.ml | 19 +-- interpreter/host/spectest.ml | 6 +- interpreter/runtime/global.ml | 4 +- interpreter/runtime/table.ml | 2 +- interpreter/script/js.ml | 89 +++++++------ interpreter/script/run.ml | 20 ++- interpreter/script/script.ml | 9 +- interpreter/syntax/ast.ml | 4 +- interpreter/syntax/free.ml | 2 +- interpreter/syntax/operators.ml | 4 +- interpreter/syntax/types.ml | 69 ++++------ interpreter/syntax/values.ml | 9 +- interpreter/text/arrange.ml | 12 +- interpreter/text/lexer.mll | 7 +- interpreter/text/parser.mly | 23 ++-- interpreter/valid/valid.ml | 62 ++++----- proposals/reference-types/Overview.md | 37 +++--- test/core/binary.wast | 4 +- test/core/br_table.wast | 93 ++------------ test/core/bulk.wast | 2 +- test/core/elem.wast | 22 ++-- test/core/global.wast | 10 +- test/core/linking.wast | 75 +++-------- test/core/ref_func.wast | 8 +- test/core/ref_is_null.wast | 53 +++----- test/core/ref_null.wast | 15 +-- test/core/select.wast | 51 ++------ test/core/table-sub.wast | 14 +-- test/core/table_fill.wast | 118 +++++++++--------- test/core/table_get.wast | 40 +++--- test/core/table_grow.wast | 88 ++++++------- test/core/table_set.wast | 62 ++++----- test/core/table_size.wast | 20 +-- 55 files changed, 580 insertions(+), 931 deletions(-) diff --git a/document/core/appendix/algorithm.rst b/document/core/appendix/algorithm.rst index 19ec29a0d3..7fd3da33fc 100644 --- a/document/core/appendix/algorithm.rst +++ b/document/core/appendix/algorithm.rst @@ -22,21 +22,16 @@ Data Structures ~~~~~~~~~~~~~~~ Types are representable as an enumeration. -A simple subtyping check can be defined on these types. .. code-block:: pseudo - type val_type = I32 | I64 | F32 | F64 | Anyref | Funcref | Nullref | Bot + type val_type = I32 | I64 | F32 | F64 | Funcref | Externref func is_num(t : val_type) : bool = - return t = I32 || t = I64 || t = F32 || t = F64 || t = Bot + return t = I32 || t = I64 || t = F32 || t = F64 func is_ref(t : val_type) : bool = - return t = Anyref || t = Funcref || t = Nullref || t = Bot - - func matches(t1 : val_type, t2 : val_type) : bool = - return t1 = t2 || t1 = Bot || - (t1 = Nullref && is_ref(t2)) || (is_ref(t1) && t2 = Anyref) + return t = Funcref || t = Externref The algorithm uses two separate stacks: the *value stack* and the *control stack*. The former tracks the :ref:`types ` of operand values on the :ref:`stack `, @@ -44,7 +39,7 @@ the latter surrounding :ref:`structured control instructions `. +For each value, the value stack records its :ref:`value type `, or :code:`Unknown` when the type is not known. + For each entered block, the control stack records a *control frame* with the type of the associated :ref:`label ` (used to type-check branches), the result type of the block (used to check its result), the height of the operand stack at the start of the block (used to check that operands do not underflow the current block), and a flag recording whether the remainder of the block is unreachable (used to handle :ref:`stack-polymorphic ` typing after branches). @@ -73,17 +69,19 @@ However, these variables are not manipulated directly by the main checking funct .. code-block:: pseudo - func push_val(type : val_type) = + func push_val(type : val_type | Unknown) = vals.push(type) - func pop_val() : val_type = - if (vals.size() = ctrls[0].height && ctrls[0].unreachable) return Bot + func pop_val() : val_type | Unknown = + if (vals.size() = ctrls[0].height && ctrls[0].unreachable) return Unknown error_if(vals.size() = ctrls[0].height) return vals.pop() - func pop_val(expect : val_type) : val_type = + func pop_val(expect : val_type | Unknown) : val_type | Unknown = let actual = pop_val() - error_if(not matches(actual, expect)) + if (actual = Unknown) return expect + if (expect = Unknown) return actual + error_if(actual =/= expect) return actual func push_vals(types : list(val_type)) = foreach (t in types) push_val(t) @@ -97,10 +95,10 @@ Pushing an operand value simply pushes the respective type to the value stack. Popping an operand value checks that the value stack does not underflow the current block and then removes one type. But first, a special case is handled where the block contains no known values, but has been marked as unreachable. That can occur after an unconditional branch, when the stack is typed :ref:`polymorphically `. -In that case, the :code:`Bot` type is returned, because that is a *principal* choice trivially satisfying all use constraints. +In that case, an unknown type is returned. A second function for popping an operand value takes an expected type, which the actual operand type is checked against. -The types may differ by subtyping, including the case where the actual type is :code:`Bot`, and thereby matches unconditionally. +The types may differ in case one of them is Unknown. The function returns the actual type popped from the stack. Finally, there are accumulative functions for pushing or popping multiple operand types. @@ -143,7 +141,7 @@ In that case, all existing operand types are purged from the value stack, in ord .. note:: Even with the unreachable flag set, consecutive operands are still pushed to and popped from the operand stack. That is necessary to detect invalid :ref:`examples ` like :math:`(\UNREACHABLE~(\I32.\CONST)~\I64.\ADD)`. - However, a polymorphic stack cannot underflow, but instead generates :code:`Bot` types as needed. + However, a polymorphic stack cannot underflow, but instead generates :code:`Unknown` types as needed. .. index:: opcode @@ -175,8 +173,8 @@ Other instructions are checked in a similar manner. let t1 = pop_val() let t2 = pop_val() error_if(not (is_num(t1) && is_num(t2))) - error_if(t1 =/= t2 && t1 =/= Bot && t2 =/= Bot) - push_val(if (t1 = Bot) t2 else t1) + error_if(t1 =/= t2 && t1 =/= Unknown && t2 =/= Unknown) + push_val(if (t1 = Unknown) t2 else t1) case (select t) pop_val(I32) @@ -217,14 +215,11 @@ Other instructions are checked in a similar manner.       push_vals(ctrls[n].label_types)    case (br_table n* m) - pop_val(I32)       error_if(ctrls.size() < m) - let arity = ctrls[m].label_types.size()       foreach (n in n*) -         error_if(ctrls.size() < n) -         error_if(ctrls[n].label_types.size() =/= arity) - push_vals(pop_vals(ctrls[n].label_types)) - pop_vals(ctrls[m].label_types) +         error_if(ctrls.size() < n || ctrls[n].label_types =/= ctrls[m].label_types) + pop_val(I32) +       pop_vals(ctrls[m].label_types)       unreachable() .. note:: diff --git a/document/core/appendix/index-instructions.rst b/document/core/appendix/index-instructions.rst index f54363c7c2..dbb0200228 100644 --- a/document/core/appendix/index-instructions.rst +++ b/document/core/appendix/index-instructions.rst @@ -215,8 +215,8 @@ Instruction Binary Opcode Type (reserved) :math:`\hex{CD}` (reserved) :math:`\hex{CE}` (reserved) :math:`\hex{CF}` -:math:`\REFNULL` :math:`\hex{D0}` :math:`[] \to [\NULLREF]` :ref:`validation ` :ref:`execution ` -:math:`\REFISNULL` :math:`\hex{D1}` :math:`[\ANYREF] \to [\I32]` :ref:`validation ` :ref:`execution ` +:math:`\REFNULL~t` :math:`\hex{D0}` :math:`[] \to [t]` :ref:`validation ` :ref:`execution ` +:math:`\REFISNULL~t` :math:`\hex{D1}` :math:`[t] \to [\I32]` :ref:`validation ` :ref:`execution ` :math:`\REFFUNC~x` :math:`\hex{D2}` :math:`[] \to [\FUNCREF]` :ref:`validation ` :ref:`execution ` :math:`\MEMORYINIT` :math:`\hex{FC08}` :math:`[\I32~\I32~\I32] \to []` :ref:`validation ` :ref:`execution ` :math:`\DATADROP` :math:`\hex{FC09}` :math:`[] \to []` :ref:`validation ` :ref:`execution ` diff --git a/document/core/appendix/index-rules.rst b/document/core/appendix/index-rules.rst index 525fe1397a..1beabe35a2 100644 --- a/document/core/appendix/index-rules.rst +++ b/document/core/appendix/index-rules.rst @@ -82,10 +82,6 @@ Matching =============================================== =============================================================================== Construct Judgement =============================================== =============================================================================== -:ref:`Number type ` :math:`\vdashnumtypematch \numtype_1 \matchesvaltype \numtype_2` -:ref:`Reference type ` :math:`\vdashreftypematch \reftype_1 \matchesvaltype \reftype_2` -:ref:`Value type ` :math:`\vdashvaltypematch \valtype_1 \matchesvaltype \valtype_2` -:ref:`Result type ` :math:`\vdashresulttypematch [t_1^?] \matchesresulttype [t_2^?]` :ref:`External type ` :math:`\vdashexterntypematch \externtype_1 \matchesexterntype \externtype_2` :ref:`Limits ` :math:`\vdashlimitsmatch \limits_1 \matcheslimits \limits_2` =============================================== =============================================================================== diff --git a/document/core/appendix/index-types.rst b/document/core/appendix/index-types.rst index 37f33c7b23..413e6f0b0e 100644 --- a/document/core/appendix/index-types.rst +++ b/document/core/appendix/index-types.rst @@ -14,9 +14,8 @@ Category Constructor :ref:`Number type ` |F64| :math:`\hex{7C}` (-4 as |Bs7|) (reserved) :math:`\hex{7B}` .. :math:`\hex{71}` :ref:`Reference type ` |FUNCREF| :math:`\hex{70}` (-16 as |Bs7|) -:ref:`Reference type ` |ANYREF| :math:`\hex{6F}` (-17 as |Bs7|) -:ref:`Reference type ` |NULLREF| :math:`\hex{6E}` (-18 as |Bs7|) -(reserved) :math:`\hex{6D}` .. :math:`\hex{61}` +:ref:`Reference type ` |EXTERNREF| :math:`\hex{6F}` (-17 as |Bs7|) +(reserved) :math:`\hex{6E}` .. :math:`\hex{61}` :ref:`Function type ` :math:`[\valtype^\ast] \to [\valtype^\ast]` :math:`\hex{60}` (-32 as |Bs7|) (reserved) :math:`\hex{5F}` .. :math:`\hex{41}` :ref:`Result type ` :math:`[\epsilon]` :math:`\hex{40}` (-64 as |Bs7|) diff --git a/document/core/appendix/properties.rst b/document/core/appendix/properties.rst index 76e47b7439..f62e02b38d 100644 --- a/document/core/appendix/properties.rst +++ b/document/core/appendix/properties.rst @@ -215,9 +215,7 @@ Module instances are classified by *module contexts*, which are regular :ref:`co * For each :ref:`reference ` :math:`\reff_i` in the table's elements :math:`\reff^n`: - * The :ref:`reference ` :math:`\reff_i` must be :ref:`valid ` with some :ref:`reference type ` :math:`t'_i`. - - * The :ref:`reference type ` :math:`t'_i` must :ref:`match ` the :ref:`reference type ` :math:`t`. + * The :ref:`reference ` :math:`\reff_i` must be :ref:`valid ` with :ref:`reference type ` :math:`t`. * Then the table instance is valid with :ref:`table type ` :math:`\limits~t`. @@ -227,9 +225,7 @@ Module instances are classified by *module contexts*, which are regular :ref:`co \qquad n = \limits.\LMIN \qquad - (S \vdash \reff : t')^n - \qquad - (\vdashreftypematch t' \matchesvaltype t)^n + (S \vdash \reff : t)^n }{ S \vdashtableinst \{ \TITYPE~(\limits~t), \TIELEM~\reff^n \} : \limits~t } @@ -265,9 +261,7 @@ Module instances are classified by *module contexts*, which are regular :ref:`co * The :ref:`global type ` :math:`\mut~t` must be :ref:`valid `. -* The :ref:`value ` :math:`\val` must be :ref:`valid ` with some :ref:`value type ` :math:`t'`. - -* The :ref:`value type ` :math:`t'` must :ref:`match ` the :ref:`value type ` :math:`t`. +* The :ref:`value ` :math:`\val` must be :ref:`valid ` with :ref:`value type ` :math:`t`. * Then the global instance is valid with :ref:`global type ` :math:`\mut~t`. @@ -275,9 +269,7 @@ Module instances are classified by *module contexts*, which are regular :ref:`co \frac{ \vdashglobaltype \mut~t \ok \qquad - S \vdashval \val : t' - \qquad - \vdashvaltypematch t' \matchesvaltype t + S \vdashval \val : t }{ S \vdashglobalinst \{ \GITYPE~(\mut~t), \GIVALUE~\val \} : \mut~t } @@ -291,17 +283,13 @@ Module instances are classified by *module contexts*, which are regular :ref:`co * For each :ref:`reference ` :math:`\reff_i` in the elements :math:`\reff^n`: - * The :ref:`reference ` :math:`\reff_i` must be :ref:`valid ` with some :ref:`reference type ` :math:`t'_i`. - - * The :ref:`reference type ` :math:`t'_i` must :ref:`match ` the :ref:`reference type ` :math:`t`. + * The :ref:`reference ` :math:`\reff_i` must be :ref:`valid ` with :ref:`reference type ` :math:`t`. * Then the table instance is valid. .. math:: \frac{ - (S \vdash \reff : t')^\ast - \qquad - (\vdashreftypematch t' \matchesvaltype t)^\ast + (S \vdash \reff : t)^\ast }{ S \vdasheleminst \{ \EITYPE~t, \EIELEM~\reff^\ast \} \ok } @@ -535,17 +523,17 @@ To that end, all previous typing judgements :math:`C \vdash \X{prop}` are genera } -.. index:: host address +.. index:: extern address -:math:`\REFHOST~\hostaddr` -.......................... +:math:`\REFEXTERNADDR~\externaddr` +.................................. -* The instruction is valid with type :math:`[] \to [\ANYREF]`. +* The instruction is valid with type :math:`[] \to [\EXTERNREF]`. .. math:: \frac{ }{ - S; C \vdashadmininstr \REFHOST~\hostaddr : [] \to [\ANYREF] + S; C \vdashadmininstr \REFEXTERNADDR~\externaddr : [] \to [\EXTERNREF] } diff --git a/document/core/binary/instructions.rst b/document/core/binary/instructions.rst index cb34bba1fe..a6fba1328b 100644 --- a/document/core/binary/instructions.rst +++ b/document/core/binary/instructions.rst @@ -76,8 +76,8 @@ Reference Instructions .. math:: \begin{array}{llclll} \production{instruction} & \Binstr &::=& \dots \\ &&|& - \hex{D0} &\Rightarrow& \REFNULL \\ &&|& - \hex{D1} &\Rightarrow& \REFISNULL \\ &&|& + \hex{D0}~~t{:}\Breftype &\Rightarrow& \REFNULL~t \\ &&|& + \hex{D1}~~t{:}\Breftype &\Rightarrow& \REFISNULL~t \\ &&|& \hex{D2}~~x{:}\Bfuncidx &\Rightarrow& \REFFUNC~x \\ \end{array} diff --git a/document/core/binary/types.rst b/document/core/binary/types.rst index e7a7f8ed9f..5154e4d8e4 100644 --- a/document/core/binary/types.rst +++ b/document/core/binary/types.rst @@ -42,8 +42,7 @@ Reference Types \begin{array}{llclll@{\qquad\qquad}l} \production{reference type} & \Breftype &::=& \hex{70} &\Rightarrow& \FUNCREF \\ &&|& - \hex{6F} &\Rightarrow& \ANYREF \\ &&|& - \hex{6E} &\Rightarrow& \NULLREF \\ + \hex{6F} &\Rightarrow& \EXTERNREF \\ \end{array} diff --git a/document/core/exec/instructions.rst b/document/core/exec/instructions.rst index ef8dd5e69a..ba0ade50d1 100644 --- a/document/core/exec/instructions.rst +++ b/document/core/exec/instructions.rst @@ -192,10 +192,10 @@ Reference Instructions .. _exec-ref.null: -:math:`\REFNULL` -................ +:math:`\REFNULL~t` +.................. -1. Push the value :math:`\REFNULL` to the stack. +1. Push the value :math:`\REFNULL~t` to the stack. .. note:: No formal reduction rule is required for this instruction, since the |REFNULL| instruction is already a :ref:`value `. @@ -203,14 +203,14 @@ Reference Instructions .. _exec-ref.is_null: -:math:`\REFISNULL` -.................. +:math:`\REFISNULL~t` +.................... 1. Assert: due to :ref:`validation `, a :ref:`reference value ` is on the top of the stack. 2. Pop the value :math:`\val` from the stack. -3. If :math:`\val` is |REFNULL|, then: +3. If :math:`\val` is :math:`\REFNULL~t`, then: a. Push the value :math:`\I32.\CONST~1` to the stack. @@ -220,10 +220,10 @@ Reference Instructions .. math:: \begin{array}{lcl@{\qquad}l} - \val~\REFISNULL &\stepto& \I32.\CONST~1 - & (\iff \val = \REFNULL) \\ - \val~\REFISNULL &\stepto& \I32.\CONST~0 - & (\iff \val \neq \REFNULL) \\ + \val~\REFISNULL~t &\stepto& \I32.\CONST~1 + & (\iff \val = \REFNULL~t) \\ + \val~\REFISNULL~t &\stepto& \I32.\CONST~0 + & (\otherwise) \\ \end{array} @@ -1768,7 +1768,7 @@ Control Instructions 11. Let :math:`r` be the :ref:`reference ` :math:`\X{tab}.\TIELEM[i]`. -12. If :math:`r` is |REFNULL|, then: +12. If :math:`r` is :math:`\REFNULL~t`, then: a. Trap. diff --git a/document/core/exec/modules.rst b/document/core/exec/modules.rst index eb46eb6836..35df503de5 100644 --- a/document/core/exec/modules.rst +++ b/document/core/exec/modules.rst @@ -110,15 +110,15 @@ The following auxiliary typing rules specify this typing relation relative to a .. _valid-ref: -:ref:`Null References ` :math:`\REFNULL` -.................................................... +:ref:`Null References ` :math:`\REFNULL~t` +...................................................... -* The value is valid with :ref:`reference type ` :math:`\NULLREF`. +* The value is valid with :ref:`reference type ` :math:`t`. .. math:: \frac{ }{ - S \vdashval \REFNULL : \NULLREF + S \vdashval \REFNULL~t : t } @@ -137,15 +137,15 @@ The following auxiliary typing rules specify this typing relation relative to a } -:ref:`Host References ` :math:`\REFHOST~a` -........................................................... +:ref:`External References ` :math:`\REFEXTERNADDR~a` +....................................................................... -* The value is valid with :ref:`reference type ` :math:`\ANYREF`. +* The value is valid with :ref:`reference type ` :math:`\EXTERNREF`. .. math:: \frac{ }{ - S \vdashval \REFHOST~a : \ANYREF + S \vdashval \REFEXTERNADDR~a : \EXTERNREF } @@ -447,7 +447,10 @@ and list of :ref:`reference ` vectors for the module's :ref:`element 3. For each :ref:`table ` :math:`\table_i` in :math:`\module.\MTABLES`, do: - a. Let :math:`\tableaddr_i` be the :ref:`table address ` resulting from :ref:`allocating ` :math:`\table_i.\TTYPE`. + a. Let :math:`\limits_i~t_i` be the :ref:`table type ` :math:`\table_i.\TTYPE`. + + b. Let :math:`\tableaddr_i` be the :ref:`table address ` resulting from :ref:`allocating ` :math:`\table_i.\TTYPE` + with initialization value :math:`\REFNULL~t_i`. 4. For each :ref:`memory ` :math:`\mem_i` in :math:`\module.\MMEMS`, do: @@ -526,8 +529,9 @@ where: \MIEXPORTS~\exportinst^\ast ~\} \end{array} \\[1ex] S_1, \funcaddr^\ast &=& \allocfunc^\ast(S, \module.\MFUNCS, \moduleinst) \\ - S_2, \tableaddr^\ast &=& \alloctable^\ast(S_1, (\table.\TTYPE)^\ast, \REFNULL) - \qquad\qquad\qquad~ (\where \table^\ast = \module.\MTABLES) \\ + S_2, \tableaddr^\ast &=& \alloctable^\ast(S_1, (\table.\TTYPE)^\ast, \REFNULL~t) + \qquad\qquad\qquad~ (\where \table^\ast = \module.\MTABLES \\ && + \qquad\qquad\qquad~~ \wedge (\table.\TTYPE)^\ast = (\limits~t)^\ast) \\ S_3, \memaddr^\ast &=& \allocmem^\ast(S_2, (\mem.\MTYPE)^\ast) \qquad\qquad\qquad~ (\where \mem^\ast = \module.\MMEMS) \\ S_4, \globaladdr^\ast &=& \allocglobal^\ast(S_3, (\global.\GTYPE)^\ast, \val^\ast) diff --git a/document/core/exec/runtime.rst b/document/core/exec/runtime.rst index 757cf3f630..568739e436 100644 --- a/document/core/exec/runtime.rst +++ b/document/core/exec/runtime.rst @@ -11,7 +11,7 @@ Runtime Structure pair: abstract syntax; value .. _syntax-num: .. _syntax-ref: -.. _syntax-ref.host: +.. _syntax-ref.extern: .. _syntax-val: Values @@ -25,7 +25,7 @@ It is convenient to reuse the same notation as for the |CONST| :ref:`instruction References other than null are represented with additional :ref:`administrative instructions `. They either are *function references*, pointing to a specific :ref:`function address `, -or *host references* pointing to an uninterpreted form of :ref:`host address ` that can be defined by the :ref:`embedder `. +or *external references* pointing to an uninterpreted form of :ref:`extern address ` that can be defined by the :ref:`embedder ` to represent its own objects. .. math:: \begin{array}{llcl} @@ -35,9 +35,9 @@ or *host references* pointing to an uninterpreted form of :ref:`host address ` an .. math:: \begin{array}{lcl@{\qquad}l} \default_t &=& t{.}\CONST~0 & (\iff t = \numtype) \\ - \default_t &=& \REFNULL & (\iff t = \reftype) \\ + \default_t &=& \REFNULL~t & (\iff t = \reftype) \\ \end{array} @@ -145,7 +145,7 @@ Convention .. _syntax-globaladdr: .. _syntax-elemaddr: .. _syntax-dataaddr: -.. _syntax-hostaddr: +.. _syntax-externaddr: .. _syntax-addr: Addresses @@ -171,7 +171,7 @@ In addition, an :ref:`embedder ` may supply an uninterpreted set of *h \addr \\ \production{(data address)} & \dataaddr &::=& \addr \\ - \production{(host address)} & \hostaddr &::=& + \production{(extern address)} & \externaddr &::=& \addr \\ \end{array} @@ -274,7 +274,7 @@ It records its :ref:`type ` and holds a vector of :ref:`refere Table elements can be mutated through :ref:`table instructions `, the execution of an active :ref:`element segment `, or by external means provided by the :ref:`embedder `. -It is an invariant of the semantics that all table elements have a type :ref:`matching ` the element type of :math:`\tabletype`. +It is an invariant of the semantics that all table elements have a type equal to the element type of :math:`\tabletype`. It also is an invariant that the length of the element vector never exceeds the maximum size of :math:`\tabletype`, if present. @@ -322,7 +322,7 @@ It records its :ref:`type ` and holds an individual :ref:`val The value of mutable globals can be mutated through :ref:`variable instructions ` or by external means provided by the :ref:`embedder `. -It is an invariant of the semantics that the value has a type :ref:`matching ` the :ref:`value type ` of :math:`\globaltype`. +It is an invariant of the semantics that the value has a type equal to the :ref:`value type ` of :math:`\globaltype`. .. index:: ! element instance, element segment, embedder, element expression @@ -526,7 +526,7 @@ In order to express the reduction of :ref:`traps `, :ref:`calls `, :ref:`calls `. Similarly, |REFHOST| represents :ref:`host references `. +The |REFFUNCADDR| instruction represents :ref:`function reference values `. Similarly, |REFEXTERNADDR| represents :ref:`external references `. The |INVOKE| instruction represents the imminent invocation of a :ref:`function instance `, identified by its :ref:`address `. It unifies the handling of different forms of calls. diff --git a/document/core/syntax/instructions.rst b/document/core/syntax/instructions.rst index 87a11b17cd..fd29a890c3 100644 --- a/document/core/syntax/instructions.rst +++ b/document/core/syntax/instructions.rst @@ -183,8 +183,8 @@ Instructions in this group are concerned with accessing :ref:`references ` of all other reference types. - The type |FUNCREF| denotes the infinite union of all references to :ref:`functions `, regardless of their :ref:`function types `. -The type |NULLREF| only contains a single value: the :ref:`null ` reference. -It is a :ref:`subtype ` of all other reference types. - -.. note:: - Future versions of WebAssembly may include reference types that do not include null and hence are not supertypes of |NULLREF|. +The type |EXTERNREF| denotes the infinite union of all references to objects owned by the :ref:`embedder ` and that can be passed into WebAssembly under this type. Reference types are *opaque*, meaning that neither their size nor their bit pattern can be observed. Values of reference type can be stored in :ref:`tables `. @@ -80,16 +74,12 @@ Value Types ~~~~~~~~~~~ *Value types* classify the individual values that WebAssembly code can compute with and the values that a variable accepts. -They are either :ref:`number types `, :ref:`reference type `, or the unique *bottom type*, written :math:`\BOT`. - -The type :math:`\BOT` is a :ref:`subtype ` of all other types. -By virtue of being representable in neither the :ref:`binary format ` nor the :ref:`text format `, it cannot be used in a program; -it only occurs during :ref:`validation `. +They are either :ref:`number types ` or :ref:`reference types `. .. math:: \begin{array}{llll} \production{value type} & \valtype &::=& - \numtype ~|~ \reftype ~|~ \BOT \\ + \numtype ~|~ \reftype \\ \end{array} Conventions diff --git a/document/core/text/instructions.rst b/document/core/text/instructions.rst index dad0d02e1c..d27370fe86 100644 --- a/document/core/text/instructions.rst +++ b/document/core/text/instructions.rst @@ -143,8 +143,8 @@ Reference Instructions .. math:: \begin{array}{llclll} \production{instruction} & \Tplaininstr_I &::=& \dots \\ &&|& - \text{ref.null} &\Rightarrow& \REFNULL \\ &&|& - \text{ref.is\_null} &\Rightarrow& \REFISNULL \\ &&|& + \text{ref.null}~~t{:}\Trefedtype &\Rightarrow& \REFNULL~t \\ &&|& + \text{ref.is\_null}~~t{:}\Trefedtype &\Rightarrow& \REFISNULL~t \\ &&|& \text{ref.func}~~x{:}\Tfuncidx &\Rightarrow& \REFFUNC~x \\ &&|& \end{array} diff --git a/document/core/text/types.rst b/document/core/text/types.rst index 569e7f215a..5711fb5452 100644 --- a/document/core/text/types.rst +++ b/document/core/text/types.rst @@ -25,6 +25,7 @@ Number Types .. index:: reference type pair: text format; reference type .. _text-reftype: +.. _text-refedtype: Reference Types ~~~~~~~~~~~~~~~ @@ -32,9 +33,11 @@ Reference Types .. math:: \begin{array}{llcll@{\qquad\qquad}l} \production{reference type} & \Treftype &::=& - \text{anyref} &\Rightarrow& \ANYREF \\ &&|& \text{funcref} &\Rightarrow& \FUNCREF \\ &&|& - \text{nullref} &\Rightarrow& \NULLREF \\ + \text{externref} &\Rightarrow& \EXTERNREF \\ + \production{referenced type} & \Trefedtype &::=& + \text{func} &\Rightarrow& \FUNCREF \\ &&|& + \text{extern} &\Rightarrow& \EXTERNREF \\ \end{array} diff --git a/document/core/util/macros.def b/document/core/util/macros.def index 4151d7a509..a74a9f56c9 100644 --- a/document/core/util/macros.def +++ b/document/core/util/macros.def @@ -179,9 +179,8 @@ .. |F32| mathdef:: \xref{syntax/types}{syntax-valtype}{\K{f32}} .. |F64| mathdef:: \xref{syntax/types}{syntax-valtype}{\K{f64}} -.. |ANYREF| mathdef:: \xref{syntax/types}{syntax-reftype}{\K{anyref}} .. |FUNCREF| mathdef:: \xref{syntax/types}{syntax-reftype}{\K{funcref}} -.. |NULLREF| mathdef:: \xref{syntax/types}{syntax-reftype}{\K{nullref}} +.. |EXTERNREF| mathdef:: \xref{syntax/types}{syntax-reftype}{\K{externref}} .. |MVAR| mathdef:: \xref{syntax/types}{syntax-mut}{\K{var}} .. |MCONST| mathdef:: \xref{syntax/types}{syntax-mut}{\K{const}} @@ -659,6 +658,7 @@ .. |Tnumtype| mathdef:: \xref{text/types}{text-numtype}{\T{numtype}} .. |Treftype| mathdef:: \xref{text/types}{text-reftype}{\T{reftype}} +.. |Trefedtype| mathdef:: \xref{text/types}{text-refedtype}{\T{refedtype}} .. |Tvaltype| mathdef:: \xref{text/types}{text-valtype}{\T{valtype}} .. |Tresulttype| mathdef:: \xref{text/types}{text-resulttype}{\T{resulttype}} .. |Tblocktype| mathdef:: \xref{text/types}{text-blocktype}{\T{blocktype}} @@ -767,8 +767,6 @@ .. |ok| mathdef:: \mathrel{\mbox{ok}} .. |const| mathdef:: \xref{valid/instructions}{valid-constant}{\mathrel{\mbox{const}}} -.. |matchesvaltype| mathdef:: \xref{valid/types}{match-valtype}{\leq} -.. |matchesresulttype| mathdef:: \xref{valid/types}{match-resulttype}{\leq} .. Contexts @@ -795,11 +793,6 @@ .. |vdashglobaltype| mathdef:: \xref{valid/types}{valid-globaltype}{\vdash} .. |vdashexterntype| mathdef:: \xref{valid/types}{valid-externtype}{\vdash} -.. |vdashnumtypematch| mathdef:: \xref{valid/types}{match-numtype}{\vdash} -.. |vdashreftypematch| mathdef:: \xref{valid/types}{match-reftype}{\vdash} -.. |vdashvaltypematch| mathdef:: \xref{valid/types}{match-valtype}{\vdash} -.. |vdashresulttypematch| mathdef:: \xref{valid/types}{match-resulttype}{\vdash} - .. |vdashinstr| mathdef:: \xref{valid/instructions}{valid-instr}{\vdash} .. |vdashinstrseq| mathdef:: \xref{valid/instructions}{valid-instr-seq}{\vdash} .. |vdashexpr| mathdef:: \xref{valid/instructions}{valid-expr}{\vdash} @@ -857,7 +850,7 @@ .. |globaladdr| mathdef:: \xref{exec/runtime}{syntax-globaladdr}{\X{globaladdr}} .. |elemaddr| mathdef:: \xref{exec/runtime}{syntax-elemaddr}{\X{elemaddr}} .. |dataaddr| mathdef:: \xref{exec/runtime}{syntax-dataaddr}{\X{dataaddr}} -.. |hostaddr| mathdef:: \xref{exec/runtime}{syntax-hostaddr}{\X{hostaddr}} +.. |externaddr| mathdef:: \xref{exec/runtime}{syntax-externaddr}{\X{externaddr}} .. Instances, terminals @@ -954,7 +947,7 @@ .. Administrative Instructions, terminals .. |REFFUNCADDR| mathdef:: \xref{exec/runtime}{syntax-ref}{\K{ref}} -.. |REFHOST| mathdef:: \xref{exec/runtime}{syntax-ref.host}{\K{ref{.}host}} +.. |REFEXTERNADDR| mathdef:: \xref{exec/runtime}{syntax-ref.extern}{\K{ref{.}extern}} .. |TRAP| mathdef:: \xref{exec/runtime}{syntax-trap}{\K{trap}} .. |INVOKE| mathdef:: \xref{exec/runtime}{syntax-invoke}{\K{invoke}} diff --git a/document/core/valid/instructions.rst b/document/core/valid/instructions.rst index c125c8bcec..1982139541 100644 --- a/document/core/valid/instructions.rst +++ b/document/core/valid/instructions.rst @@ -166,29 +166,31 @@ Reference Instructions .. _valid-ref.null: -:math:`\REFNULL` -................ +:math:`\REFNULL~t` +.................. -* The instruction is valid with type :math:`[] \to [\NULLREF]`. +* The instruction is valid with type :math:`[] \to [t]`. .. math:: \frac{ }{ - C \vdashinstr \REFNULL : [] \to [\NULLREF] + C \vdashinstr \REFNULL~t : [] \to [t] } +.. note:: + In future versions of WebAssembly, there may be reference types for which no null reference is allowed. .. _valid-ref.is_null: -:math:`\REFISNULL` -.................. +:math:`\REFISNULL~t` +.................... -* The instruction is valid with type :math:`[\ANYREF] \to [\I32]`. +* The instruction is valid with type :math:`[t] \to [\I32]`. .. math:: \frac{ }{ - C \vdashinstr \REFISNULL : [\ANYREF] \to [\I32] + C \vdashinstr \REFISNULL~t : [t] \to [\I32] } .. _valid-ref.func: @@ -251,7 +253,7 @@ Parametric Instructions * Else: - * The instruction is valid with type :math:`[t~t~\I32] \to [t]`, for any :ref:`value type ` :math:`t` that :ref:`matches ` some :ref:`number type `. + * The instruction is valid with type :math:`[t~t~\I32] \to [t]`, for any :ref:`number type ` :math:`t`. .. math:: \frac{ @@ -260,7 +262,7 @@ Parametric Instructions } \qquad \frac{ - \vdashvaltypematch t \matchesvaltype \numtype + t = \numtype }{ C \vdashinstr \SELECT : [t~t~\I32] \to [t] } @@ -488,17 +490,15 @@ Table Instructions * Let :math:`\limits_2~t_2` be the :ref:`table type ` :math:`C.\CTABLES[y]`. -* The :ref:`reference type ` :math:`t_2` must :ref:`match ` :math:`t_1`. +* The :ref:`reference type ` :math:`t_1` must be the same as :math:`t_2`. * Then the instruction is valid with type :math:`[\I32~\I32~\I32] \to []`. .. math:: \frac{ - C.\CTABLES[x] = \limits_1~t_1 + C.\CTABLES[x] = \limits_1~t \qquad - C.\CTABLES[x] = \limits_2~t_2 - \qquad - \vdashreftypematch t_2 \matchesvaltype t_1 + C.\CTABLES[x] = \limits_2~t }{ C \vdashinstr \TABLECOPY~x~y : [\I32~\I32~\I32] \to [] } @@ -517,17 +517,15 @@ Table Instructions * Let :math:`t_2` be the :ref:`reference type ` :math:`C.\CELEMS[y]`. -* The :ref:`reference type ` :math:`t_2` must :ref:`match ` :math:`t_1`. +* The :ref:`reference type ` :math:`t_1` must be the same as :math:`t_2`. * Then the instruction is valid with type :math:`[\I32~\I32~\I32] \to []`. .. math:: \frac{ - C.\CTABLES[x] = \limits_1~t_1 - \qquad - C.\CELEMS[y] = t_2 + C.\CTABLES[x] = \limits_1~t \qquad - \vdashreftypematch t_2 \matchesvaltype t_1 + C.\CELEMS[y] = t }{ C \vdashinstr \TABLEINIT~x~y : [\I32~\I32~\I32] \to [] } @@ -926,20 +924,16 @@ Control Instructions * For all :math:`l_i` in :math:`l^\ast`, the label :math:`C.\CLABELS[l_i]` must be defined in the context. -* There must be a :ref:`result type ` :math:`[t^?]`, such that: - - * The result type :math:`[t^?]` :ref:`matches ` :math:`C.\CLABELS[l_N]`. - - * For all :math:`l_i` in :math:`l^\ast`, - the result type :math:`[t^?]` :ref:`matches ` :math:`C.\CLABELS[l_i]`. +* For all :math:`l_i` in :math:`l^\ast`, + :math:`C.\CLABELS[l_i]` must be :math:`[t^?]`. * Then the instruction is valid with type :math:`[t_1^\ast~t^?~\I32] \to [t_2^\ast]`, for any sequences of :ref:`value types ` :math:`t_1^\ast` and :math:`t_2^\ast`. .. math:: \frac{ - (\vdashresulttypematch [t^?] \matchesresulttype C.\CLABELS[l])^\ast + (C.\CLABELS[l] = [t^?])^\ast \qquad - \vdashresulttypematch [t^?] \matchesresulttype C.\CLABELS[l_N] + C.\CLABELS[l_N] = [t^?] }{ C \vdashinstr \BRTABLE~l^\ast~l_N : [t_1^\ast~t^?~\I32] \to [t_2^\ast] } @@ -1002,7 +996,7 @@ Control Instructions * Let :math:`\limits~t` be the :ref:`table type ` :math:`C.\CTABLES[x]`. -* The :ref:`reference type ` :math:`t` must :ref:`match ` type |FUNCREF|. +* The :ref:`reference type ` :math:`t` must be |FUNCREF|. * The type :math:`C.\CTYPES[y]` must be defined in the context. @@ -1012,9 +1006,7 @@ Control Instructions .. math:: \frac{ - C.\CTABLES[x] = \limits~t - \qquad - \vdashvaltypematch t \leq \FUNCREF + C.\CTABLES[x] = \limits~\FUNCREF \qquad C.\CTYPES[y] = [t_1^\ast] \to [t_2^\ast] }{ @@ -1054,17 +1046,13 @@ Non-empty Instruction Sequence: :math:`\instr^\ast~\instr_N` for some sequences of :ref:`value types ` :math:`t^\ast` and :math:`t_3^\ast`. * There must be a sequence of :ref:`value types ` :math:`t_0^\ast`, - such that :math:`t_2^\ast = t_0^\ast~{t'}^\ast` where the type sequence :math:`{t'}^\ast` is as long as :math:`t^\ast`. - -* For each :ref:`value type ` :math:`t'_i` in :math:`{t'}^\ast` and corresponding type :math:`t_i` in :math:`t^\ast`, the type :math:`t'_i` must :ref:`match ` :math:`t_i`. + such that :math:`t_2^\ast = t_0^\ast~t^\ast`. * Then the combined instruction sequence is valid with type :math:`[t_1^\ast] \to [t_0^\ast~t_3^\ast]`. .. math:: \frac{ - C \vdashinstrseq \instr^\ast : [t_1^\ast] \to [t_0^\ast~{t'}^\ast] - \qquad - (\vdashvaltypematch t' \matchesvaltype t)^\ast + C \vdashinstrseq \instr^\ast : [t_1^\ast] \to [t_0^\ast~t^\ast] \qquad C \vdashinstr \instr_N : [t^\ast] \to [t_3^\ast] }{ diff --git a/document/core/valid/modules.rst b/document/core/valid/modules.rst index 374cfddbcb..40b25a7646 100644 --- a/document/core/valid/modules.rst +++ b/document/core/valid/modules.rst @@ -156,9 +156,7 @@ Element segments :math:`\elem` are classified by the :ref:`reference type `. -* The element mode :math:`\elemmode` must be valid with :ref:`reference type ` :math:`t'`. - -* The :ref:`reference type ` :math:`t` must :ref:`match ` the reference type :math:`t'`. +* The element mode :math:`\elemmode` must be valid with :ref:`reference type ` :math:`t`. * Then the element segment is valid with :ref:`reference type ` :math:`t`. @@ -169,9 +167,7 @@ Element segments :math:`\elem` are classified by the :ref:`reference type ` are universally valid. However, restrictions apply to :ref:`function types ` as well as the :ref:`limits ` of :ref:`table types ` and :ref:`memory types `, which must be checked during validation. -On :ref:`value types `, a simple notion of subtyping is defined. - .. index:: limits pair: validation; limits @@ -200,107 +198,6 @@ External Types } -.. index:: subtyping - -Value Subtyping -~~~~~~~~~~~~~~~ - -.. index:: number type - -.. _match-numtype: - -Number Types -............ - -A :ref:`number type ` :math:`\numtype_1` matches a :ref:`number type ` :math:`\numtype_2` if and only if: - -* Both :math:`\numtype_1` and :math:`\numtype_2` are the same. - -.. math:: - ~\\[-1ex] - \frac{ - }{ - \vdashnumtypematch \numtype \matchesvaltype \numtype - } - - -.. index:: reference type - -.. _match-reftype: - -Reference Types -............... - -A :ref:`reference type ` :math:`\reftype_1` matches a :ref:`reference type ` :math:`\reftype_2` if and only if: - -* Either both :math:`\reftype_1` and :math:`\reftype_2` are the same. - -* Or :math:`\reftype_1` is |NULLREF|. - -* Or :math:`\reftype_2` is |ANYREF|. - -.. math:: - ~\\[-1ex] - \frac{ - }{ - \vdashreftypematch \reftype \matchesvaltype \reftype - } - \qquad - \frac{ - }{ - \vdashreftypematch \NULLREF \matchesvaltype \reftype - } - \qquad - \frac{ - }{ - \vdashreftypematch \reftype \matchesvaltype \ANYREF - } - - -.. index:: value type, number type, reference type - -.. _match-valtype: - -Value Types -........... - -A :ref:`value type ` :math:`\valtype_1` matches a :ref:`value type ` :math:`\valtype_2` if and only if: - -* Either both :math:`\valtype_1` and :math:`\valtype_2` are :ref:`number types ` and :math:`\valtype_1` :ref:`matches ` :math:`\valtype_2`. - -* Or both :math:`\valtype_1` and :math:`\valtype_2` are :ref:`reference types ` and :math:`\valtype_1` :ref:`matches ` :math:`\valtype_2`. - -* Or :math:`\valtype_1` is :math:`\BOT`. - -.. math:: - ~\\[-1ex] - \frac{ - }{ - \vdashvaltypematch \BOT \matchesvaltype \valtype - } - - -.. _match-resulttype: - -Result Types -............ - -Subtyping is lifted to :ref:`result types ` in a pointwise manner. -That is, a :ref:`result type ` :math:`[t_1^?]` matches a :ref:`result type ` :math:`[t_2^?]` if and only if: - -* Either both :math:`t_1^?` and :math:`t_2^?` are empty. - -* Or :ref:`value type ` :math:`t_1` :ref:`matches ` :ref:`value type ` :math:`t_2`. - -.. math:: - ~\\[-1ex] - \frac{ - (\vdashvaltypematch t_1 \matchesvaltype t_2)^? - }{ - \vdashresulttypematch [t_1^?] \matchesresulttype [t_2^?] - } - - .. index:: ! matching, external type .. _exec-import: .. _match: @@ -414,21 +311,13 @@ An :ref:`external type ` :math:`\ETMEM~\limits_1` matches :ma Globals ....... -An :ref:`external type ` :math:`\ETGLOBAL~(\mut_1~t_1)` matches :math:`\ETGLOBAL~(\mut_2~t_2)` if and only if: +An :ref:`external type ` :math:`\ETGLOBAL~\globaltype_1` matches :math:`\ETGLOBAL~\globaltype_2` if and only if: -* Either both :math:`\mut_1` and :math:`\mut_2` are |MVAR| and :math:`t_1` and :math:`t_2` are the same. - -* Or both :math:`\mut_1` and :math:`\mut_2` are |MCONST| and :math:`t_1` :ref:`matches ` :math:`t_2`. +* Both :math:`\globaltype_1` and :math:`\globaltype_2` are the same. .. math:: ~\\[-1ex] \frac{ }{ - \vdashexterntypematch \ETGLOBAL~(\MVAR~t) \matchesexterntype \ETGLOBAL~(\MVAR~t) - } - \qquad - \frac{ - \vdashvaltypematch t_1 \matchesvaltype t_2 - }{ - \vdashexterntypematch \ETGLOBAL~(\MCONST~t_1) \matchesexterntype \ETGLOBAL~(\MCONST~t_2) + \vdashexterntypematch \ETGLOBAL~\globaltype \matchesexterntype \ETGLOBAL~\globaltype } diff --git a/document/js-api/index.bs b/document/js-api/index.bs index 14bd1b5963..4ab7e0e59c 100644 --- a/document/js-api/index.bs +++ b/document/js-api/index.bs @@ -150,9 +150,8 @@ urlPrefix: https://webassembly.github.io/spec/core/; spec: WebAssembly; type: df text: 𝖿𝟥𝟤 text: 𝖿𝟨𝟦 url: syntax/types.html#syntax-reftype - text: anyref + text: externref text: funcref - text: nullref text: function element; url: exec/runtime.html#syntax-funcelem text: import component; url: syntax/modules.html#imports text: external value; url: exec/runtime.html#syntax-externval @@ -707,8 +706,7 @@ Immediately after a WebAssembly [=memory.grow=] instruction executes, perform th
     enum TableKind {
    -  "nullref",
    -  "anyref",
    +  "externref",
       "anyfunc",
       // Note: More values may be added in future iterations,
       // e.g., typed function references, typed GC references
    @@ -836,8 +834,7 @@ enum ValueType {
       "i64",
       "f32",
       "f64",
    -  "nullref",
    -  "anyref",
    +  "externref",
       "anyfunc",
     };
     
    @@ -890,9 +887,8 @@ which can be simultaneously referenced by multiple {{Instance}} objects. Each 1. If |s| equals "i64", return [=𝗂𝟨𝟦=]. 1. If |s| equals "f32", return [=𝖿𝟥𝟤=]. 1. If |s| equals "f64", return [=𝖿𝟨𝟦=]. - 1. If |s| equals "anyref", return [=anyref=]. 1. If |s| equals "funcref", return [=funcref=]. - 1. If |s| equals "nullref", return [=nullref=]. + 1. If |s| equals "externref", return [=externref=]. 1. Assert: This step is not reached. @@ -902,9 +898,7 @@ which can be simultaneously referenced by multiple {{Instance}} objects. Each 1. If |valuetype| equals [=𝗂𝟨𝟦=], return [=𝗂𝟨𝟦.𝖼𝗈𝗇𝗌𝗍=] 0. 1. If |valuetype| equals [=𝖿𝟥𝟤=], return [=𝖿𝟥𝟤.𝖼𝗈𝗇𝗌𝗍=] 0. 1. If |valuetype| equals [=𝖿𝟨𝟦=], return [=𝖿𝟨𝟦.𝖼𝗈𝗇𝗌𝗍=] 0. - 1. If |valuetype| equals [=nullref=], return [=ref.null=]. - 1. If |valuetype| equals [=anyref=], return [=ToWebAssemblyValue=](undefined, |valuetype|). - 1. If |valuetype| equals [=nullref=], return [=ref.null=]. + 1. If |valuetype| equals [=externref=], return [=ToWebAssemblyValue=](undefined, |valuetype|). 1. Assert: This step is not reached. @@ -1093,12 +1087,10 @@ The algorithm ToWebAssemblyValue(|v|, |type|) coerces a JavaScript va 1. Let |f64| be ? [=ToNumber=](|v|). 1. Return [=𝖿𝟨𝟦.𝖼𝗈𝗇𝗌𝗍=] |f64|. 1. Assert: |type| is a reference type. -1. If |type| is [=anyref=], +1. If |type| is [=externref=], 1. Do nothing. 1. If |type| is [=funcref=], 1. If |v| is not an [=Exported function=] or null, throw a {{TypeError}}. -1. If |type| is [=nullref=], - 1. If |v| is not null, throw a {{TypeError}}. 1. Return the result of [=allocating a host address=] for |v|. diff --git a/interpreter/README.md b/interpreter/README.md index 2c320f168e..8af4fd7795 100644 --- a/interpreter/README.md +++ b/interpreter/README.md @@ -178,13 +178,14 @@ var: | unop: ctz | clz | popcnt | ... binop: add | sub | mul | ... relop: eq | ne | lt | ... -sign: s|u +sign: s | u offset: offset= align: align=(1|2|4|8|...) cvtop: trunc | extend | wrap | ... num_type: i32 | i64 | f32 | f64 -ref_type: anyref | funcref | nullref +ref_kind: func | extern +ref_type: funcref | externref val_type: num_type | ref_type block_type : ( result * )* func_type: ( type )? * * @@ -240,8 +241,8 @@ op: memory.copy memory.init data.drop - ref.null - ref.isnull + ref.null + ref.is_null ref.func .const . @@ -349,7 +350,7 @@ action: const: ( .const ) ;; number value - ( ref.null ) ;; null reference + ( ref.null ) ;; null reference ( ref.host ) ;; host reference assertion: @@ -363,7 +364,7 @@ assertion: result: ( .const ) - ( ref.any ) + ( ref.extern ) ( ref.func ) numpat: diff --git a/interpreter/binary/decode.ml b/interpreter/binary/decode.ml index af687e8643..4c1b135f3c 100644 --- a/interpreter/binary/decode.ml +++ b/interpreter/binary/decode.ml @@ -144,8 +144,7 @@ let num_type s = let ref_type s = match vs7 s with | -0x10 -> FuncRefType - | -0x11 -> AnyRefType - | -0x12 -> NullRefType + | -0x11 -> ExternRefType | _ -> error s (pos s - 1) "malformed reference type" let value_type s = @@ -444,8 +443,8 @@ let rec instr s = | 0xc0 | 0xc1 | 0xc2 | 0xc3 | 0xc4 | 0xc5 | 0xc6 | 0xc7 | 0xc8 | 0xc9 | 0xca | 0xcb | 0xcc | 0xcd | 0xce | 0xcf as b -> illegal s pos b - | 0xd0 -> ref_null - | 0xd1 -> ref_is_null + | 0xd0 -> ref_null (ref_type s) + | 0xd1 -> ref_is_null (ref_type s) | 0xd2 -> ref_func (at var s) | 0xfc as b1 -> diff --git a/interpreter/binary/encode.ml b/interpreter/binary/encode.ml index 6910cf4256..c0263df559 100644 --- a/interpreter/binary/encode.ml +++ b/interpreter/binary/encode.ml @@ -98,13 +98,11 @@ let encode m = let ref_type = function | FuncRefType -> vs7 (-0x10) - | AnyRefType -> vs7 (-0x11) - | NullRefType -> vs7 (-0x12) + | ExternRefType -> vs7 (-0x11) let value_type = function | NumType t -> num_type t | RefType t -> ref_type t - | BotType -> assert false let stack_type = function | [] -> vs7 (-0x40) @@ -233,8 +231,8 @@ let encode m = | MemoryInit x -> op 0xfc; op 0x08; var x; u8 0x00 | DataDrop x -> op 0xfc; op 0x09; var x - | RefNull -> op 0xd0 - | RefIsNull -> op 0xd1 + | RefNull t -> op 0xd0; ref_type t + | RefIsNull t -> op 0xd1; ref_type t | RefFunc x -> op 0xd2; var x | Const {it = I32 c; _} -> op 0x41; vs32 c diff --git a/interpreter/exec/eval.ml b/interpreter/exec/eval.ml index 5880285015..aae2a0ce5b 100644 --- a/interpreter/exec/eval.ml +++ b/interpreter/exec/eval.ml @@ -97,7 +97,7 @@ let any_ref inst x i at = let func_ref inst x i at = match any_ref inst x i at with | FuncRef f -> f - | NullRef -> Trap.error at ("uninitialized element " ^ Int32.to_string i) + | NullRef _ -> Trap.error at ("uninitialized element " ^ Int32.to_string i) | _ -> Crash.error at ("type mismatch for element " ^ Int32.to_string i) let take n (vs : 'a stack) at = @@ -407,14 +407,16 @@ let rec step (c : config) : config = seg := ""; vs, [] - | RefNull, vs' -> - Ref NullRef :: vs', [] + | RefNull t, vs' -> + Ref (NullRef t) :: vs', [] - | RefIsNull, Ref r :: vs' -> - if r = NullRef then + | RefIsNull _, Ref r :: vs' -> + (match r with + | NullRef _ -> Num (I32 1l) :: vs', [] - else + | _ -> Num (I32 0l) :: vs', [] + ) | RefFunc x, vs' -> let f = func frame.inst x in @@ -534,7 +536,7 @@ let invoke (func : func_inst) (vs : value list) : value list = let FuncType (ins, out) = Func.type_of func in if List.length vs <> List.length ins then Crash.error at "wrong number of arguments"; - if not (List.for_all2 (fun v -> match_value_type (type_of_value v)) vs ins) then + if not (List.for_all2 (fun v -> (=) (type_of_value v)) vs ins) then Crash.error at "wrong types of arguments"; let c = config empty_module_inst (List.rev vs) [Invoke func @@ at] in try List.rev (eval c) with Stack_overflow -> @@ -554,7 +556,8 @@ let create_func (inst : module_inst) (f : func) : func_inst = let create_table (inst : module_inst) (tab : table) : table_inst = let {ttype} = tab.it in - Table.alloc ttype NullRef + let TableType (_lim, t) = ttype in + Table.alloc ttype (NullRef t) let create_memory (inst : module_inst) (mem : memory) : memory_inst = let {mtype} = mem.it in diff --git a/interpreter/host/spectest.ml b/interpreter/host/spectest.ml index a8d32aa55e..8d67b3b79a 100644 --- a/interpreter/host/spectest.ml +++ b/interpreter/host/spectest.ml @@ -14,12 +14,12 @@ let global (GlobalType (t, _) as gt) = | NumType I64Type -> Num (I64 666L) | NumType F32Type -> Num (F32 (F32.of_float 666.6)) | NumType F64Type -> Num (F64 (F64.of_float 666.6)) - | RefType _ -> Ref NullRef - | BotType -> assert false + | RefType t -> Ref (NullRef t) in Global.alloc gt v let table = - Table.alloc (TableType ({min = 10l; max = Some 20l}, FuncRefType)) NullRef + Table.alloc (TableType ({min = 10l; max = Some 20l}, FuncRefType)) + (NullRef FuncRefType) let memory = Memory.alloc (MemoryType {min = 1l; max = Some 2l}) let func f t = Func.alloc_host t (f t) diff --git a/interpreter/runtime/global.ml b/interpreter/runtime/global.ml index 181399e0a1..5e1729950a 100644 --- a/interpreter/runtime/global.ml +++ b/interpreter/runtime/global.ml @@ -8,7 +8,7 @@ exception Type exception NotMutable let alloc (GlobalType (t, _) as ty) v = - if not (match_value_type (type_of_value v) t) then raise Type; + if type_of_value v <> t then raise Type; {ty; content = v} let type_of glob = @@ -20,5 +20,5 @@ let load glob = let store glob v = let GlobalType (t, mut) = glob.ty in if mut <> Mutable then raise NotMutable; - if not (match_value_type (type_of_value v) t) then raise Type; + if type_of_value v <> t then raise Type; glob.content <- v diff --git a/interpreter/runtime/table.ml b/interpreter/runtime/table.ml index 8da0090eb5..bb10cab8b3 100644 --- a/interpreter/runtime/table.ml +++ b/interpreter/runtime/table.ml @@ -51,7 +51,7 @@ let load tab i = let store tab i r = let TableType (lim, t) = tab.ty in - if not (match_ref_type (type_of_ref r) t) then raise Type; + if type_of_ref r <> t then raise Type; try Lib.Array32.set tab.content i r with Invalid_argument _ -> raise Bounds let blit tab offset rs = diff --git a/interpreter/script/js.ml b/interpreter/script/js.ml index f0eeb11441..66efeb730e 100644 --- a/interpreter/script/js.ml +++ b/interpreter/script/js.ml @@ -10,25 +10,28 @@ let harness = {| 'use strict'; -let hostrefs = {}; -let hostsym = Symbol("hostref"); -function hostref(s) { - if (! (s in hostrefs)) hostrefs[s] = {[hostsym]: s}; - return hostrefs[s]; +let externrefs = {}; +let externsym = Symbol("externref"); +function externref(s) { + if (! (s in externrefs)) externrefs[s] = {[externsym]: s}; + return externrefs[s]; } -function is_hostref(x) { - return (x !== null && hostsym in x) ? 1 : 0; +function is_externref(x) { + return (x !== null && externsym in x) ? 1 : 0; } function is_funcref(x) { return typeof x === "function" ? 1 : 0; } -function eq_ref(x, y) { +function eq_externref(x, y) { + return x === y ? 1 : 0; +} +function eq_funcref(x, y) { return x === y ? 1 : 0; } let spectest = { - hostref: hostref, - is_hostref: is_hostref, + externref: externref, + is_externref: is_externref, is_funcref: is_funcref, eq_ref: eq_ref, print: console.log.bind(console), @@ -157,7 +160,7 @@ function assert_return(action, expected) { throw new Error("Wasm function return value expected, got " + actual); }; return; - case "ref.any": + case "ref.extern": if (actual === null) { throw new Error("Wasm reference return value expected, got " + actual); }; @@ -211,11 +214,12 @@ let lookup (mods : modules) x_opt name at = (* Wrappers *) let subject_idx = 0l -let hostref_idx = 1l -let _is_hostref_idx = 2l +let externref_idx = 1l +let is_externref_idx = 2l let is_funcref_idx = 3l -let eq_ref_idx = 4l -let subject_type_idx = 5l +let eq_externref_idx = 4l +let _eq_funcref_idx = 5l +let subject_type_idx = 6l let eq_of = function | I32Type -> Values.I32 I32Op.Eq @@ -244,9 +248,9 @@ let abs_mask_of = function let value v = match v.it with | Values.Num num -> [Const (num @@ v.at) @@ v.at] - | Values.Ref Values.NullRef -> [RefNull @@ v.at] - | Values.Ref (HostRef n) -> - [Const (Values.I32 n @@ v.at) @@ v.at; Call (hostref_idx @@ v.at) @@ v.at] + | Values.Ref (Values.NullRef t) -> [RefNull t @@ v.at] + | Values.Ref (ExternRef n) -> + [Const (Values.I32 n @@ v.at) @@ v.at; Call (externref_idx @@ v.at) @@ v.at] | Values.Ref _ -> assert false let invoke ft vs at = @@ -270,14 +274,14 @@ let assert_return ress ts at = Compare (eq_of t') @@ at; Test (Values.I32 I32Op.Eqz) @@ at; BrIf (0l @@ at) @@ at ] - | LitResult {it = Values.Ref Values.NullRef; _} -> - [ RefIsNull @@ at; + | LitResult {it = Values.Ref (Values.NullRef t); _} -> + [ RefIsNull t @@ at; Test (Values.I32 I32Op.Eqz) @@ at; BrIf (0l @@ at) @@ at ] - | LitResult {it = Values.Ref (HostRef n); _} -> + | LitResult {it = Values.Ref (ExternRef n); _} -> [ Const (Values.I32 n @@ at) @@ at; - Call (hostref_idx @@ at) @@ at; - Call (eq_ref_idx @@ at) @@ at; + Call (externref_idx @@ at) @@ at; + Call (eq_externref_idx @@ at) @@ at; Test (Values.I32 I32Op.Eqz) @@ at; BrIf (0l @@ at) @@ at ] | LitResult {it = Values.Ref _; _} -> @@ -302,11 +306,13 @@ let assert_return ress ts at = Compare (eq_of t') @@ at; Test (Values.I32 I32Op.Eqz) @@ at; BrIf (0l @@ at) @@ at ] - | RefResult -> - [ RefIsNull @@ at; - BrIf (0l @@ at) @@ at ] - | FuncResult -> - [ Call (is_funcref_idx @@ at) @@ at; + | RefResult t -> + let is_ref_idx = + match t with + | FuncRefType -> is_funcref_idx + | ExternRefType -> is_externref_idx + in + [ Call (is_ref_idx @@ at) @@ at; Test (Values.I32 I32Op.Eqz) @@ at; BrIf (0l @@ at) @@ at ] in [], List.flatten (List.rev_map test ress) @@ -316,22 +322,25 @@ let wrap item_name wrap_action wrap_assertion at = let locals, assertion = wrap_assertion at in let types = (FuncType ([], []) @@ at) :: - (FuncType ([NumType I32Type], [RefType AnyRefType]) @@ at) :: - (FuncType ([RefType AnyRefType], [NumType I32Type]) @@ at) :: - (FuncType ([RefType AnyRefType], [NumType I32Type]) @@ at) :: - (FuncType ([RefType AnyRefType; RefType AnyRefType], [NumType I32Type]) @@ at) :: + (FuncType ([NumType I32Type], [RefType ExternRefType]) @@ at) :: + (FuncType ([RefType ExternRefType], [NumType I32Type]) @@ at) :: + (FuncType ([RefType FuncRefType], [NumType I32Type]) @@ at) :: + (FuncType ([RefType ExternRefType; RefType ExternRefType], [NumType I32Type]) @@ at) :: + (FuncType ([RefType FuncRefType; RefType FuncRefType], [NumType I32Type]) @@ at) :: itypes in let imports = [ {module_name = Utf8.decode "module"; item_name; idesc} @@ at; - {module_name = Utf8.decode "spectest"; item_name = Utf8.decode "hostref"; + {module_name = Utf8.decode "spectest"; item_name = Utf8.decode "externref"; idesc = FuncImport (1l @@ at) @@ at} @@ at; - {module_name = Utf8.decode "spectest"; item_name = Utf8.decode "is_hostref"; + {module_name = Utf8.decode "spectest"; item_name = Utf8.decode "is_externref"; idesc = FuncImport (2l @@ at) @@ at} @@ at; {module_name = Utf8.decode "spectest"; item_name = Utf8.decode "is_funcref"; idesc = FuncImport (3l @@ at) @@ at} @@ at; - {module_name = Utf8.decode "spectest"; item_name = Utf8.decode "eq_ref"; - idesc = FuncImport (4l @@ at) @@ at} @@ at ] + {module_name = Utf8.decode "spectest"; item_name = Utf8.decode "eq_externref"; + idesc = FuncImport (4l @@ at) @@ at} @@ at; + {module_name = Utf8.decode "spectest"; item_name = Utf8.decode "eq_funcref"; + idesc = FuncImport (5l @@ at) @@ at} @@ at ] in let item = List.fold_left @@ -357,7 +366,6 @@ let is_js_num_type = function let is_js_value_type = function | NumType t -> is_js_num_type t | RefType t -> true - | BotType -> assert false let is_js_global_type = function | GlobalType (t, mut) -> is_js_value_type t && mut = Immutable @@ -407,8 +415,8 @@ let of_value v = | Num (I64 i) -> "int64(\"" ^ I64.to_string_s i ^ "\")" | Num (F32 z) -> of_float (F32.to_float z) | Num (F64 z) -> of_float (F64.to_float z) - | Ref NullRef -> "null" - | Ref (HostRef n) -> "hostref(" ^ Int32.to_string n ^ ")" + | Ref (NullRef _) -> "null" + | Ref (ExternRef n) -> "externref(" ^ Int32.to_string n ^ ")" | _ -> assert false let of_nan = function @@ -423,8 +431,7 @@ let of_result res = | Values.I32 _ | Values.I64 _ -> assert false | Values.F32 n | Values.F64 n -> of_nan n ) - | RefResult -> "\"ref.any\"" - | FuncResult -> "\"ref.func\"" + | RefResult t -> "\"ref." ^ string_of_refed_type t ^ "\"" let rec of_definition def = match def.it with diff --git a/interpreter/script/run.ml b/interpreter/script/run.ml index 11764e43ab..3eacaccafa 100644 --- a/interpreter/script/run.ml +++ b/interpreter/script/run.ml @@ -254,8 +254,7 @@ let type_of_result r = match r with | LitResult v -> Values.type_of_value v.it | NanResult n -> Types.NumType (Values.type_of_num n.it) - | RefResult -> Types.RefType Types.AnyRefType - | FuncResult -> Types.RefType Types.FuncRefType + | RefResult t -> Types.RefType t let string_of_result r = match r with @@ -265,8 +264,7 @@ let string_of_result r = | Values.I32 _ | Values.I64 _ -> assert false | Values.F32 n | Values.F64 n -> string_of_nan n ) - | RefResult -> "ref" - | FuncResult -> "func" + | RefResult t -> Types.string_of_refed_type t let string_of_results = function | [r] -> string_of_result r @@ -337,7 +335,7 @@ let run_action act : Values.value list = if List.length vs <> List.length ins then Script.error act.at "wrong number of arguments"; List.iter2 (fun v t -> - if not (Types.match_value_type (Values.type_of_value v.it) t) then + if Values.type_of_value v.it <> t then Script.error v.at "wrong type of argument" ) vs ins; Eval.invoke f (List.map (fun v -> v.it) vs) @@ -375,14 +373,10 @@ let assert_result at got expect = Int64.logand (F64.to_bits z) pos_nan <> pos_nan | _, _ -> false ) - | RefResult -> - (match v with - | Ref ref -> ref = NullRef - | _ -> true - ) - | FuncResult -> - (match v with - | Ref (Instance.FuncRef _) -> false + | RefResult t -> + (match t, v with + | Types.FuncRefType, Ref (Instance.FuncRef _) + | Types.ExternRefType, Ref (ExternRef _) -> false | _ -> true ) ) got expect diff --git a/interpreter/script/script.ml b/interpreter/script/script.ml index 0c664c012b..50531b2fa3 100644 --- a/interpreter/script/script.ml +++ b/interpreter/script/script.ml @@ -1,6 +1,6 @@ type var = string Source.phrase -type Values.ref_ += HostRef of int32 +type Values.ref_ += ExternRef of int32 type value = Values.value Source.phrase type definition = definition' Source.phrase @@ -22,8 +22,7 @@ type result = result' Source.phrase and result' = | LitResult of Values.value Source.phrase | NanResult of nanop - | RefResult - | FuncResult + | RefResult of Types.ref_type type assertion = assertion' Source.phrase and assertion' = @@ -57,11 +56,11 @@ exception Syntax of Source.region * string let () = let type_of_ref' = !Values.type_of_ref' in Values.type_of_ref' := function - | HostRef _ -> Types.AnyRefType + | ExternRef _ -> Types.ExternRefType | r -> type_of_ref' r let () = let string_of_ref' = !Values.string_of_ref' in Values.string_of_ref' := function - | HostRef n -> "ref " ^ Int32.to_string n + | ExternRef n -> "ref " ^ Int32.to_string n | r -> string_of_ref' r diff --git a/interpreter/syntax/ast.ml b/interpreter/syntax/ast.ml index d3e1c6c08e..c78a671a5a 100644 --- a/interpreter/syntax/ast.ml +++ b/interpreter/syntax/ast.ml @@ -102,8 +102,8 @@ and instr' = | MemoryCopy (* copy memory ranges *) | MemoryInit of var (* initialize memory range from segment *) | DataDrop of var (* drop passive data segment *) - | RefNull (* null reference *) - | RefIsNull (* null test *) + | RefNull of ref_type (* null reference *) + | RefIsNull of ref_type (* null test *) | RefFunc of var (* function reference *) | Const of num (* constant *) | Test of testop (* numeric test *) diff --git a/interpreter/syntax/free.ml b/interpreter/syntax/free.ml index af322f672d..fb8973cf49 100644 --- a/interpreter/syntax/free.ml +++ b/interpreter/syntax/free.ml @@ -62,7 +62,7 @@ let list free xs = List.fold_left union empty (List.map free xs) let rec instr (e : instr) = match e.it with | Unreachable | Nop | Drop | Select _ -> empty - | RefNull | RefIsNull -> empty + | RefNull _ | RefIsNull _ -> empty | RefFunc x -> funcs (var x) | Const _ | Test _ | Compare _ | Unary _ | Binary _ | Convert _ -> empty | Block (_, es) | Loop (_, es) -> block es diff --git a/interpreter/syntax/operators.ml b/interpreter/syntax/operators.ml index e804a41395..4a5d5a4809 100644 --- a/interpreter/syntax/operators.ml +++ b/interpreter/syntax/operators.ml @@ -9,9 +9,9 @@ let i32_const n = Const (I32 n.it @@ n.at) let i64_const n = Const (I64 n.it @@ n.at) let f32_const n = Const (F32 n.it @@ n.at) let f64_const n = Const (F64 n.it @@ n.at) -let ref_null = RefNull let ref_func x = RefFunc x -let ref_is_null = RefIsNull +let ref_null t = RefNull t +let ref_is_null t = RefIsNull t let unreachable = Unreachable let nop = Nop diff --git a/interpreter/syntax/types.ml b/interpreter/syntax/types.ml index fb3f13b1ba..82faaf6e9b 100644 --- a/interpreter/syntax/types.ml +++ b/interpreter/syntax/types.ml @@ -1,8 +1,8 @@ (* Types *) type num_type = I32Type | I64Type | F32Type | F64Type -type ref_type = NullRefType | AnyRefType | FuncRefType -type value_type = NumType of num_type | RefType of ref_type | BotType +type ref_type = FuncRefType | ExternRefType +type value_type = NumType of num_type | RefType of ref_type type stack_type = value_type list type func_type = FuncType of stack_type * stack_type @@ -24,24 +24,28 @@ let size = function | I32Type | F32Type -> 4 | I64Type | F64Type -> 8 +let is_num_type = function + | NumType _ -> true + | RefType _ -> false -(* Subtyping *) +let is_ref_type = function + | NumType _ -> false + | RefType _ -> true -let match_num_type t1 t2 = - t1 = t2 -let match_ref_type t1 t2 = - match t1, t2 with - | _, AnyRefType -> true - | NullRefType, _ -> true - | _, _ -> t1 = t2 +(* Filters *) -let match_value_type t1 t2 = - match t1, t2 with - | NumType t1', NumType t2' -> match_num_type t1' t2' - | RefType t1', RefType t2' -> match_ref_type t1' t2' - | BotType, _ -> true - | _, _ -> false +let funcs = + Lib.List.map_filter (function ExternFuncType t -> Some t | _ -> None) +let tables = + Lib.List.map_filter (function ExternTableType t -> Some t | _ -> None) +let memories = + Lib.List.map_filter (function ExternMemoryType t -> Some t | _ -> None) +let globals = + Lib.List.map_filter (function ExternGlobalType t -> Some t | _ -> None) + + +(* Subtyping *) let match_limits lim1 lim2 = I32.ge_u lim1.min lim2.min && @@ -59,9 +63,8 @@ let match_table_type (TableType (lim1, et1)) (TableType (lim2, et2)) = let match_memory_type (MemoryType lim1) (MemoryType lim2) = match_limits lim1 lim2 -let match_global_type (GlobalType (t1, mut1)) (GlobalType (t2, mut2)) = - mut1 = mut2 && - (t1 = t2 || mut2 = Immutable && match_value_type t1 t2) +let match_global_type gt1 gt2 = + gt1 = gt2 let match_extern_type et1 et2 = match et1, et2 with @@ -71,26 +74,6 @@ let match_extern_type et1 et2 = | ExternGlobalType gt1, ExternGlobalType gt2 -> match_global_type gt1 gt2 | _, _ -> false -let is_num_type = function - | NumType _ | BotType -> true - | RefType _ -> false - -let is_ref_type = function - | NumType _ -> false - | RefType _ | BotType -> true - - -(* Filters *) - -let funcs = - Lib.List.map_filter (function ExternFuncType t -> Some t | _ -> None) -let tables = - Lib.List.map_filter (function ExternTableType t -> Some t | _ -> None) -let memories = - Lib.List.map_filter (function ExternMemoryType t -> Some t | _ -> None) -let globals = - Lib.List.map_filter (function ExternGlobalType t -> Some t | _ -> None) - (* String conversion *) @@ -101,14 +84,16 @@ let string_of_num_type = function | F64Type -> "f64" let string_of_ref_type = function - | NullRefType -> "nullref" - | AnyRefType -> "anyref" | FuncRefType -> "funcref" + | ExternRefType -> "externref" + +let string_of_refed_type = function + | FuncRefType -> "func" + | ExternRefType -> "extern" let string_of_value_type = function | NumType t -> string_of_num_type t | RefType t -> string_of_ref_type t - | BotType -> "impossible" let string_of_value_types = function | [t] -> string_of_value_type t diff --git a/interpreter/syntax/values.ml b/interpreter/syntax/values.ml index 6907ae75b9..634166092d 100644 --- a/interpreter/syntax/values.ml +++ b/interpreter/syntax/values.ml @@ -9,7 +9,7 @@ type ('i32, 'i64, 'f32, 'f64) op = type num = (I32.t, I64.t, F32.t, F64.t) op type ref_ = .. -type ref_ += NullRef +type ref_ += NullRef of ref_type type value = Num of num | Ref of ref_ @@ -22,7 +22,7 @@ let type_of_num = function | F32 _ -> F32Type | F64 _ -> F64Type -let type_of_ref' = ref (function NullRef -> NullRefType | _ -> AnyRefType) +let type_of_ref' = ref (function NullRef t -> t | _ -> assert false) let type_of_ref r = !type_of_ref' r let type_of_value = function @@ -50,12 +50,11 @@ let default_num = function | F64Type -> F64 F64.zero let default_ref = function - | _ -> NullRef + | t -> NullRef t let default_value = function | NumType t' -> Num (default_num t') | RefType t' -> Ref (default_ref t') - | BotType -> assert false (* Conversion *) @@ -68,7 +67,7 @@ let string_of_num = function | F32 z -> F32.to_string z | F64 z -> F64.to_string z -let string_of_ref' = ref (function NullRef -> "null" | _ -> "ref") +let string_of_ref' = ref (function NullRef t -> "null" | _ -> "ref") let string_of_ref r = !string_of_ref' r let string_of_value = function diff --git a/interpreter/text/arrange.ml b/interpreter/text/arrange.ml index 6fc76e9325..a6733c1a51 100644 --- a/interpreter/text/arrange.ml +++ b/interpreter/text/arrange.ml @@ -57,6 +57,7 @@ let break_string s = let num_type t = string_of_num_type t let ref_type t = string_of_ref_type t +let refed_type t = string_of_refed_type t let value_type t = string_of_value_type t let decls kind ts = tab kind (atom value_type) ts @@ -262,8 +263,8 @@ let rec instr e = | MemoryCopy -> "memory.copy", [] | MemoryInit x -> "memory.init " ^ var x, [] | DataDrop x -> "data.drop " ^ var x, [] - | RefNull -> "ref.null", [] - | RefIsNull -> "ref.is_null", [] + | RefNull t -> "ref.null", [Atom (refed_type t)] + | RefIsNull t -> "ref.is_null", [Atom (refed_type t)] | RefFunc x -> "ref.func " ^ var x, [] | Const n -> constop n ^ " " ^ num n, [] | Test op -> testop op, [] @@ -431,8 +432,8 @@ let value v = | Num (Values.I64 i) -> Node ("i64.const " ^ I64.to_string_s i, []) | Num (Values.F32 z) -> Node ("f32.const " ^ F32.to_string z, []) | Num (Values.F64 z) -> Node ("f64.const " ^ F64.to_string z, []) - | Ref NullRef -> Node ("ref.null", []) - | Ref (HostRef n) -> Node ("ref.host " ^ Int32.to_string n, []) + | Ref (NullRef t) -> Node ("ref.null", [Atom (refed_type t)]) + | Ref (ExternRef n) -> Node ("ref.extern " ^ Int32.to_string n, []) | _ -> assert false let definition mode x_opt def = @@ -483,8 +484,7 @@ let result res = | Values.F32 n -> Node ("f32.const " ^ nan n, []) | Values.F64 n -> Node ("f64.const " ^ nan n, []) ) - | RefResult -> Node ("ref", []) - | FuncResult -> Node ("ref.func", []) + | RefResult t -> Node ("ref." ^ refed_type t, []) let assertion mode ass = match ass.it with diff --git a/interpreter/text/lexer.mll b/interpreter/text/lexer.mll index 3a1c3f1145..36524d236a 100644 --- a/interpreter/text/lexer.mll +++ b/interpreter/text/lexer.mll @@ -160,9 +160,9 @@ rule token = parse | '"'character*'\\'_ { error_nest (Lexing.lexeme_end_p lexbuf) lexbuf "illegal escape" } - | "anyref" { ANYREF } + | "extern" { EXTERN } + | "externref" { EXTERNREF } | "funcref" { FUNCREF } - | "nullref" { NULLREF } | (nxx as t) { NUM_TYPE (num_type t) } | "mut" { MUT } @@ -180,7 +180,7 @@ rule token = parse } | "ref.null" { REF_NULL } | "ref.func" { REF_FUNC } - | "ref.host" { REF_HOST } + | "ref.extern" { REF_EXTERN } | "ref.is_null" { REF_IS_NULL } | "nop" { NOP } @@ -370,7 +370,6 @@ rule token = parse | "assert_exhaustion" { ASSERT_EXHAUSTION } | "nan:canonical" { NAN Script.CanonicalNan } | "nan:arithmetic" { NAN Script.ArithmeticNan } - | "ref.any" { REF_ANY } | "input" { INPUT } | "output" { OUTPUT } diff --git a/interpreter/text/parser.mly b/interpreter/text/parser.mly index 07be9cbcb1..445c6db3b1 100644 --- a/interpreter/text/parser.mly +++ b/interpreter/text/parser.mly @@ -164,7 +164,7 @@ let inline_type_explicit (c : context) x ft at = %token LPAR RPAR %token NAT INT FLOAT STRING VAR -%token ANYREF NULLREF FUNCREF NUM_TYPE MUT +%token NUM_TYPE FUNCREF EXTERNREF EXTERN MUT %token UNREACHABLE NOP DROP SELECT %token BLOCK END IF THEN ELSE LOOP BR BR_IF BR_TABLE %token CALL CALL_INDIRECT RETURN @@ -174,7 +174,7 @@ let inline_type_explicit (c : context) x ft at = %token MEMORY_SIZE MEMORY_GROW MEMORY_FILL MEMORY_COPY MEMORY_INIT DATA_DROP %token LOAD STORE OFFSET_EQ_NAT ALIGN_EQ_NAT %token CONST UNARY BINARY TEST COMPARE CONVERT -%token REF_ANY REF_NULL REF_FUNC REF_HOST REF_IS_NULL +%token REF_NULL REF_FUNC REF_EXTERN REF_IS_NULL %token FUNC START TYPE PARAM RESULT LOCAL GLOBAL %token TABLE ELEM MEMORY DATA DECLARE OFFSET ITEM IMPORT EXPORT %token MODULE BIN QUOTE @@ -226,10 +226,13 @@ string_list : /* Types */ +ref_kind : + | FUNC { FuncRefType } + | EXTERN { ExternRefType } + ref_type : - | ANYREF { AnyRefType } | FUNCREF { FuncRefType } - | NULLREF { NullRefType } + | EXTERNREF { ExternRefType } value_type : | NUM_TYPE { NumType $1 } @@ -372,8 +375,8 @@ plain_instr : | MEMORY_COPY { fun c -> memory_copy } | MEMORY_INIT var { fun c -> memory_init ($2 c data) } | DATA_DROP var { fun c -> data_drop ($2 c data) } - | REF_NULL { fun c -> ref_null } - | REF_IS_NULL { fun c -> ref_is_null } + | REF_NULL ref_kind { fun c -> ref_null $2 } + | REF_IS_NULL ref_kind { fun c -> ref_is_null $2 } | REF_FUNC var { fun c -> ref_func ($2 c func) } | CONST num { fun c -> fst (num $1 $2) } | TEST { fun c -> $1 } @@ -986,8 +989,8 @@ meta : const : | LPAR CONST num RPAR { Values.Num (snd (num $2 $3)) @@ at () } - | LPAR REF_NULL RPAR { Values.Ref Values.NullRef @@ at () } - | LPAR REF_HOST NAT RPAR { Values.Ref (HostRef (nat32 $3 (ati 3))) @@ at () } + | LPAR REF_NULL ref_kind RPAR { Values.Ref (Values.NullRef $3) @@ at () } + | LPAR REF_EXTERN NAT RPAR { Values.Ref (ExternRef (nat32 $3 (ati 3))) @@ at () } const_list : | /* empty */ { [] } @@ -996,8 +999,8 @@ const_list : result : | const { LitResult $1 @@ at () } | LPAR CONST NAN RPAR { NanResult (nanop $2 ($3 @@ ati 3)) @@ at () } - | LPAR REF_ANY RPAR { RefResult @@ at () } - | LPAR REF_FUNC RPAR { FuncResult @@ at () } + | LPAR REF_FUNC RPAR { RefResult FuncRefType @@ at () } + | LPAR REF_EXTERN RPAR { RefResult ExternRefType @@ at () } result_list : | /* empty */ { [] } diff --git a/interpreter/valid/valid.ml b/interpreter/valid/valid.ml index 30de76a624..1eb6bcf1b4 100644 --- a/interpreter/valid/valid.ml +++ b/interpreter/valid/valid.ml @@ -70,25 +70,32 @@ let refer_func (c : context) x = refer "function" c.refs.Free.funcs x *) type ellipses = NoEllipses | Ellipses -type infer_stack_type = ellipses * value_type list +type infer_stack_type = ellipses * value_type option list type op_type = {ins : infer_stack_type; outs : infer_stack_type} -let stack ts = (NoEllipses, ts) -let (-->) ts1 ts2 = {ins = NoEllipses, ts1; outs = NoEllipses, ts2} -let (-->...) ts1 ts2 = {ins = Ellipses, ts1; outs = Ellipses, ts2} +let known = List.map (fun t -> Some t) +let stack ts = (NoEllipses, known ts) +let (-~>) ts1 ts2 = {ins = NoEllipses, ts1; outs = NoEllipses, ts2} +let (-->) ts1 ts2 = {ins = NoEllipses, known ts1; outs = NoEllipses, known ts2} +let (-->...) ts1 ts2 = {ins = Ellipses, known ts1; outs = Ellipses, known ts2} +let string_of_infer_type t = + Lib.Option.get (Lib.Option.map string_of_value_type t) "_" +let string_of_infer_types ts = + "[" ^ String.concat " " (List.map string_of_infer_type ts) ^ "]" + +let eq_ty t1 t2 = (t1 = t2 || t1 = None || t2 = None) let check_stack ts1 ts2 at = - require - (List.length ts1 = List.length ts2 && List.for_all2 match_value_type ts1 ts2) at - ("type mismatch: operator requires " ^ string_of_stack_type ts2 ^ - " but stack has " ^ string_of_stack_type ts1) + require (List.length ts1 = List.length ts2 && List.for_all2 eq_ty ts1 ts2) at + ("type mismatch: operator requires " ^ string_of_infer_types ts1 ^ + " but stack has " ^ string_of_infer_types ts2) let pop (ell1, ts1) (ell2, ts2) at = let n1 = List.length ts1 in let n2 = List.length ts2 in let n = min n1 n2 in let n3 = if ell2 = Ellipses then (n1 - n) else 0 in - check_stack (Lib.List.make n3 BotType @ Lib.List.drop (n2 - n) ts2) ts1 at; + check_stack ts1 (Lib.List.make n3 None @ Lib.List.drop (n2 - n) ts2) at; (ell2, if ell1 = Ellipses then [] else Lib.List.take (n2 - n) ts2) let push (ell1, ts1) (ell2, ts2) = @@ -97,7 +104,7 @@ let push (ell1, ts1) (ell2, ts2) = ts2 @ ts1 let peek i (ell, ts) = - try List.nth (List.rev ts) i with Failure _ -> BotType + try List.nth (List.rev ts) i with Failure _ -> None (* Type Synthesis *) @@ -191,14 +198,14 @@ let rec check_instr (c : context) (e : instr) (s : infer_stack_type) : op_type = [] --> [] | Drop -> - [peek 0 s] --> [] + [peek 0 s] -~> [] | Select None -> let t = peek 1 s in - require (is_num_type t) e.at + require (match t with None -> true | Some t -> is_num_type t) e.at ("type mismatch: instruction requires numeric type" ^ - " but stack has " ^ string_of_value_type t); - [t; t; NumType I32Type] --> [t] + " but stack has " ^ string_of_infer_type t); + [t; t; Some (NumType I32Type)] -~> [t] | Select (Some ts) -> check_arity (List.length ts) e.at; @@ -228,10 +235,8 @@ let rec check_instr (c : context) (e : instr) (s : infer_stack_type) : op_type = (label c x @ [NumType I32Type]) --> label c x | BrTable (xs, x) -> - let n = List.length (label c x) in - let ts = Lib.List.table n (fun i -> peek (i + 1) s) in - check_stack ts (label c x) x.at; - List.iter (fun x' -> check_stack ts (label c x') x'.at) xs; + let ts = label c x in + List.iter (fun x' -> check_stack (known ts) (known (label c x')) x'.at) xs; (ts @ [NumType I32Type]) -->... [] | Return -> @@ -244,7 +249,7 @@ let rec check_instr (c : context) (e : instr) (s : infer_stack_type) : op_type = | CallIndirect (x, y) -> let TableType (lim, t) = table c x in let FuncType (ins, out) = type_ c y in - require (match_ref_type t FuncRefType) x.at + require (t = FuncRefType) x.at ("type mismatch: instruction requires table of functions" ^ " but table has " ^ string_of_ref_type t); (ins @ [NumType I32Type]) --> out @@ -290,7 +295,7 @@ let rec check_instr (c : context) (e : instr) (s : infer_stack_type) : op_type = | TableCopy (x, y) -> let TableType (_lim1, t1) = table c x in let TableType (_lim2, t2) = table c y in - require (match_ref_type t2 t1) x.at + require (t1 = t2) x.at ("type mismatch: source element type " ^ string_of_ref_type t1 ^ " does not match destination element type " ^ string_of_ref_type t2); [NumType I32Type; NumType I32Type; NumType I32Type] --> [] @@ -298,7 +303,7 @@ let rec check_instr (c : context) (e : instr) (s : infer_stack_type) : op_type = | TableInit (x, y) -> let TableType (_lim1, t1) = table c x in let t2 = elem c y in - require (match_ref_type t2 t1) x.at + require (t1 = t2) x.at ("type mismatch: source element type " ^ string_of_ref_type t1 ^ " does not match destination element type " ^ string_of_ref_type t2); [NumType I32Type; NumType I32Type; NumType I32Type] --> [] @@ -342,11 +347,11 @@ let rec check_instr (c : context) (e : instr) (s : infer_stack_type) : op_type = ignore (data c x); [] --> [] - | RefNull -> - [] --> [RefType NullRefType] + | RefNull t -> + [] --> [RefType t] - | RefIsNull -> - [RefType AnyRefType] --> [NumType I32Type] + | RefIsNull t -> + [RefType t] --> [NumType I32Type] | RefFunc x -> let _ft = func c x in @@ -393,7 +398,7 @@ and check_block (c : context) (es : instr list) (ts : stack_type) at = let s' = pop (stack ts) s at in require (snd s' = []) at ("type mismatch: operator requires " ^ string_of_stack_type ts ^ - " but stack has " ^ string_of_stack_type (snd s)) + " but stack has " ^ string_of_infer_types (snd s)) (* Types *) @@ -417,7 +422,6 @@ let check_value_type (t : value_type) at = match t with | NumType t' -> check_num_type t' at | RefType t' -> check_ref_type t' at - | BotType -> () let check_func_type (ft : func_type) at = let FuncType (ins, out) = ft in @@ -466,7 +470,7 @@ let check_func (c : context) (f : func) = let is_const (c : context) (e : instr) = match e.it with - | RefNull + | RefNull _ | RefFunc _ | Const _ -> true | GlobalGet x -> let GlobalType (_, mut) = global c x in mut = Immutable @@ -493,7 +497,7 @@ let check_elem_mode (c : context) (t : ref_type) (mode : segment_mode) = | Passive -> () | Active {index; offset} -> let TableType (_, et) = table c index in - require (match_ref_type t et) mode.at + require (t = et) mode.at "type mismatch in active element segment"; check_const c offset (NumType I32Type) | Declarative -> () diff --git a/proposals/reference-types/Overview.md b/proposals/reference-types/Overview.md index 8e35ab7106..14ff3b4163 100644 --- a/proposals/reference-types/Overview.md +++ b/proposals/reference-types/Overview.md @@ -7,7 +7,7 @@ TODO: more text, motivation, explanation Motivation: * Easier and more efficient interop with host environment (see e.g. the [Interface Types proposal](https://github.com/WebAssembly/interface-types/blob/master/proposals/interface-types/Explainer.md)) - - allow host references to be represented directly by type `anyref` (see [here](https://github.com/WebAssembly/interface-types/issues/9)) + - allow host references to be represented directly by type `externref` (see [here](https://github.com/WebAssembly/interface-types/issues/9)) - without having to go through tables, allocating slots, and maintaining index bijections at the boundaries * Basic manipulation of tables inside Wasm @@ -25,8 +25,7 @@ by repurposing tables as a general memory for opaque data types Get the most important parts soon! Summary: - -* Add new types `anyref` and `nullref` that can be used as both a value types and a table element types. +* Add new type `externref` that can be used as both a value types and a table element type. * Also allow `funcref` as a value type. @@ -47,8 +46,8 @@ Notes: Typing extensions: -* Introduce `anyref`, `funcref`, and `nullref` as a new class of *reference types*. - - `reftype ::= anyref | funcref | nullref` +* Introduce `funcref` and `externref` as a new class of *reference types*. + - `reftype ::= funcref | externref` * Value types (of locals, globals, function parameters and results) can now be either numeric types or reference types. - `numtype ::= i32 | i64 | f32 | f64` @@ -58,21 +57,17 @@ Typing extensions: * Element types (of tables) are equated with reference types. - `elemtype ::= ` -* Introduce a simple subtype relation between reference types. - - reflexive transitive closure of the following rules - - `t <: anyref` for all reftypes `t` - - `nullref <: anyref` and `nullref <: funcref` - - Note: No rule `nullref <: t` for all reftypes `t` -- while that is derivable from the above given the current set of types it might not hold for future reference types which don't allow null. - New/extended instructions: * The new instruction `ref.null` evaluates to the null reference constant. - - `ref.null : [] -> [nullref]` + - `ref.null rt : [] -> [rtref]` + - iff `rt = func` or `rt = extern` - allowed in constant expressions * The new instruction `ref.is_null` checks for null. - - `ref.is_null : [anyref] -> [i32]` + - `ref.is_null rt : [rtref] -> [i32]` + - iff `rt = func` or `rt = extern` * The new instruction `ref.func` creates a reference to a given function. - `ref.func $x : [] -> [funcref]` @@ -137,7 +132,7 @@ Table extensions: API extensions: -* Any JS value can be passed as `anyref` to a Wasm function, stored in a global, or in a table. +* Any JS value can be passed as `externref` to a Wasm function, stored in a global, or in a table. * Any Wasm exported function object or `null` can be passed as `funcref` to a Wasm function, stored in a global, or in a table. @@ -145,6 +140,19 @@ API extensions: ## Possible Future Extensions +### Subtyping + +Motivation: + +* Enable various extensions (see below). + +Additions: + +* Introduce a simple subtype relation between reference types. + - reflexive transitive closure of the following rules + - `t <: anyref` for all reftypes `t` + + ### Equality on references Motivation: @@ -159,7 +167,6 @@ Additions: - `reftype ::= ... | eqref` * It is a subtype of `anyref` - `eqref < anyref` - - `nullref < eqref` * Add `ref.eq` instruction. - `ref.eq : [eqref eqref] -> [i32]` diff --git a/test/core/binary.wast b/test/core/binary.wast index 91cdd3598b..4b00271df6 100644 --- a/test/core/binary.wast +++ b/test/core/binary.wast @@ -1116,10 +1116,10 @@ "\05\03\01\00\00" ;; Memory section - "\09\06\01" ;; Element section with one segment + "\09\07\01" ;; Element section with one segment "\05\70" ;; Passive, funcref "\01" ;; 1 element - "\d0\0b" ;; ref.null, end + "\d0\70\0b" ;; ref.null, end "\0a\04\01" ;; Code section diff --git a/test/core/br_table.wast b/test/core/br_table.wast index 48e7a874a3..fc84e2f01e 100644 --- a/test/core/br_table.wast +++ b/test/core/br_table.wast @@ -1243,72 +1243,13 @@ ) ) - (func (export "meet-anyref") (param i32) (param anyref) (result anyref) - (block $l1 (result anyref) - (block $l2 (result anyref) + (func (export "meet-externref") (param i32) (param externref) (result externref) + (block $l1 (result externref) + (block $l2 (result externref) (br_table $l1 $l2 $l1 (local.get 1) (local.get 0)) ) ) ) - - (func (export "meet-funcref-1") (param i32) (result anyref) - (block $l1 (result anyref) - (block $l2 (result funcref) - (br_table $l1 $l1 $l2 (table.get 0 (i32.const 0)) (local.get 0)) - ) - ) - ) - (func (export "meet-funcref-2") (param i32) (result anyref) - (block $l1 (result anyref) - (block $l2 (result funcref) - (br_table $l2 $l2 $l1 (table.get 0 (i32.const 0)) (local.get 0)) - ) - ) - ) - (func (export "meet-funcref-3") (param i32) (result anyref) - (block $l1 (result anyref) - (block $l2 (result funcref) - (br_table $l2 $l1 $l2 (table.get 0 (i32.const 0)) (local.get 0)) - ) - ) - ) - (func (export "meet-funcref-4") (param i32) (result anyref) - (block $l1 (result anyref) - (block $l2 (result funcref) - (br_table $l1 $l2 $l1 (table.get 0 (i32.const 0)) (local.get 0)) - ) - ) - ) - - (func (export "meet-nullref") (param i32) (result funcref) - (block $l1 (result funcref) - (block $l2 (result nullref) - (br_table $l1 $l2 $l1 (ref.null) (local.get 0)) - ) - ) - ) - - (func (export "meet-multi-ref") (param i32) (result anyref) - (block $l1 (result anyref) - (block $l2 (result funcref) - (block $l3 (result nullref) - (br_table $l3 $l2 $l1 (ref.null) (local.get 0)) - ) - ) - ) - ) - - (func (export "meet-bottom") - (block (result f64) - (block (result f32) - (unreachable) - (br_table 0 1 1 (i32.const 1)) - ) - (drop) - (f64.const 0) - ) - (drop) - ) ) (assert_return (invoke "type-i32")) @@ -1492,22 +1433,9 @@ (assert_return (invoke "nested-br_table-loop-block" (i32.const 1)) (i32.const 3)) -(assert_return (invoke "meet-anyref" (i32.const 0) (ref.host 1)) (ref.host 1)) -(assert_return (invoke "meet-anyref" (i32.const 1) (ref.host 1)) (ref.host 1)) -(assert_return (invoke "meet-anyref" (i32.const 2) (ref.host 1)) (ref.host 1)) - -(assert_return (invoke "meet-funcref-1" (i32.const 0)) (ref.func)) -(assert_return (invoke "meet-funcref-1" (i32.const 1)) (ref.func)) -(assert_return (invoke "meet-funcref-1" (i32.const 2)) (ref.func)) -(assert_return (invoke "meet-funcref-2" (i32.const 0)) (ref.func)) -(assert_return (invoke "meet-funcref-2" (i32.const 1)) (ref.func)) -(assert_return (invoke "meet-funcref-2" (i32.const 2)) (ref.func)) -(assert_return (invoke "meet-funcref-3" (i32.const 0)) (ref.func)) -(assert_return (invoke "meet-funcref-3" (i32.const 1)) (ref.func)) -(assert_return (invoke "meet-funcref-3" (i32.const 2)) (ref.func)) -(assert_return (invoke "meet-funcref-4" (i32.const 0)) (ref.func)) -(assert_return (invoke "meet-funcref-4" (i32.const 1)) (ref.func)) -(assert_return (invoke "meet-funcref-4" (i32.const 2)) (ref.func)) +(assert_return (invoke "meet-externref" (i32.const 0) (ref.extern 1)) (ref.extern 1)) +(assert_return (invoke "meet-externref" (i32.const 1) (ref.extern 1)) (ref.extern 1)) +(assert_return (invoke "meet-externref" (i32.const 2) (ref.extern 1)) (ref.extern 1)) (assert_invalid (module (func $type-arg-void-vs-num (result i32) @@ -1636,15 +1564,16 @@ "type mismatch" ) + (assert_invalid - (module (func $meet-bottom (param i32) (result anyref) - (block $l1 (result anyref) + (module (func $meet-bottom (param i32) (result externref) + (block $l1 (result externref) (drop (block $l2 (result i32) - (br_table $l2 $l1 $l2 (ref.null) (local.get 0)) + (br_table $l2 $l1 $l2 (ref.null extern) (local.get 0)) ) ) - (ref.null) + (ref.null extern) ) )) "type mismatch" diff --git a/test/core/bulk.wast b/test/core/bulk.wast index fe71939d3b..1927461fc8 100644 --- a/test/core/bulk.wast +++ b/test/core/bulk.wast @@ -5,7 +5,7 @@ (module (table 3 funcref) - (elem funcref (ref.func 0) (ref.null) (ref.func 1)) + (elem funcref (ref.func 0) (ref.null func) (ref.func 1)) (func) (func)) diff --git a/test/core/elem.wast b/test/core/elem.wast index 6661c9a89f..d0537aa2b0 100644 --- a/test/core/elem.wast +++ b/test/core/elem.wast @@ -8,18 +8,18 @@ ;; Passive (elem funcref) - (elem funcref (ref.func $f) (item ref.func $f) (item (ref.null)) (ref.func $g)) + (elem funcref (ref.func $f) (item ref.func $f) (item (ref.null func)) (ref.func $g)) (elem func) (elem func $f $f $g $g) (elem $p1 funcref) - (elem $p2 funcref (ref.func $f) (ref.func $f) (ref.null) (ref.func $g)) + (elem $p2 funcref (ref.func $f) (ref.func $f) (ref.null func) (ref.func $g)) (elem $p3 func) (elem $p4 func $f $f $g $g) ;; Active (elem (table $t) (i32.const 0) funcref) - (elem (table $t) (i32.const 0) funcref (ref.func $f) (ref.null)) + (elem (table $t) (i32.const 0) funcref (ref.func $f) (ref.null func)) (elem (table $t) (i32.const 0) func) (elem (table $t) (i32.const 0) func $f $g) (elem (table $t) (offset (i32.const 0)) funcref) @@ -33,16 +33,16 @@ (elem (table $t) (offset (i32.const 0)) func) (elem (table $t) (offset (i32.const 0)) func $f $f) (elem (offset (i32.const 0))) - (elem (offset (i32.const 0)) funcref (ref.func $f) (ref.null)) + (elem (offset (i32.const 0)) funcref (ref.func $f) (ref.null func)) (elem (offset (i32.const 0)) func $f $f) (elem (offset (i32.const 0)) $f $f) (elem (i32.const 0)) - (elem (i32.const 0) funcref (ref.func $f) (ref.null)) + (elem (i32.const 0) funcref (ref.func $f) (ref.null func)) (elem (i32.const 0) func $f $f) (elem (i32.const 0) $f $f) (elem $a1 (table $t) (i32.const 0) funcref) - (elem $a2 (table $t) (i32.const 0) funcref (ref.func $f) (ref.null)) + (elem $a2 (table $t) (i32.const 0) funcref (ref.func $f) (ref.null func)) (elem $a3 (table $t) (i32.const 0) func) (elem $a4 (table $t) (i32.const 0) func $f $g) (elem $a9 (table $t) (offset (i32.const 0)) funcref) @@ -56,22 +56,22 @@ (elem $a17 (table $t) (offset (i32.const 0)) func) (elem $a18 (table $t) (offset (i32.const 0)) func $f $f) (elem $a19 (offset (i32.const 0))) - (elem $a20 (offset (i32.const 0)) funcref (ref.func $f) (ref.null)) + (elem $a20 (offset (i32.const 0)) funcref (ref.func $f) (ref.null func)) (elem $a21 (offset (i32.const 0)) func $f $f) (elem $a22 (offset (i32.const 0)) $f $f) (elem $a23 (i32.const 0)) - (elem $a24 (i32.const 0) funcref (ref.func $f) (ref.null)) + (elem $a24 (i32.const 0) funcref (ref.func $f) (ref.null func)) (elem $a25 (i32.const 0) func $f $f) (elem $a26 (i32.const 0) $f $f) ;; Declarative (elem declare funcref) - (elem declare funcref (ref.func $f) (ref.func $f) (ref.null) (ref.func $g)) + (elem declare funcref (ref.func $f) (ref.func $f) (ref.null func) (ref.func $g)) (elem declare func) (elem declare func $f $f $g $g) (elem $d1 declare funcref) - (elem $d2 declare funcref (ref.func $f) (ref.func $f) (ref.null) (ref.func $g)) + (elem $d2 declare funcref (ref.func $f) (ref.func $f) (ref.null func) (ref.func $g)) (elem $d3 declare func) (elem $d4 declare func $f $f $g $g) ) @@ -80,7 +80,7 @@ (func $f) (func $g) - (table $t funcref (elem (ref.func $f) (ref.null) (ref.func $g))) + (table $t funcref (elem (ref.func $f) (ref.null func) (ref.func $g))) ) diff --git a/test/core/global.wast b/test/core/global.wast index 1326679e31..a19ae5e739 100644 --- a/test/core/global.wast +++ b/test/core/global.wast @@ -11,12 +11,12 @@ (global (;6;) (mut f64) (f64.const -14)) (global $y (mut i64) (i64.const -15)) - (global $r anyref (ref.null)) - (global funcref (ref.null)) + (global $r externref (ref.null extern)) + (global funcref (ref.null func)) (func (export "get-a") (result i32) (global.get $a)) (func (export "get-b") (result i64) (global.get $b)) - (func (export "get-r") (result anyref) (global.get $r)) + (func (export "get-r") (result externref) (global.get $r)) (func (export "get-x") (result i32) (global.get $x)) (func (export "get-y") (result i64) (global.get $y)) (func (export "set-x") (param i32) (global.set $x (local.get 0))) @@ -184,7 +184,7 @@ (assert_return (invoke "get-a") (i32.const -2)) (assert_return (invoke "get-b") (i64.const -5)) -(assert_return (invoke "get-r") (ref.null)) +(assert_return (invoke "get-r") (ref.null extern)) (assert_return (invoke "get-x") (i32.const -12)) (assert_return (invoke "get-y") (i64.const -15)) @@ -294,7 +294,7 @@ ) (assert_invalid - (module (global (import "" "") anyref) (global funcref (global.get 0))) + (module (global (import "" "") externref) (global funcref (global.get 0))) "type mismatch" ) diff --git a/test/core/linking.wast b/test/core/linking.wast index 49d55723db..ed551cb3d8 100644 --- a/test/core/linking.wast +++ b/test/core/linking.wast @@ -94,64 +94,37 @@ (module $Mref_ex - (global (export "g-const-null") nullref (ref.null)) - (global (export "g-var-null") (mut nullref) (ref.null)) - (global (export "g-const-func") funcref (ref.null)) - (global (export "g-var-func") (mut funcref) (ref.null)) - (global (export "g-const-any") anyref (ref.null)) - (global (export "g-var-any") (mut anyref) (ref.null)) + (global (export "g-const-func") funcref (ref.null func)) + (global (export "g-var-func") (mut funcref) (ref.null func)) + (global (export "g-const-extern") externref (ref.null extern)) + (global (export "g-var-extern") (mut externref) (ref.null extern)) ) (register "Mref_ex" $Mref_ex) (module $Mref_im - (global (import "Mref_ex" "g-const-null") nullref) - (global (import "Mref_ex" "g-const-null") funcref) - (global (import "Mref_ex" "g-const-null") anyref) (global (import "Mref_ex" "g-const-func") funcref) - (global (import "Mref_ex" "g-const-func") anyref) - (global (import "Mref_ex" "g-const-any") anyref) + (global (import "Mref_ex" "g-const-extern") externref) - (global (import "Mref_ex" "g-var-null") (mut nullref)) (global (import "Mref_ex" "g-var-func") (mut funcref)) - (global (import "Mref_ex" "g-var-any") (mut anyref)) + (global (import "Mref_ex" "g-var-extern") (mut externref)) ) (assert_unlinkable - (module (global (import "Mref_ex" "g-const-func") nullref)) + (module (global (import "Mref_ex" "g-const-extern") funcref)) "incompatible import type" ) (assert_unlinkable - (module (global (import "Mref_ex" "g-const-any") nullref)) - "incompatible import type" -) -(assert_unlinkable - (module (global (import "Mref_ex" "g-const-any") funcref)) + (module (global (import "Mref_ex" "g-const-func") externref)) "incompatible import type" ) (assert_unlinkable - (module (global (import "Mref_ex" "g-var-null") (mut funcref))) - "incompatible import type" -) -(assert_unlinkable - (module (global (import "Mref_ex" "g-var-null") (mut anyref))) - "incompatible import type" -) -(assert_unlinkable - (module (global (import "Mref_ex" "g-var-func") (mut nullref))) + (module (global (import "Mref_ex" "g-var-func") (mut externref))) "incompatible import type" ) (assert_unlinkable - (module (global (import "Mref_ex" "g-var-func") (mut anyref))) - "incompatible import type" -) -(assert_unlinkable - (module (global (import "Mref_ex" "g-var-any") (mut nullref))) - "incompatible import type" -) -(assert_unlinkable - (module (global (import "Mref_ex" "g-var-any") (mut funcref))) + (module (global (import "Mref_ex" "g-var-extern") (mut funcref))) "incompatible import type" ) @@ -315,40 +288,22 @@ (module $Mtable_ex - (table $t1 (export "t-null") 1 nullref) - (table $t2 (export "t-func") 1 funcref) - (table $t3 (export "t-any") 1 anyref) + (table $t1 (export "t-func") 1 funcref) + (table $t2 (export "t-extern") 1 externref) ) (register "Mtable_ex" $Mtable_ex) (module - (table (import "Mtable_ex" "t-null") 1 nullref) (table (import "Mtable_ex" "t-func") 1 funcref) - (table (import "Mtable_ex" "t-any") 1 anyref) + (table (import "Mtable_ex" "t-extern") 1 externref) ) (assert_unlinkable - (module (table (import "Mtable_ex" "t-null") 1 funcref)) - "incompatible import type" -) -(assert_unlinkable - (module (table (import "Mtable_ex" "t-null") 1 anyref)) - "incompatible import type" -) -(assert_unlinkable - (module (table (import "Mtable_ex" "t-func") 1 nullref)) - "incompatible import type" -) -(assert_unlinkable - (module (table (import "Mtable_ex" "t-func") 1 anyref)) - "incompatible import type" -) -(assert_unlinkable - (module (table (import "Mtable_ex" "t-any") 1 nullref)) + (module (table (import "Mtable_ex" "t-func") 1 externref)) "incompatible import type" ) (assert_unlinkable - (module (table (import "Mtable_ex" "t-any") 1 funcref)) + (module (table (import "Mtable_ex" "t-extern") 1 funcref)) "incompatible import type" ) diff --git a/test/core/ref_func.wast b/test/core/ref_func.wast index e9033a3b04..436b386642 100644 --- a/test/core/ref_func.wast +++ b/test/core/ref_func.wast @@ -9,8 +9,6 @@ (i32.add (local.get $x) (i32.const 1)) ) - (global anyref (ref.func $f)) - (global anyref (ref.func $g)) (global funcref (ref.func $f)) (global funcref (ref.func $g)) (global $v (mut funcref) (ref.func $f)) @@ -26,13 +24,13 @@ (func $ff2) (func (export "is_null-f") (result i32) - (ref.is_null (ref.func $f)) + (ref.is_null func (ref.func $f)) ) (func (export "is_null-g") (result i32) - (ref.is_null (ref.func $g)) + (ref.is_null func (ref.func $g)) ) (func (export "is_null-v") (result i32) - (ref.is_null (global.get $v)) + (ref.is_null func (global.get $v)) ) (func (export "set-f") (global.set $v (ref.func $f))) diff --git a/test/core/ref_is_null.wast b/test/core/ref_is_null.wast index 7a42ca7d5d..7c01bb5410 100644 --- a/test/core/ref_is_null.wast +++ b/test/core/ref_is_null.wast @@ -1,62 +1,49 @@ (module - (func $f1 (export "nullref") (param $x nullref) (result i32) - (ref.is_null (local.get $x)) + (func $f1 (export "funcref") (param $x funcref) (result i32) + (ref.is_null func (local.get $x)) ) - (func $f2 (export "anyref") (param $x anyref) (result i32) - (ref.is_null (local.get $x)) - ) - (func $f3 (export "funcref") (param $x funcref) (result i32) - (ref.is_null (local.get $x)) + (func $f2 (export "externref") (param $x externref) (result i32) + (ref.is_null extern (local.get $x)) ) - (table $t1 2 nullref) - (table $t2 2 anyref) - (table $t3 2 funcref) - (elem (table $t3) (i32.const 1) func $dummy) + (table $t1 2 funcref) + (table $t2 2 externref) + (elem (table $t1) (i32.const 1) func $dummy) (func $dummy) - (func (export "init") (param $r anyref) + (func (export "init") (param $r externref) (table.set $t2 (i32.const 1) (local.get $r)) ) (func (export "deinit") - (table.set $t1 (i32.const 1) (ref.null)) - (table.set $t2 (i32.const 1) (ref.null)) - (table.set $t3 (i32.const 1) (ref.null)) + (table.set $t1 (i32.const 1) (ref.null func)) + (table.set $t2 (i32.const 1) (ref.null extern)) ) - (func (export "nullref-elem") (param $x i32) (result i32) + (func (export "funcref-elem") (param $x i32) (result i32) (call $f1 (table.get $t1 (local.get $x))) ) - (func (export "anyref-elem") (param $x i32) (result i32) + (func (export "externref-elem") (param $x i32) (result i32) (call $f2 (table.get $t2 (local.get $x))) ) - (func (export "funcref-elem") (param $x i32) (result i32) - (call $f3 (table.get $t3 (local.get $x))) - ) ) -(assert_return (invoke "nullref" (ref.null)) (i32.const 1)) -(assert_return (invoke "anyref" (ref.null)) (i32.const 1)) -(assert_return (invoke "funcref" (ref.null)) (i32.const 1)) +(assert_return (invoke "funcref" (ref.null func)) (i32.const 1)) +(assert_return (invoke "externref" (ref.null extern)) (i32.const 1)) -(assert_return (invoke "anyref" (ref.host 1)) (i32.const 0)) +(assert_return (invoke "externref" (ref.extern 1)) (i32.const 0)) -(invoke "init" (ref.host 0)) +(invoke "init" (ref.extern 0)) -(assert_return (invoke "nullref-elem" (i32.const 0)) (i32.const 1)) -(assert_return (invoke "anyref-elem" (i32.const 0)) (i32.const 1)) (assert_return (invoke "funcref-elem" (i32.const 0)) (i32.const 1)) +(assert_return (invoke "externref-elem" (i32.const 0)) (i32.const 1)) -(assert_return (invoke "nullref-elem" (i32.const 1)) (i32.const 1)) -(assert_return (invoke "anyref-elem" (i32.const 1)) (i32.const 0)) (assert_return (invoke "funcref-elem" (i32.const 1)) (i32.const 0)) +(assert_return (invoke "externref-elem" (i32.const 1)) (i32.const 0)) (invoke "deinit") -(assert_return (invoke "nullref-elem" (i32.const 0)) (i32.const 1)) -(assert_return (invoke "anyref-elem" (i32.const 0)) (i32.const 1)) (assert_return (invoke "funcref-elem" (i32.const 0)) (i32.const 1)) +(assert_return (invoke "externref-elem" (i32.const 0)) (i32.const 1)) -(assert_return (invoke "nullref-elem" (i32.const 0)) (i32.const 1)) -(assert_return (invoke "anyref-elem" (i32.const 1)) (i32.const 1)) (assert_return (invoke "funcref-elem" (i32.const 1)) (i32.const 1)) +(assert_return (invoke "externref-elem" (i32.const 1)) (i32.const 1)) diff --git a/test/core/ref_null.wast b/test/core/ref_null.wast index 96cac314ad..b88b0888fd 100644 --- a/test/core/ref_null.wast +++ b/test/core/ref_null.wast @@ -1,13 +1,10 @@ (module - (func (export "anyref") (result anyref) (ref.null)) - (func (export "funcref") (result funcref) (ref.null)) - (func (export "nullref") (result nullref) (ref.null)) + (func (export "externref") (result externref) (ref.null extern)) + (func (export "funcref") (result funcref) (ref.null func)) - (global anyref (ref.null)) - (global funcref (ref.null)) - (global nullref (ref.null)) + (global externref (ref.null extern)) + (global funcref (ref.null func)) ) -(assert_return (invoke "anyref") (ref.null)) -(assert_return (invoke "funcref") (ref.null)) -(assert_return (invoke "nullref") (ref.null)) +(assert_return (invoke "externref") (ref.null extern)) +(assert_return (invoke "funcref") (ref.null func)) diff --git a/test/core/select.wast b/test/core/select.wast index 267dd57389..61edfd9ee5 100644 --- a/test/core/select.wast +++ b/test/core/select.wast @@ -29,32 +29,11 @@ (func (export "select-f64-t") (param f64 f64 i32) (result f64) (select (result f64) (local.get 0) (local.get 1) (local.get 2)) ) - (func (export "select-nullref") (param nullref nullref i32) (result nullref) - (select (result nullref) (local.get 0) (local.get 1) (local.get 2)) - ) (func (export "select-funcref") (param funcref funcref i32) (result funcref) (select (result funcref) (local.get 0) (local.get 1) (local.get 2)) ) - (func (export "select-anyref") (param anyref anyref i32) (result anyref) - (select (result anyref) (local.get 0) (local.get 1) (local.get 2)) - ) - - (func (export "join-nullref") (param i32) (result anyref) - (select (result nullref) (ref.null) (ref.null) (local.get 0)) - ) - (func (export "join-funcref") (param i32) (result anyref) - (select (result funcref) - (table.get $tab (i32.const 0)) - (ref.null) - (local.get 0) - ) - ) - (func (export "join-anyref") (param i32) (param anyref) (result anyref) - (select (result anyref) - (table.get $tab (i32.const 0)) - (local.get 1) - (local.get 0) - ) + (func (export "select-externref") (param externref externref i32) (result externref) + (select (result externref) (local.get 0) (local.get 1) (local.get 2)) ) ;; Check that both sides of the select are evaluated @@ -250,16 +229,15 @@ (assert_return (invoke "select-i64-t" (i64.const 2) (i64.const 1) (i32.const 1)) (i64.const 2)) (assert_return (invoke "select-f32-t" (f32.const 1) (f32.const 2) (i32.const 1)) (f32.const 1)) (assert_return (invoke "select-f64-t" (f64.const 1) (f64.const 2) (i32.const 1)) (f64.const 1)) -(assert_return (invoke "select-nullref" (ref.null) (ref.null) (i32.const 1)) (ref.null)) -(assert_return (invoke "select-funcref" (ref.null) (ref.null) (i32.const 1)) (ref.null)) -(assert_return (invoke "select-anyref" (ref.host 1) (ref.host 2) (i32.const 1)) (ref.host 1)) +(assert_return (invoke "select-funcref" (ref.null func) (ref.null func) (i32.const 1)) (ref.null func)) +(assert_return (invoke "select-externref" (ref.extern 1) (ref.extern 2) (i32.const 1)) (ref.extern 1)) (assert_return (invoke "select-i32-t" (i32.const 1) (i32.const 2) (i32.const 0)) (i32.const 2)) (assert_return (invoke "select-i32-t" (i32.const 2) (i32.const 1) (i32.const 0)) (i32.const 1)) (assert_return (invoke "select-i64-t" (i64.const 2) (i64.const 1) (i32.const -1)) (i64.const 2)) (assert_return (invoke "select-i64-t" (i64.const 2) (i64.const 1) (i32.const 0xf0f0f0f0)) (i64.const 2)) -(assert_return (invoke "select-anyref" (ref.host 1) (ref.host 2) (i32.const 0)) (ref.host 2)) -(assert_return (invoke "select-anyref" (ref.host 2) (ref.host 1) (i32.const 0)) (ref.host 1)) +(assert_return (invoke "select-externref" (ref.extern 1) (ref.extern 2) (i32.const 0)) (ref.extern 2)) +(assert_return (invoke "select-externref" (ref.extern 2) (ref.extern 1) (i32.const 0)) (ref.extern 1)) (assert_return (invoke "select-f32-t" (f32.const nan) (f32.const 1) (i32.const 1)) (f32.const nan)) (assert_return (invoke "select-f32-t" (f32.const nan:0x20304) (f32.const 1) (i32.const 1)) (f32.const nan:0x20304)) @@ -279,15 +257,6 @@ (assert_return (invoke "select-f64-t" (f64.const 2) (f64.const nan) (i32.const 0)) (f64.const nan)) (assert_return (invoke "select-f64-t" (f64.const 2) (f64.const nan:0x20304) (i32.const 0)) (f64.const nan:0x20304)) -(assert_return (invoke "join-nullref" (i32.const 1)) (ref.null)) -(assert_return (invoke "join-nullref" (i32.const 0)) (ref.null)) - -(assert_return (invoke "join-funcref" (i32.const 1)) (ref.func)) -(assert_return (invoke "join-funcref" (i32.const 0)) (ref.null)) - -(assert_return (invoke "join-anyref" (i32.const 1) (ref.host 1)) (ref.func)) -(assert_return (invoke "join-anyref" (i32.const 0) (ref.host 1)) (ref.host 1)) - (assert_trap (invoke "select-trap-left" (i32.const 1)) "unreachable") (assert_trap (invoke "select-trap-left" (i32.const 0)) "unreachable") (assert_trap (invoke "select-trap-right" (i32.const 1)) "unreachable") @@ -390,13 +359,7 @@ (assert_invalid - (module (func $type-nullref-implicit - (drop (select (ref.null) (ref.null) (i32.const 1))) - )) - "type mismatch" -) -(assert_invalid - (module (func $type-anyref-implicit (param $r anyref) + (module (func $type-externref-implicit (param $r externref) (drop (select (local.get $r) (local.get $r) (i32.const 1))) )) "type mismatch" diff --git a/test/core/table-sub.wast b/test/core/table-sub.wast index 66f183108b..08787bddd2 100644 --- a/test/core/table-sub.wast +++ b/test/core/table-sub.wast @@ -1,17 +1,7 @@ -(module - (table $t1 10 anyref) - (table $t2 10 funcref) - (elem $el funcref) - (func $f - (table.init $t1 $el (i32.const 0) (i32.const 1) (i32.const 2)) - (table.copy $t1 $t2 (i32.const 0) (i32.const 1) (i32.const 2)) - ) -) - (assert_invalid (module (table $t1 10 funcref) - (table $t2 10 anyref) + (table $t2 10 externref) (func $f (table.copy $t1 $t2 (i32.const 0) (i32.const 1) (i32.const 2)) ) @@ -22,7 +12,7 @@ (assert_invalid (module (table $t 10 funcref) - (elem $el anyref) + (elem $el externref) (func $f (table.init $t $el (i32.const 0) (i32.const 1) (i32.const 2)) ) diff --git a/test/core/table_fill.wast b/test/core/table_fill.wast index 7aff20246c..29c556db94 100644 --- a/test/core/table_fill.wast +++ b/test/core/table_fill.wast @@ -1,66 +1,66 @@ (module - (table $t 10 anyref) + (table $t 10 externref) - (func (export "fill") (param $i i32) (param $r anyref) (param $n i32) + (func (export "fill") (param $i i32) (param $r externref) (param $n i32) (table.fill $t (local.get $i) (local.get $r) (local.get $n)) ) - (func (export "get") (param $i i32) (result anyref) + (func (export "get") (param $i i32) (result externref) (table.get $t (local.get $i)) ) ) -(assert_return (invoke "get" (i32.const 1)) (ref.null)) -(assert_return (invoke "get" (i32.const 2)) (ref.null)) -(assert_return (invoke "get" (i32.const 3)) (ref.null)) -(assert_return (invoke "get" (i32.const 4)) (ref.null)) -(assert_return (invoke "get" (i32.const 5)) (ref.null)) - -(assert_return (invoke "fill" (i32.const 2) (ref.host 1) (i32.const 3))) -(assert_return (invoke "get" (i32.const 1)) (ref.null)) -(assert_return (invoke "get" (i32.const 2)) (ref.host 1)) -(assert_return (invoke "get" (i32.const 3)) (ref.host 1)) -(assert_return (invoke "get" (i32.const 4)) (ref.host 1)) -(assert_return (invoke "get" (i32.const 5)) (ref.null)) - -(assert_return (invoke "fill" (i32.const 4) (ref.host 2) (i32.const 2))) -(assert_return (invoke "get" (i32.const 3)) (ref.host 1)) -(assert_return (invoke "get" (i32.const 4)) (ref.host 2)) -(assert_return (invoke "get" (i32.const 5)) (ref.host 2)) -(assert_return (invoke "get" (i32.const 6)) (ref.null)) - -(assert_return (invoke "fill" (i32.const 4) (ref.host 3) (i32.const 0))) -(assert_return (invoke "get" (i32.const 3)) (ref.host 1)) -(assert_return (invoke "get" (i32.const 4)) (ref.host 2)) -(assert_return (invoke "get" (i32.const 5)) (ref.host 2)) - -(assert_return (invoke "fill" (i32.const 8) (ref.host 4) (i32.const 2))) -(assert_return (invoke "get" (i32.const 7)) (ref.null)) -(assert_return (invoke "get" (i32.const 8)) (ref.host 4)) -(assert_return (invoke "get" (i32.const 9)) (ref.host 4)) - -(assert_return (invoke "fill" (i32.const 9) (ref.null) (i32.const 1))) -(assert_return (invoke "get" (i32.const 8)) (ref.host 4)) -(assert_return (invoke "get" (i32.const 9)) (ref.null)) - -(assert_return (invoke "fill" (i32.const 10) (ref.host 5) (i32.const 0))) -(assert_return (invoke "get" (i32.const 9)) (ref.null)) +(assert_return (invoke "get" (i32.const 1)) (ref.null extern)) +(assert_return (invoke "get" (i32.const 2)) (ref.null extern)) +(assert_return (invoke "get" (i32.const 3)) (ref.null extern)) +(assert_return (invoke "get" (i32.const 4)) (ref.null extern)) +(assert_return (invoke "get" (i32.const 5)) (ref.null extern)) + +(assert_return (invoke "fill" (i32.const 2) (ref.extern 1) (i32.const 3))) +(assert_return (invoke "get" (i32.const 1)) (ref.null extern)) +(assert_return (invoke "get" (i32.const 2)) (ref.extern 1)) +(assert_return (invoke "get" (i32.const 3)) (ref.extern 1)) +(assert_return (invoke "get" (i32.const 4)) (ref.extern 1)) +(assert_return (invoke "get" (i32.const 5)) (ref.null extern)) + +(assert_return (invoke "fill" (i32.const 4) (ref.extern 2) (i32.const 2))) +(assert_return (invoke "get" (i32.const 3)) (ref.extern 1)) +(assert_return (invoke "get" (i32.const 4)) (ref.extern 2)) +(assert_return (invoke "get" (i32.const 5)) (ref.extern 2)) +(assert_return (invoke "get" (i32.const 6)) (ref.null extern)) + +(assert_return (invoke "fill" (i32.const 4) (ref.extern 3) (i32.const 0))) +(assert_return (invoke "get" (i32.const 3)) (ref.extern 1)) +(assert_return (invoke "get" (i32.const 4)) (ref.extern 2)) +(assert_return (invoke "get" (i32.const 5)) (ref.extern 2)) + +(assert_return (invoke "fill" (i32.const 8) (ref.extern 4) (i32.const 2))) +(assert_return (invoke "get" (i32.const 7)) (ref.null extern)) +(assert_return (invoke "get" (i32.const 8)) (ref.extern 4)) +(assert_return (invoke "get" (i32.const 9)) (ref.extern 4)) + +(assert_return (invoke "fill" (i32.const 9) (ref.null extern) (i32.const 1))) +(assert_return (invoke "get" (i32.const 8)) (ref.extern 4)) +(assert_return (invoke "get" (i32.const 9)) (ref.null extern)) + +(assert_return (invoke "fill" (i32.const 10) (ref.extern 5) (i32.const 0))) +(assert_return (invoke "get" (i32.const 9)) (ref.null extern)) (assert_trap - (invoke "fill" (i32.const 8) (ref.host 6) (i32.const 3)) + (invoke "fill" (i32.const 8) (ref.extern 6) (i32.const 3)) "out of bounds" ) -(assert_return (invoke "get" (i32.const 7)) (ref.null)) -(assert_return (invoke "get" (i32.const 8)) (ref.host 4)) -(assert_return (invoke "get" (i32.const 9)) (ref.null)) +(assert_return (invoke "get" (i32.const 7)) (ref.null extern)) +(assert_return (invoke "get" (i32.const 8)) (ref.extern 4)) +(assert_return (invoke "get" (i32.const 9)) (ref.null extern)) (assert_trap - (invoke "fill" (i32.const 11) (ref.null) (i32.const 0)) + (invoke "fill" (i32.const 11) (ref.null extern) (i32.const 0)) "out of bounds" ) (assert_trap - (invoke "fill" (i32.const 11) (ref.null) (i32.const 10)) + (invoke "fill" (i32.const 11) (ref.null extern) (i32.const 10)) "out of bounds" ) @@ -69,7 +69,7 @@ (assert_invalid (module - (table $t 10 anyref) + (table $t 10 externref) (func $type-index-value-length-empty-vs-i32-i32 (table.fill $t) ) @@ -78,16 +78,16 @@ ) (assert_invalid (module - (table $t 10 anyref) + (table $t 10 externref) (func $type-index-empty-vs-i32 - (table.fill $t (ref.null) (i32.const 1)) + (table.fill $t (ref.null extern) (i32.const 1)) ) ) "type mismatch" ) (assert_invalid (module - (table $t 10 anyref) + (table $t 10 externref) (func $type-value-empty-vs (table.fill $t (i32.const 1) (i32.const 1)) ) @@ -96,18 +96,18 @@ ) (assert_invalid (module - (table $t 10 anyref) + (table $t 10 externref) (func $type-length-empty-vs-i32 - (table.fill $t (i32.const 1) (ref.null)) + (table.fill $t (i32.const 1) (ref.null extern)) ) ) "type mismatch" ) (assert_invalid (module - (table $t 0 anyref) + (table $t 0 externref) (func $type-index-f32-vs-i32 - (table.fill $t (f32.const 1) (ref.null) (i32.const 1)) + (table.fill $t (f32.const 1) (ref.null extern) (i32.const 1)) ) ) "type mismatch" @@ -115,7 +115,7 @@ (assert_invalid (module (table $t 0 funcref) - (func $type-value-vs-funcref (param $r anyref) + (func $type-value-vs-funcref (param $r externref) (table.fill $t (i32.const 1) (local.get $r) (i32.const 1)) ) ) @@ -123,9 +123,9 @@ ) (assert_invalid (module - (table $t 0 anyref) + (table $t 0 externref) (func $type-length-f32-vs-i32 - (table.fill $t (i32.const 1) (ref.null) (f32.const 1)) + (table.fill $t (i32.const 1) (ref.null extern) (f32.const 1)) ) ) "type mismatch" @@ -133,9 +133,9 @@ (assert_invalid (module - (table $t1 1 anyref) + (table $t1 1 externref) (table $t2 1 funcref) - (func $type-value-anyref-vs-funcref-multi (param $r anyref) + (func $type-value-externref-vs-funcref-multi (param $r externref) (table.fill $t2 (i32.const 0) (local.get $r) (i32.const 1)) ) ) @@ -144,9 +144,9 @@ (assert_invalid (module - (table $t 1 anyref) + (table $t 1 externref) (func $type-result-empty-vs-num (result i32) - (table.fill $t (i32.const 0) (ref.null) (i32.const 1)) + (table.fill $t (i32.const 0) (ref.null extern) (i32.const 1)) ) ) "type mismatch" diff --git a/test/core/table_get.wast b/test/core/table_get.wast index c95fce7232..3df7190e37 100644 --- a/test/core/table_get.wast +++ b/test/core/table_get.wast @@ -1,15 +1,15 @@ (module - (table $t2 2 anyref) + (table $t2 2 externref) (table $t3 3 funcref) (elem (table $t3) (i32.const 1) func $dummy) (func $dummy) - (func (export "init") (param $r anyref) + (func (export "init") (param $r externref) (table.set $t2 (i32.const 1) (local.get $r)) (table.set $t3 (i32.const 2) (table.get $t3 (i32.const 1))) ) - (func (export "get-anyref") (param $i i32) (result anyref) + (func (export "get-externref") (param $i i32) (result externref) (table.get $t2 (local.get $i)) ) (func $f3 (export "get-funcref") (param $i i32) (result funcref) @@ -17,22 +17,22 @@ ) (func (export "is_null-funcref") (param $i i32) (result i32) - (ref.is_null (call $f3 (local.get $i))) + (ref.is_null func (call $f3 (local.get $i))) ) ) -(invoke "init" (ref.host 1)) +(invoke "init" (ref.extern 1)) -(assert_return (invoke "get-anyref" (i32.const 0)) (ref.null)) -(assert_return (invoke "get-anyref" (i32.const 1)) (ref.host 1)) +(assert_return (invoke "get-externref" (i32.const 0)) (ref.null extern)) +(assert_return (invoke "get-externref" (i32.const 1)) (ref.extern 1)) -(assert_return (invoke "get-funcref" (i32.const 0)) (ref.null)) +(assert_return (invoke "get-funcref" (i32.const 0)) (ref.null func)) (assert_return (invoke "is_null-funcref" (i32.const 1)) (i32.const 0)) (assert_return (invoke "is_null-funcref" (i32.const 2)) (i32.const 0)) -(assert_trap (invoke "get-anyref" (i32.const 2)) "out of bounds") +(assert_trap (invoke "get-externref" (i32.const 2)) "out of bounds") (assert_trap (invoke "get-funcref" (i32.const 3)) "out of bounds") -(assert_trap (invoke "get-anyref" (i32.const -1)) "out of bounds") +(assert_trap (invoke "get-externref" (i32.const -1)) "out of bounds") (assert_trap (invoke "get-funcref" (i32.const -1)) "out of bounds") @@ -40,8 +40,8 @@ (assert_invalid (module - (table $t 10 anyref) - (func $type-index-empty-vs-i32 (result anyref) + (table $t 10 externref) + (func $type-index-empty-vs-i32 (result externref) (table.get $t) ) ) @@ -49,8 +49,8 @@ ) (assert_invalid (module - (table $t 10 anyref) - (func $type-index-f32-vs-i32 (result anyref) + (table $t 10 externref) + (func $type-index-f32-vs-i32 (result externref) (table.get $t (f32.const 1)) ) ) @@ -59,8 +59,8 @@ (assert_invalid (module - (table $t 10 anyref) - (func $type-result-anyref-vs-empty + (table $t 10 externref) + (func $type-result-externref-vs-empty (table.get $t (i32.const 0)) ) ) @@ -68,8 +68,8 @@ ) (assert_invalid (module - (table $t 10 anyref) - (func $type-result-anyref-vs-funcref (result funcref) + (table $t 10 externref) + (func $type-result-externref-vs-funcref (result funcref) (table.get $t (i32.const 1)) ) ) @@ -79,8 +79,8 @@ (assert_invalid (module (table $t1 1 funcref) - (table $t2 1 anyref) - (func $type-result-anyref-vs-funcref-multi (result funcref) + (table $t2 1 externref) + (func $type-result-externref-vs-funcref-multi (result funcref) (table.get $t2 (i32.const 0)) ) ) diff --git a/test/core/table_grow.wast b/test/core/table_grow.wast index 91fc096f45..2b992ff7d7 100644 --- a/test/core/table_grow.wast +++ b/test/core/table_grow.wast @@ -1,43 +1,43 @@ (module - (table $t 0 anyref) + (table $t 0 externref) - (func (export "get") (param $i i32) (result anyref) (table.get $t (local.get $i))) - (func (export "set") (param $i i32) (param $r anyref) (table.set $t (local.get $i) (local.get $r))) + (func (export "get") (param $i i32) (result externref) (table.get $t (local.get $i))) + (func (export "set") (param $i i32) (param $r externref) (table.set $t (local.get $i) (local.get $r))) - (func (export "grow") (param $sz i32) (param $init anyref) (result i32) + (func (export "grow") (param $sz i32) (param $init externref) (result i32) (table.grow $t (local.get $init) (local.get $sz)) ) (func (export "size") (result i32) (table.size $t)) ) (assert_return (invoke "size") (i32.const 0)) -(assert_trap (invoke "set" (i32.const 0) (ref.host 2)) "out of bounds table access") +(assert_trap (invoke "set" (i32.const 0) (ref.extern 2)) "out of bounds table access") (assert_trap (invoke "get" (i32.const 0)) "out of bounds table access") -(assert_return (invoke "grow" (i32.const 1) (ref.null)) (i32.const 0)) +(assert_return (invoke "grow" (i32.const 1) (ref.null extern)) (i32.const 0)) (assert_return (invoke "size") (i32.const 1)) -(assert_return (invoke "get" (i32.const 0)) (ref.null)) -(assert_return (invoke "set" (i32.const 0) (ref.host 2))) -(assert_return (invoke "get" (i32.const 0)) (ref.host 2)) -(assert_trap (invoke "set" (i32.const 1) (ref.host 2)) "out of bounds table access") +(assert_return (invoke "get" (i32.const 0)) (ref.null extern)) +(assert_return (invoke "set" (i32.const 0) (ref.extern 2))) +(assert_return (invoke "get" (i32.const 0)) (ref.extern 2)) +(assert_trap (invoke "set" (i32.const 1) (ref.extern 2)) "out of bounds table access") (assert_trap (invoke "get" (i32.const 1)) "out of bounds table access") -(assert_return (invoke "grow" (i32.const 4) (ref.host 3)) (i32.const 1)) +(assert_return (invoke "grow" (i32.const 4) (ref.extern 3)) (i32.const 1)) (assert_return (invoke "size") (i32.const 5)) -(assert_return (invoke "get" (i32.const 0)) (ref.host 2)) -(assert_return (invoke "set" (i32.const 0) (ref.host 2))) -(assert_return (invoke "get" (i32.const 0)) (ref.host 2)) -(assert_return (invoke "get" (i32.const 1)) (ref.host 3)) -(assert_return (invoke "get" (i32.const 4)) (ref.host 3)) -(assert_return (invoke "set" (i32.const 4) (ref.host 4))) -(assert_return (invoke "get" (i32.const 4)) (ref.host 4)) -(assert_trap (invoke "set" (i32.const 5) (ref.host 2)) "out of bounds table access") +(assert_return (invoke "get" (i32.const 0)) (ref.extern 2)) +(assert_return (invoke "set" (i32.const 0) (ref.extern 2))) +(assert_return (invoke "get" (i32.const 0)) (ref.extern 2)) +(assert_return (invoke "get" (i32.const 1)) (ref.extern 3)) +(assert_return (invoke "get" (i32.const 4)) (ref.extern 3)) +(assert_return (invoke "set" (i32.const 4) (ref.extern 4))) +(assert_return (invoke "get" (i32.const 4)) (ref.extern 4)) +(assert_trap (invoke "set" (i32.const 5) (ref.extern 2)) "out of bounds table access") (assert_trap (invoke "get" (i32.const 5)) "out of bounds table access") ;; Reject growing to size outside i32 value range (module - (table $t 0x10 anyref) + (table $t 0x10 funcref) (elem declare func $f) (func $f (export "grow") (result i32) (table.grow $t (ref.func $f) (i32.const 0xffff_fff0)) @@ -48,9 +48,9 @@ (module - (table $t 0 anyref) + (table $t 0 externref) (func (export "grow") (param i32) (result i32) - (table.grow $t (ref.null) (local.get 0)) + (table.grow $t (ref.null extern) (local.get 0)) ) ) @@ -62,9 +62,9 @@ (module - (table $t 0 10 anyref) + (table $t 0 10 externref) (func (export "grow") (param i32) (result i32) - (table.grow $t (ref.null) (local.get 0)) + (table.grow $t (ref.null extern) (local.get 0)) ) ) @@ -79,18 +79,18 @@ (module - (table $t 10 anyref) + (table $t 10 funcref) (func (export "grow") (param i32) (result i32) - (table.grow $t (ref.null) (local.get 0)) + (table.grow $t (ref.null func) (local.get 0)) ) (elem declare func 1) - (func (export "check-table-null") (param i32 i32) (result anyref) - (local anyref) + (func (export "check-table-null") (param i32 i32) (result funcref) + (local funcref) (local.set 2 (ref.func 1)) (block (loop (local.set 2 (table.get $t (local.get 0))) - (br_if 1 (i32.eqz (ref.is_null (local.get 2)))) + (br_if 1 (i32.eqz (ref.is_null func (local.get 2)))) (br_if 1 (i32.ge_u (local.get 0) (local.get 1))) (local.set 0 (i32.add (local.get 0) (i32.const 1))) (br_if 0 (i32.le_u (local.get 0) (local.get 1))) @@ -100,17 +100,17 @@ ) ) -(assert_return (invoke "check-table-null" (i32.const 0) (i32.const 9)) (ref.null)) +(assert_return (invoke "check-table-null" (i32.const 0) (i32.const 9)) (ref.null func)) (assert_return (invoke "grow" (i32.const 10)) (i32.const 10)) -(assert_return (invoke "check-table-null" (i32.const 0) (i32.const 19)) (ref.null)) +(assert_return (invoke "check-table-null" (i32.const 0) (i32.const 19)) (ref.null func)) ;; Type errors (assert_invalid (module - (table $t 0 anyref) - (func $type-init-size-empty-vs-i32-anyref (result i32) + (table $t 0 externref) + (func $type-init-size-empty-vs-i32-externref (result i32) (table.grow $t) ) ) @@ -118,17 +118,17 @@ ) (assert_invalid (module - (table $t 0 anyref) + (table $t 0 externref) (func $type-size-empty-vs-i32 (result i32) - (table.grow $t (ref.null)) + (table.grow $t (ref.null extern)) ) ) "type mismatch" ) (assert_invalid (module - (table $t 0 anyref) - (func $type-init-empty-vs-anyref (result i32) + (table $t 0 externref) + (func $type-init-empty-vs-externref (result i32) (table.grow $t (i32.const 1)) ) ) @@ -136,9 +136,9 @@ ) (assert_invalid (module - (table $t 0 anyref) + (table $t 0 externref) (func $type-size-f32-vs-i32 (result i32) - (table.grow $t (ref.null) (f32.const 1)) + (table.grow $t (ref.null extern) (f32.const 1)) ) ) "type mismatch" @@ -146,7 +146,7 @@ (assert_invalid (module (table $t 0 funcref) - (func $type-init-anyref-vs-funcref (param $r anyref) (result i32) + (func $type-init-externref-vs-funcref (param $r externref) (result i32) (table.grow $t (local.get $r) (i32.const 1)) ) ) @@ -155,18 +155,18 @@ (assert_invalid (module - (table $t 1 anyref) + (table $t 1 externref) (func $type-result-i32-vs-empty - (table.grow $t (ref.null) (i32.const 0)) + (table.grow $t (ref.null extern) (i32.const 0)) ) ) "type mismatch" ) (assert_invalid (module - (table $t 1 anyref) + (table $t 1 externref) (func $type-result-i32-vs-f32 (result f32) - (table.grow $t (ref.null) (i32.const 0)) + (table.grow $t (ref.null extern) (i32.const 0)) ) ) "type mismatch" diff --git a/test/core/table_set.wast b/test/core/table_set.wast index 848830e2fb..6da9db87d6 100644 --- a/test/core/table_set.wast +++ b/test/core/table_set.wast @@ -1,17 +1,17 @@ (module - (table $t2 1 anyref) + (table $t2 1 externref) (table $t3 2 funcref) (elem (table $t3) (i32.const 1) func $dummy) (func $dummy) - (func (export "get-anyref") (param $i i32) (result anyref) + (func (export "get-externref") (param $i i32) (result externref) (table.get $t2 (local.get $i)) ) (func $f3 (export "get-funcref") (param $i i32) (result funcref) (table.get $t3 (local.get $i)) ) - (func (export "set-anyref") (param $i i32) (param $r anyref) + (func (export "set-externref") (param $i i32) (param $r externref) (table.set $t2 (local.get $i) (local.get $r)) ) (func (export "set-funcref") (param $i i32) (param $r funcref) @@ -22,30 +22,30 @@ ) (func (export "is_null-funcref") (param $i i32) (result i32) - (ref.is_null (call $f3 (local.get $i))) + (ref.is_null func (call $f3 (local.get $i))) ) ) -(assert_return (invoke "get-anyref" (i32.const 0)) (ref.null)) -(assert_return (invoke "set-anyref" (i32.const 0) (ref.host 1))) -(assert_return (invoke "get-anyref" (i32.const 0)) (ref.host 1)) -(assert_return (invoke "set-anyref" (i32.const 0) (ref.null))) -(assert_return (invoke "get-anyref" (i32.const 0)) (ref.null)) +(assert_return (invoke "get-externref" (i32.const 0)) (ref.null extern)) +(assert_return (invoke "set-externref" (i32.const 0) (ref.extern 1))) +(assert_return (invoke "get-externref" (i32.const 0)) (ref.extern 1)) +(assert_return (invoke "set-externref" (i32.const 0) (ref.null extern))) +(assert_return (invoke "get-externref" (i32.const 0)) (ref.null extern)) -(assert_return (invoke "get-funcref" (i32.const 0)) (ref.null)) +(assert_return (invoke "get-funcref" (i32.const 0)) (ref.null func)) (assert_return (invoke "set-funcref-from" (i32.const 0) (i32.const 1))) (assert_return (invoke "is_null-funcref" (i32.const 0)) (i32.const 0)) -(assert_return (invoke "set-funcref" (i32.const 0) (ref.null))) -(assert_return (invoke "get-funcref" (i32.const 0)) (ref.null)) +(assert_return (invoke "set-funcref" (i32.const 0) (ref.null func))) +(assert_return (invoke "get-funcref" (i32.const 0)) (ref.null func)) -(assert_trap (invoke "set-anyref" (i32.const 2) (ref.null)) "out of bounds") -(assert_trap (invoke "set-funcref" (i32.const 3) (ref.null)) "out of bounds") -(assert_trap (invoke "set-anyref" (i32.const -1) (ref.null)) "out of bounds") -(assert_trap (invoke "set-funcref" (i32.const -1) (ref.null)) "out of bounds") +(assert_trap (invoke "set-externref" (i32.const 2) (ref.null extern)) "out of bounds") +(assert_trap (invoke "set-funcref" (i32.const 3) (ref.null func)) "out of bounds") +(assert_trap (invoke "set-externref" (i32.const -1) (ref.null extern)) "out of bounds") +(assert_trap (invoke "set-funcref" (i32.const -1) (ref.null func)) "out of bounds") -(assert_trap (invoke "set-anyref" (i32.const 2) (ref.host 0)) "out of bounds") +(assert_trap (invoke "set-externref" (i32.const 2) (ref.extern 0)) "out of bounds") (assert_trap (invoke "set-funcref-from" (i32.const 3) (i32.const 1)) "out of bounds") -(assert_trap (invoke "set-anyref" (i32.const -1) (ref.host 0)) "out of bounds") +(assert_trap (invoke "set-externref" (i32.const -1) (ref.extern 0)) "out of bounds") (assert_trap (invoke "set-funcref-from" (i32.const -1) (i32.const 1)) "out of bounds") @@ -53,8 +53,8 @@ (assert_invalid (module - (table $t 10 anyref) - (func $type-index-value-empty-vs-i32-anyref + (table $t 10 externref) + (func $type-index-value-empty-vs-i32-externref (table.set $t) ) ) @@ -62,17 +62,17 @@ ) (assert_invalid (module - (table $t 10 anyref) + (table $t 10 externref) (func $type-index-empty-vs-i32 - (table.set $t (ref.null)) + (table.set $t (ref.null extern)) ) ) "type mismatch" ) (assert_invalid (module - (table $t 10 anyref) - (func $type-value-empty-vs-anyref + (table $t 10 externref) + (func $type-value-empty-vs-externref (table.set $t (i32.const 1)) ) ) @@ -80,9 +80,9 @@ ) (assert_invalid (module - (table $t 10 anyref) + (table $t 10 externref) (func $type-size-f32-vs-i32 - (table.set $t (f32.const 1) (ref.null)) + (table.set $t (f32.const 1) (ref.null extern)) ) ) "type mismatch" @@ -90,7 +90,7 @@ (assert_invalid (module (table $t 10 funcref) - (func $type-value-anyref-vs-funcref (param $r anyref) + (func $type-value-externref-vs-funcref (param $r externref) (table.set $t (i32.const 1) (local.get $r)) ) ) @@ -99,9 +99,9 @@ (assert_invalid (module - (table $t1 1 anyref) + (table $t1 1 externref) (table $t2 1 funcref) - (func $type-value-anyref-vs-funcref-multi (param $r anyref) + (func $type-value-externref-vs-funcref-multi (param $r externref) (table.set $t2 (i32.const 0) (local.get $r)) ) ) @@ -110,9 +110,9 @@ (assert_invalid (module - (table $t 10 anyref) + (table $t 10 externref) (func $type-result-empty-vs-num (result i32) - (table.set $t (i32.const 0) (ref.null)) + (table.set $t (i32.const 0) (ref.null extern)) ) ) "type mismatch" diff --git a/test/core/table_size.wast b/test/core/table_size.wast index 5817104a4c..ad293b5ee4 100644 --- a/test/core/table_size.wast +++ b/test/core/table_size.wast @@ -1,8 +1,8 @@ (module - (table $t0 0 anyref) - (table $t1 1 anyref) - (table $t2 0 2 anyref) - (table $t3 3 8 anyref) + (table $t0 0 externref) + (table $t1 1 externref) + (table $t2 0 2 externref) + (table $t3 3 8 externref) (func (export "size-t0") (result i32) (table.size $t0)) (func (export "size-t1") (result i32) (table.size $t1)) @@ -10,16 +10,16 @@ (func (export "size-t3") (result i32) (table.size $t3)) (func (export "grow-t0") (param $sz i32) - (drop (table.grow $t0 (ref.null) (local.get $sz))) + (drop (table.grow $t0 (ref.null extern) (local.get $sz))) ) (func (export "grow-t1") (param $sz i32) - (drop (table.grow $t1 (ref.null) (local.get $sz))) + (drop (table.grow $t1 (ref.null extern) (local.get $sz))) ) (func (export "grow-t2") (param $sz i32) - (drop (table.grow $t2 (ref.null) (local.get $sz))) + (drop (table.grow $t2 (ref.null extern) (local.get $sz))) ) (func (export "grow-t3") (param $sz i32) - (drop (table.grow $t3 (ref.null) (local.get $sz))) + (drop (table.grow $t3 (ref.null extern) (local.get $sz))) ) ) @@ -68,7 +68,7 @@ (assert_invalid (module - (table $t 1 anyref) + (table $t 1 externref) (func $type-result-i32-vs-empty (table.size $t) ) @@ -77,7 +77,7 @@ ) (assert_invalid (module - (table $t 1 anyref) + (table $t 1 externref) (func $type-result-i32-vs-f32 (result f32) (table.size $t) ) From 5567def1677c113d8ec67d0352f3596a5ad32ce7 Mon Sep 17 00:00:00 2001 From: Andreas Rossberg Date: Tue, 12 May 2020 08:47:46 +0200 Subject: [PATCH 159/199] Merge upstream (#89) * Upgrade to latest Sphinx release (2.4.4) (#1171) Fixes #1157 * Support 4GB of memory both in initial and max. * [interpreter] Strictify and specify .bin.wast format (#1173) * Merge nontrapping-float-to-int proposal into spec (#1143) See the non-trapping-float-to-int-conversions proposal here: https://github.com/WebAssembly/nontrapping-float-to-int-conversions * Merge sign-extension-ops proposal into spec (#1144) See the sign-extension-ops proposal here: https://github.com/WebAssembly/sign-extension-ops This PR is built on top of #1143 (merge nontrapping-float-to-int). * Merge multi-value proposal into spec (#1145) See the multi-value proposal here: https://github.com/WebAssembly/multi-value This PR is built on top of the following PRs: * #1143 (merge nontrapping-float-to-int) * #1144 (merge sign-extension-ops) * [interpreter] Remove junk in README * [interpreter] Remove junk in README * [spec] Fix grammar for fractions (#1178) * [spec] Add missing i64.extend32_s syntax (#1179) * [js-api][web-api] Fix some markup errors. * Add a README to the proposals directory. * Add more address overflow tests (#1188) There are already tests for effective address overflow, but those have a large value baked into the offset. These tests all use `1` as the immediate offset, and use `-1` for the address on the stack, which may be compiled differently. * Add a test for non-treelike behavior of stack (#961) We've recently found a bug in a WebAssembly library we've been working with where we're mapping WebAssembly to a tree-like IR internally. The way we parse into this representation, however, has a bug when the function isn't itself tree-like but rather exibits properties that exploit a stack machine. For example this isn't so straightforward to represent in a tree-like fashion: (import "" "a" (func $foo)) (import "" "b" (func $foo (result i32))) (func (result i32) call $b call $b call $a i32.xor) The extra `call $a` in the middle is valid `WebAssembly` but needs special treatment when converting to a more tree-like IR format. I figured it'd be good to ensure there's a spec test covering this case as we currently pass the suite of spec tests but still contain this bug! * [js-api] Various editorial improvements. * [js-api] Replace pseudo-ASCII characters by normal ones. This also required disambiguating the references to "module", as there are now two definitions by that name. * [js-api] Improve prose in 'run a host function'. * [js-api] Improve some of the multi-value prose. * Synchronize js-api tests. * Add script to synchronize js-api tests. Co-authored-by: Ng Zhi An Co-authored-by: Alon Zakai Co-authored-by: Ben Smith Co-authored-by: Ms2ger Co-authored-by: Alex Crichton --- .travis.yml | 2 +- document/core/appendix/algorithm.rst | 57 +- document/core/appendix/implementation.rst | 2 + document/core/appendix/index-instructions.rst | 491 ++++++++------ document/core/appendix/index-rules.rst | 1 + document/core/appendix/properties.rst | 28 +- document/core/binary/instructions.rst | 62 +- document/core/binary/types.rst | 18 +- document/core/conf.py | 2 +- document/core/exec/instructions.rst | 97 ++- document/core/exec/numerics.rst | 69 ++ document/core/exec/runtime.rst | 13 +- document/core/syntax/instructions.rst | 36 +- document/core/syntax/types.rst | 22 +- document/core/text/instructions.rst | 61 +- document/core/text/modules.rst | 2 +- document/core/text/types.rst | 18 +- document/core/text/values.rst | 18 +- document/core/util/macros.def | 23 +- document/core/valid/conventions.rst | 10 +- document/core/valid/instructions.rst | 125 ++-- document/core/valid/modules.rst | 21 +- document/core/valid/types.rst | 51 +- document/index.html | 4 +- document/js-api/index.bs | 210 +++--- document/web-api/index.bs | 2 +- interpreter/Makefile | 2 +- interpreter/README.md | 57 +- interpreter/binary/decode.ml | 51 +- interpreter/binary/encode.ml | 40 +- interpreter/exec/eval.ml | 61 +- interpreter/exec/eval_numeric.ml | 21 +- interpreter/exec/float.ml | 33 +- interpreter/exec/i32.ml | 1 + interpreter/exec/i32_convert.ml | 48 ++ interpreter/exec/i32_convert.mli | 4 + interpreter/exec/i64.ml | 1 + interpreter/exec/i64_convert.ml | 52 ++ interpreter/exec/i64_convert.mli | 4 + interpreter/exec/int.ml | 25 +- interpreter/runtime/memory.ml | 8 - interpreter/runtime/memory.mli | 4 - interpreter/script/js.ml | 61 +- interpreter/script/script.ml | 8 +- interpreter/syntax/ast.ml | 15 +- interpreter/syntax/operators.ml | 21 +- interpreter/syntax/types.ml | 8 + interpreter/text/arrange.ml | 107 +-- interpreter/text/lexer.mll | 11 + interpreter/text/parser.mly | 89 ++- interpreter/util/lib.ml | 6 + interpreter/util/lib.mli | 3 + interpreter/valid/valid.ml | 115 ++-- proposals/README.md | 3 + proposals/multi-value/Overview.md | 196 ++++++ .../Overview.md | 93 +++ proposals/sign-extension-ops/Overview.md | 51 ++ test/core/address.wast | 21 + test/core/binary.wast | 2 +- test/core/block.wast | 377 ++++++++++- test/core/br.wast | 51 ++ test/core/break-drop.wast | 9 - test/core/call.wast | 55 ++ test/core/call_indirect.wast | 49 +- test/core/const.wast | 15 + test/core/conversions.wast | 199 ++++++ test/core/fac.wast | 20 + test/core/func.wast | 268 +++++++- test/core/i32.wast | 18 + test/core/i64.wast | 30 + test/core/if.wast | 639 +++++++++++++++++- test/core/loop.wast | 320 ++++++++- test/core/stack.wast | 19 + test/core/type.wast | 45 +- test/js-api/assertions.js | 22 + test/js-api/bad-imports.js | 23 +- test/js-api/constructor/compile.any.js | 13 +- .../instantiate-bad-imports.any.js | 6 +- test/js-api/constructor/instantiate.any.js | 34 +- test/js-api/constructor/multi-value.any.js | 149 ++++ test/js-api/constructor/validate.any.js | 8 +- .../error-interfaces-no-symbol-tostringtag.js | 13 + test/js-api/global/constructor.any.js | 18 +- test/js-api/global/toString.any.js | 12 +- test/js-api/global/value-get-set.any.js | 41 +- test/js-api/global/valueOf.any.js | 4 +- .../instance/constructor-bad-imports.any.js | 4 +- .../instance/constructor-caching.any.js | 54 ++ test/js-api/instance/constructor.any.js | 10 +- test/js-api/instance/exports.any.js | 6 +- test/js-api/instance/toString.any.js | 12 +- test/js-api/instanceTestFactory.js | 2 +- test/js-api/interface.any.js | 6 +- test/js-api/limits.any.js | 11 +- test/js-api/memory/assertions.js | 38 ++ test/js-api/memory/buffer.any.js | 6 +- test/js-api/memory/constructor.any.js | 39 +- test/js-api/memory/grow.any.js | 60 +- test/js-api/memory/toString.any.js | 12 +- test/js-api/module/constructor.any.js | 17 +- test/js-api/module/customSections.any.js | 44 +- test/js-api/module/exports.any.js | 8 +- test/js-api/module/imports.any.js | 8 +- test/js-api/module/toString.any.js | 12 +- test/js-api/prototypes.any.js | 43 ++ test/js-api/table/assertions.js | 10 +- test/js-api/table/constructor.any.js | 24 +- test/js-api/table/get-set.any.js | 32 +- test/js-api/table/grow.any.js | 12 +- test/js-api/table/length.any.js | 6 +- test/js-api/table/toString.any.js | 12 +- test/js-api/wasm-module-builder.js | 589 +++++++++++++--- test/sync-js-api.py | 54 ++ 113 files changed, 4995 insertions(+), 1260 deletions(-) create mode 100644 proposals/README.md create mode 100644 proposals/multi-value/Overview.md create mode 100644 proposals/nontrapping-float-to-int-conversion/Overview.md create mode 100644 proposals/sign-extension-ops/Overview.md delete mode 100644 test/core/break-drop.wast create mode 100644 test/js-api/constructor/multi-value.any.js create mode 100644 test/js-api/error-interfaces-no-symbol-tostringtag.js create mode 100644 test/js-api/instance/constructor-caching.any.js create mode 100644 test/js-api/memory/assertions.js create mode 100644 test/js-api/prototypes.any.js create mode 100755 test/sync-js-api.py diff --git a/.travis.yml b/.travis.yml index f567be1ba6..96ed4878f1 100644 --- a/.travis.yml +++ b/.travis.yml @@ -15,7 +15,7 @@ addons: - yarn install: - - pip install Sphinx==2.3.0 + - pip install Sphinx==2.4.4 - git clone https://github.com/tabatkins/bikeshed.git - pip install --editable $PWD/bikeshed - bikeshed update diff --git a/document/core/appendix/algorithm.rst b/document/core/appendix/algorithm.rst index 7fd3da33fc..be20a53587 100644 --- a/document/core/appendix/algorithm.rst +++ b/document/core/appendix/algorithm.rst @@ -43,7 +43,8 @@ the latter surrounding :ref:`structured control instructions `, or :code:`Unknown` when the type is not known. -For each entered block, the control stack records a *control frame* with the type of the associated :ref:`label ` (used to type-check branches), the result type of the block (used to check its result), the height of the operand stack at the start of the block (used to check that operands do not underflow the current block), and a flag recording whether the remainder of the block is unreachable (used to handle :ref:`stack-polymorphic ` typing after branches). - -.. note:: - In the presentation of this algorithm, multiple values are supported for the :ref:`result types ` classifying blocks and labels. - With the current version of WebAssembly, the :code:`list` could be simplified to an optional value. +For each entered block, the control stack records a *control frame* with the originating opcode, the types on the top of the operand stack at the start and end of the block (used to check its result as well as branches), the height of the operand stack at the start of the block (used to check that operands do not underflow the current block), and a flag recording whether the remainder of the block is unreachable (used to handle :ref:`stack-polymorphic ` typing after branches). For the purpose of presenting the algorithm, the operand and control stacks are simply maintained as global variables: @@ -112,17 +109,21 @@ The control stack is likewise manipulated through auxiliary functions: .. code-block:: pseudo - func push_ctrl(label : list(val_type), out : list(val_type)) = -  let frame = ctrl_frame(label, out, vals.size(), false) + func push_ctrl(opcode : opcode, in : list(val_type), out : list(val_type)) = +  let frame = ctrl_frame(opcode, in, out, vals.size(), false)   ctrls.push(frame) + push_vals(in) - func pop_ctrl() : list(val_type) = + func pop_ctrl() : ctrl_frame =  error_if(ctrls.is_empty())  let frame = ctrls[0]   pop_vals(frame.end_types)   error_if(vals.size() =/= frame.height) ctrls.pop() -   return frame.end_types +   return frame + + func label_types(frame : ctrl_frame) : list(val_types) = + return (if frame.opcode == loop then frame.start_types else frame.end_types) func unreachable() =   vals.resize(ctrls[0].height) @@ -135,6 +136,8 @@ Popping a frame first checks that the control stack is not empty. It then verifies that the operand stack contains the right types of values expected at the end of the exited block and pops them off the operand stack. Afterwards, it checks that the stack has shrunk back to its initial height. +The type of the :ref:`label ` associated with a control frame is either that of the stack at the start or the end of the frame, determined by the opcode that it originates from. + Finally, the current frame can be marked as unreachable. In that case, all existing operand types are purged from the value stack, in order to allow for the :ref:`stack-polymorphism ` logic in :code:`pop_val` to take effect. @@ -185,41 +188,45 @@ Other instructions are checked in a similar manner.    case (unreachable)       unreachable() - case (block t*) - push_ctrl([t*], [t*]) + case (block t1*->t2*) + pop_vals([t1*]) + push_ctrl(block, [t1*], [t2*]) - case (loop t*) - push_ctrl([], [t*]) + case (loop t1*->t2*) + pop_vals([t1*]) + push_ctrl(loop, [t1*], [t2*]) - case (if t*) + case (if t1*->t2*) pop_val(I32) - push_ctrl([t*], [t*]) + pop_vals([t1*]) + push_ctrl(if, [t1*], [t2*]) case (end) - let results = pop_ctrl() - push_vals(results) + let frame = pop_ctrl() + push_vals(frame.end_types) case (else) - let results = pop_ctrl() - push_ctrl(results, results) + let frame = pop_ctrl() + error_if(frame.opcode =/= if) + push_ctrl(else, frame.start_types, frame.end_types) case (br n)      error_if(ctrls.size() < n) -       pop_vals(ctrls[n].label_types) +       pop_vals(label_types(ctrls[n]))       unreachable() case (br_if n)      error_if(ctrls.size() < n) pop_val(I32) -       pop_vals(ctrls[n].label_types) -       push_vals(ctrls[n].label_types) +       pop_vals(label_types(ctrls[n])) +       push_vals(label_types(ctrls[n]))    case (br_table n* m)       error_if(ctrls.size() < m)       foreach (n in n*) -         error_if(ctrls.size() < n || ctrls[n].label_types =/= ctrls[m].label_types) +         error_if(ctrls.size() < n || label_types(ctrls[n]) =/= label_types(ctrls[m])) pop_val(I32) -       pop_vals(ctrls[m].label_types) +       pop_vals(label_types(ctrls[m]))       unreachable() .. note:: diff --git a/document/core/appendix/implementation.rst b/document/core/appendix/implementation.rst index df2885ccc8..d5e53920fa 100644 --- a/document/core/appendix/implementation.rst +++ b/document/core/appendix/implementation.rst @@ -43,6 +43,8 @@ An implementation may impose restrictions on the following dimensions of a modul * the number of :ref:`exports ` from a :ref:`module ` * the number of parameters in a :ref:`function type ` * the number of results in a :ref:`function type ` +* the number of parameters in a :ref:`block type ` +* the number of results in a :ref:`block type ` * the number of :ref:`locals ` in a :ref:`function ` * the size of a :ref:`function ` body * the size of a :ref:`structured control instruction ` diff --git a/document/core/appendix/index-instructions.rst b/document/core/appendix/index-instructions.rst index dbb0200228..e0c683cedb 100644 --- a/document/core/appendix/index-instructions.rst +++ b/document/core/appendix/index-instructions.rst @@ -4,228 +4,269 @@ Index of Instructions --------------------- -====================================== ================== ========================================== ======================================== =============================================================== -Instruction Binary Opcode Type Validation Execution -====================================== ================== ========================================== ======================================== =============================================================== -:math:`\UNREACHABLE` :math:`\hex{00}` :math:`[t_1^\ast] \to [t_2^\ast]` :ref:`validation ` :ref:`execution ` -:math:`\NOP` :math:`\hex{01}` :math:`[] \to []` :ref:`validation ` :ref:`execution ` -:math:`\BLOCK~[t^?]` :math:`\hex{02}` :math:`[] \to [t^\ast]` :ref:`validation ` :ref:`execution ` -:math:`\LOOP~[t^?]` :math:`\hex{03}` :math:`[] \to [t^\ast]` :ref:`validation ` :ref:`execution ` -:math:`\IF~[t^?]` :math:`\hex{04}` :math:`[\I32] \to [t^\ast]` :ref:`validation ` :ref:`execution ` -:math:`\ELSE` :math:`\hex{05}` -(reserved) :math:`\hex{06}` -(reserved) :math:`\hex{07}` -(reserved) :math:`\hex{08}` -(reserved) :math:`\hex{09}` -(reserved) :math:`\hex{0A}` -:math:`\END` :math:`\hex{0B}` -:math:`\BR~l` :math:`\hex{0C}` :math:`[t_1^\ast~t^?] \to [t_2^\ast]` :ref:`validation ` :ref:`execution ` -:math:`\BRIF~l` :math:`\hex{0D}` :math:`[t^?~\I32] \to [t^?]` :ref:`validation ` :ref:`execution ` -:math:`\BRTABLE~l^\ast~l` :math:`\hex{0E}` :math:`[t_1^\ast~t^?~\I32] \to [t_2^\ast]` :ref:`validation ` :ref:`execution ` -:math:`\RETURN` :math:`\hex{0F}` :math:`[t_1^\ast~t^?] \to [t_2^\ast]` :ref:`validation ` :ref:`execution ` -:math:`\CALL~x` :math:`\hex{10}` :math:`[t_1^\ast] \to [t_2^\ast]` :ref:`validation ` :ref:`execution ` -:math:`\CALLINDIRECT~x` :math:`\hex{11}` :math:`[t_1^\ast~\I32] \to [t_2^\ast]` :ref:`validation ` :ref:`execution ` -(reserved) :math:`\hex{12}` -(reserved) :math:`\hex{13}` -(reserved) :math:`\hex{14}` -(reserved) :math:`\hex{15}` -(reserved) :math:`\hex{16}` -(reserved) :math:`\hex{17}` -(reserved) :math:`\hex{18}` -(reserved) :math:`\hex{19}` -:math:`\DROP` :math:`\hex{1A}` :math:`[t] \to []` :ref:`validation ` :ref:`execution ` -:math:`\SELECT` :math:`\hex{1B}` :math:`[t~t~\I32] \to [t]` :ref:`validation ` :ref:`execution ` -:math:`\SELECT~t` :math:`\hex{1C}` :math:`[t~t~\I32] \to [t]` :ref:`validation ` :ref:`execution ` -(reserved) :math:`\hex{1D}` -(reserved) :math:`\hex{1E}` -(reserved) :math:`\hex{1F}` -:math:`\LOCALGET~x` :math:`\hex{20}` :math:`[] \to [t]` :ref:`validation ` :ref:`execution ` -:math:`\LOCALSET~x` :math:`\hex{21}` :math:`[t] \to []` :ref:`validation ` :ref:`execution ` -:math:`\LOCALTEE~x` :math:`\hex{22}` :math:`[t] \to [t]` :ref:`validation ` :ref:`execution ` -:math:`\GLOBALGET~x` :math:`\hex{23}` :math:`[] \to [t]` :ref:`validation ` :ref:`execution ` -:math:`\GLOBALSET~x` :math:`\hex{24}` :math:`[t] \to []` :ref:`validation ` :ref:`execution ` -:math:`\TABLEGET~x` :math:`\hex{25}` :math:`[\I32] \to [t]` :ref:`validation ` :ref:`execution ` -:math:`\TABLESET~x` :math:`\hex{26}` :math:`[\I32~t] \to []` :ref:`validation ` :ref:`execution ` -(reserved) :math:`\hex{27}` -:math:`\I32.\LOAD~\memarg` :math:`\hex{28}` :math:`[\I32] \to [\I32]` :ref:`validation ` :ref:`execution ` -:math:`\I64.\LOAD~\memarg` :math:`\hex{29}` :math:`[\I32] \to [\I64]` :ref:`validation ` :ref:`execution ` -:math:`\F32.\LOAD~\memarg` :math:`\hex{2A}` :math:`[\I32] \to [\F32]` :ref:`validation ` :ref:`execution ` -:math:`\F64.\LOAD~\memarg` :math:`\hex{2B}` :math:`[\I32] \to [\F64]` :ref:`validation ` :ref:`execution ` -:math:`\I32.\LOAD\K{8\_s}~\memarg` :math:`\hex{2C}` :math:`[\I32] \to [\I32]` :ref:`validation ` :ref:`execution ` -:math:`\I32.\LOAD\K{8\_u}~\memarg` :math:`\hex{2D}` :math:`[\I32] \to [\I32]` :ref:`validation ` :ref:`execution ` -:math:`\I32.\LOAD\K{16\_s}~\memarg` :math:`\hex{2E}` :math:`[\I32] \to [\I32]` :ref:`validation ` :ref:`execution ` -:math:`\I32.\LOAD\K{16\_u}~\memarg` :math:`\hex{2F}` :math:`[\I32] \to [\I32]` :ref:`validation ` :ref:`execution ` -:math:`\I64.\LOAD\K{8\_s}~\memarg` :math:`\hex{30}` :math:`[\I32] \to [\I64]` :ref:`validation ` :ref:`execution ` -:math:`\I64.\LOAD\K{8\_u}~\memarg` :math:`\hex{31}` :math:`[\I32] \to [\I64]` :ref:`validation ` :ref:`execution ` -:math:`\I64.\LOAD\K{16\_s}~\memarg` :math:`\hex{32}` :math:`[\I32] \to [\I64]` :ref:`validation ` :ref:`execution ` -:math:`\I64.\LOAD\K{16\_u}~\memarg` :math:`\hex{33}` :math:`[\I32] \to [\I64]` :ref:`validation ` :ref:`execution ` -:math:`\I64.\LOAD\K{32\_s}~\memarg` :math:`\hex{34}` :math:`[\I32] \to [\I64]` :ref:`validation ` :ref:`execution ` -:math:`\I64.\LOAD\K{32\_u}~\memarg` :math:`\hex{35}` :math:`[\I32] \to [\I64]` :ref:`validation ` :ref:`execution ` -:math:`\I32.\STORE~\memarg` :math:`\hex{36}` :math:`[\I32~\I32] \to []` :ref:`validation ` :ref:`execution ` -:math:`\I64.\STORE~\memarg` :math:`\hex{37}` :math:`[\I32~\I64] \to []` :ref:`validation ` :ref:`execution ` -:math:`\F32.\STORE~\memarg` :math:`\hex{38}` :math:`[\I32~\F32] \to []` :ref:`validation ` :ref:`execution ` -:math:`\F64.\STORE~\memarg` :math:`\hex{39}` :math:`[\I32~\F64] \to []` :ref:`validation ` :ref:`execution ` -:math:`\I32.\STORE\K{8}~\memarg` :math:`\hex{3A}` :math:`[\I32~\I32] \to []` :ref:`validation ` :ref:`execution ` -:math:`\I32.\STORE\K{16}~\memarg` :math:`\hex{3B}` :math:`[\I32~\I32] \to []` :ref:`validation ` :ref:`execution ` -:math:`\I64.\STORE\K{8}~\memarg` :math:`\hex{3C}` :math:`[\I32~\I64] \to []` :ref:`validation ` :ref:`execution ` -:math:`\I64.\STORE\K{16}~\memarg` :math:`\hex{3D}` :math:`[\I32~\I64] \to []` :ref:`validation ` :ref:`execution ` -:math:`\I64.\STORE\K{32}~\memarg` :math:`\hex{3E}` :math:`[\I32~\I64] \to []` :ref:`validation ` :ref:`execution ` -:math:`\MEMORYSIZE` :math:`\hex{3F}` :math:`[] \to [\I32]` :ref:`validation ` :ref:`execution ` -:math:`\MEMORYGROW` :math:`\hex{40}` :math:`[\I32] \to [\I32]` :ref:`validation ` :ref:`execution ` -:math:`\I32.\CONST~\i32` :math:`\hex{41}` :math:`[] \to [\I32]` :ref:`validation ` :ref:`execution ` -:math:`\I64.\CONST~\i64` :math:`\hex{42}` :math:`[] \to [\I64]` :ref:`validation ` :ref:`execution ` -:math:`\F32.\CONST~\f32` :math:`\hex{43}` :math:`[] \to [\F32]` :ref:`validation ` :ref:`execution ` -:math:`\F64.\CONST~\f64` :math:`\hex{44}` :math:`[] \to [\F64]` :ref:`validation ` :ref:`execution ` -:math:`\I32.\EQZ` :math:`\hex{45}` :math:`[\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I32.\EQ` :math:`\hex{46}` :math:`[\I32~\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I32.\NE` :math:`\hex{47}` :math:`[\I32~\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I32.\LT\K{\_s}` :math:`\hex{48}` :math:`[\I32~\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I32.\LT\K{\_u}` :math:`\hex{49}` :math:`[\I32~\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I32.\GT\K{\_s}` :math:`\hex{4A}` :math:`[\I32~\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I32.\GT\K{\_u}` :math:`\hex{4B}` :math:`[\I32~\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I32.\LE\K{\_s}` :math:`\hex{4C}` :math:`[\I32~\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I32.\LE\K{\_u}` :math:`\hex{4D}` :math:`[\I32~\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I32.\GE\K{\_s}` :math:`\hex{4E}` :math:`[\I32~\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I32.\GE\K{\_u}` :math:`\hex{4F}` :math:`[\I32~\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I64.\EQZ` :math:`\hex{50}` :math:`[\I64] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I64.\EQ` :math:`\hex{51}` :math:`[\I64~\I64] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I64.\NE` :math:`\hex{52}` :math:`[\I64~\I64] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I64.\LT\K{\_s}` :math:`\hex{53}` :math:`[\I64~\I64] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I64.\LT\K{\_u}` :math:`\hex{54}` :math:`[\I64~\I64] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I64.\GT\K{\_s}` :math:`\hex{55}` :math:`[\I64~\I64] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I64.\GT\K{\_u}` :math:`\hex{56}` :math:`[\I64~\I64] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I64.\LE\K{\_s}` :math:`\hex{57}` :math:`[\I64~\I64] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I64.\LE\K{\_u}` :math:`\hex{58}` :math:`[\I64~\I64] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I64.\GE\K{\_s}` :math:`\hex{59}` :math:`[\I64~\I64] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I64.\GE\K{\_u}` :math:`\hex{5A}` :math:`[\I64~\I64] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F32.\EQ` :math:`\hex{5B}` :math:`[\F32~\F32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F32.\NE` :math:`\hex{5C}` :math:`[\F32~\F32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F32.\LT` :math:`\hex{5D}` :math:`[\F32~\F32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F32.\GT` :math:`\hex{5E}` :math:`[\F32~\F32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F32.\LE` :math:`\hex{5F}` :math:`[\F32~\F32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F32.\GE` :math:`\hex{60}` :math:`[\F32~\F32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F64.\EQ` :math:`\hex{61}` :math:`[\F64~\F64] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F64.\NE` :math:`\hex{62}` :math:`[\F64~\F64] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F64.\LT` :math:`\hex{63}` :math:`[\F64~\F64] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F64.\GT` :math:`\hex{64}` :math:`[\F64~\F64] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F64.\LE` :math:`\hex{65}` :math:`[\F64~\F64] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F64.\GE` :math:`\hex{66}` :math:`[\F64~\F64] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I32.\CLZ` :math:`\hex{67}` :math:`[\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I32.\CTZ` :math:`\hex{68}` :math:`[\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I32.\POPCNT` :math:`\hex{69}` :math:`[\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I32.\ADD` :math:`\hex{6A}` :math:`[\I32~\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I32.\SUB` :math:`\hex{6B}` :math:`[\I32~\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I32.\MUL` :math:`\hex{6C}` :math:`[\I32~\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I32.\DIV\K{\_s}` :math:`\hex{6D}` :math:`[\I32~\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I32.\DIV\K{\_u}` :math:`\hex{6E}` :math:`[\I32~\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I32.\REM\K{\_s}` :math:`\hex{6F}` :math:`[\I32~\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I32.\REM\K{\_u}` :math:`\hex{70}` :math:`[\I32~\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I32.\AND` :math:`\hex{71}` :math:`[\I32~\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I32.\OR` :math:`\hex{72}` :math:`[\I32~\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I32.\XOR` :math:`\hex{73}` :math:`[\I32~\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I32.\SHL` :math:`\hex{74}` :math:`[\I32~\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I32.\SHR\K{\_s}` :math:`\hex{75}` :math:`[\I32~\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I32.\SHR\K{\_u}` :math:`\hex{76}` :math:`[\I32~\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I32.\ROTL` :math:`\hex{77}` :math:`[\I32~\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I32.\ROTR` :math:`\hex{78}` :math:`[\I32~\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I64.\CLZ` :math:`\hex{79}` :math:`[\I64] \to [\I64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I64.\CTZ` :math:`\hex{7A}` :math:`[\I64] \to [\I64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I64.\POPCNT` :math:`\hex{7B}` :math:`[\I64] \to [\I64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I64.\ADD` :math:`\hex{7C}` :math:`[\I64~\I64] \to [\I64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I64.\SUB` :math:`\hex{7D}` :math:`[\I64~\I64] \to [\I64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I64.\MUL` :math:`\hex{7E}` :math:`[\I64~\I64] \to [\I64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I64.\DIV\K{\_s}` :math:`\hex{7F}` :math:`[\I64~\I64] \to [\I64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I64.\DIV\K{\_u}` :math:`\hex{80}` :math:`[\I64~\I64] \to [\I64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I64.\REM\K{\_s}` :math:`\hex{81}` :math:`[\I64~\I64] \to [\I64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I64.\REM\K{\_u}` :math:`\hex{82}` :math:`[\I64~\I64] \to [\I64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I64.\AND` :math:`\hex{83}` :math:`[\I64~\I64] \to [\I64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I64.\OR` :math:`\hex{84}` :math:`[\I64~\I64] \to [\I64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I64.\XOR` :math:`\hex{85}` :math:`[\I64~\I64] \to [\I64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I64.\SHL` :math:`\hex{86}` :math:`[\I64~\I64] \to [\I64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I64.\SHR\K{\_s}` :math:`\hex{87}` :math:`[\I64~\I64] \to [\I64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I64.\SHR\K{\_u}` :math:`\hex{88}` :math:`[\I64~\I64] \to [\I64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I64.\ROTL` :math:`\hex{89}` :math:`[\I64~\I64] \to [\I64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I64.\ROTR` :math:`\hex{8A}` :math:`[\I64~\I64] \to [\I64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F32.\ABS` :math:`\hex{8B}` :math:`[\F32] \to [\F32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F32.\NEG` :math:`\hex{8C}` :math:`[\F32] \to [\F32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F32.\CEIL` :math:`\hex{8D}` :math:`[\F32] \to [\F32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F32.\FLOOR` :math:`\hex{8E}` :math:`[\F32] \to [\F32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F32.\TRUNC` :math:`\hex{8F}` :math:`[\F32] \to [\F32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F32.\NEAREST` :math:`\hex{90}` :math:`[\F32] \to [\F32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F32.\SQRT` :math:`\hex{91}` :math:`[\F32] \to [\F32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F32.\ADD` :math:`\hex{92}` :math:`[\F32~\F32] \to [\F32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F32.\SUB` :math:`\hex{93}` :math:`[\F32~\F32] \to [\F32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F32.\MUL` :math:`\hex{94}` :math:`[\F32~\F32] \to [\F32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F32.\DIV` :math:`\hex{95}` :math:`[\F32~\F32] \to [\F32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F32.\FMIN` :math:`\hex{96}` :math:`[\F32~\F32] \to [\F32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F32.\FMAX` :math:`\hex{97}` :math:`[\F32~\F32] \to [\F32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F32.\COPYSIGN` :math:`\hex{98}` :math:`[\F32~\F32] \to [\F32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F64.\ABS` :math:`\hex{99}` :math:`[\F64] \to [\F64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F64.\NEG` :math:`\hex{9A}` :math:`[\F64] \to [\F64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F64.\CEIL` :math:`\hex{9B}` :math:`[\F64] \to [\F64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F64.\FLOOR` :math:`\hex{9C}` :math:`[\F64] \to [\F64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F64.\TRUNC` :math:`\hex{9D}` :math:`[\F64] \to [\F64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F64.\NEAREST` :math:`\hex{9E}` :math:`[\F64] \to [\F64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F64.\SQRT` :math:`\hex{9F}` :math:`[\F64] \to [\F64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F64.\ADD` :math:`\hex{A0}` :math:`[\F64~\F64] \to [\F64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F64.\SUB` :math:`\hex{A1}` :math:`[\F64~\F64] \to [\F64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F64.\MUL` :math:`\hex{A2}` :math:`[\F64~\F64] \to [\F64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F64.\DIV` :math:`\hex{A3}` :math:`[\F64~\F64] \to [\F64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F64.\FMIN` :math:`\hex{A4}` :math:`[\F64~\F64] \to [\F64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F64.\FMAX` :math:`\hex{A5}` :math:`[\F64~\F64] \to [\F64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F64.\COPYSIGN` :math:`\hex{A6}` :math:`[\F64~\F64] \to [\F64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I32.\WRAP\K{\_}\I64` :math:`\hex{A7}` :math:`[\I64] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I32.\TRUNC\K{\_}\F32\K{\_s}` :math:`\hex{A8}` :math:`[\F32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I32.\TRUNC\K{\_}\F32\K{\_u}` :math:`\hex{A9}` :math:`[\F32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I32.\TRUNC\K{\_}\F64\K{\_s}` :math:`\hex{AA}` :math:`[\F64] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I32.\TRUNC\K{\_}\F64\K{\_u}` :math:`\hex{AB}` :math:`[\F64] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I64.\EXTEND\K{\_}\I32\K{\_s}` :math:`\hex{AC}` :math:`[\I32] \to [\I64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I64.\EXTEND\K{\_}\I32\K{\_u}` :math:`\hex{AD}` :math:`[\I32] \to [\I64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I64.\TRUNC\K{\_}\F32\K{\_s}` :math:`\hex{AE}` :math:`[\F32] \to [\I64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I64.\TRUNC\K{\_}\F32\K{\_u}` :math:`\hex{AF}` :math:`[\F32] \to [\I64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I64.\TRUNC\K{\_}\F64\K{\_s}` :math:`\hex{B0}` :math:`[\F64] \to [\I64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I64.\TRUNC\K{\_}\F64\K{\_u}` :math:`\hex{B1}` :math:`[\F64] \to [\I64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F32.\CONVERT\K{\_}\I32\K{\_s}` :math:`\hex{B2}` :math:`[\I32] \to [\F32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F32.\CONVERT\K{\_}\I32\K{\_u}` :math:`\hex{B3}` :math:`[\I32] \to [\F32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F32.\CONVERT\K{\_}\I64\K{\_s}` :math:`\hex{B4}` :math:`[\I64] \to [\F32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F32.\CONVERT\K{\_}\I64\K{\_u}` :math:`\hex{B5}` :math:`[\I64] \to [\F32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F32.\DEMOTE\K{\_}\F64` :math:`\hex{B6}` :math:`[\F64] \to [\F32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F64.\CONVERT\K{\_}\I32\K{\_s}` :math:`\hex{B7}` :math:`[\I32] \to [\F64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F64.\CONVERT\K{\_}\I32\K{\_u}` :math:`\hex{B8}` :math:`[\I32] \to [\F64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F64.\CONVERT\K{\_}\I64\K{\_s}` :math:`\hex{B9}` :math:`[\I64] \to [\F64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F64.\CONVERT\K{\_}\I64\K{\_u}` :math:`\hex{BA}` :math:`[\I64] \to [\F64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F64.\PROMOTE\K{\_}\F32` :math:`\hex{BB}` :math:`[\F32] \to [\F64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I32.\REINTERPRET\K{\_}\F32` :math:`\hex{BC}` :math:`[\F32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I64.\REINTERPRET\K{\_}\F64` :math:`\hex{BD}` :math:`[\F64] \to [\I64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F32.\REINTERPRET\K{\_}\I32` :math:`\hex{BE}` :math:`[\I32] \to [\F32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F64.\REINTERPRET\K{\_}\I64` :math:`\hex{BF}` :math:`[\I64] \to [\F64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -(reserved) :math:`\hex{C0}` -(reserved) :math:`\hex{C1}` -(reserved) :math:`\hex{C2}` -(reserved) :math:`\hex{C3}` -(reserved) :math:`\hex{C4}` -(reserved) :math:`\hex{C5}` -(reserved) :math:`\hex{C6}` -(reserved) :math:`\hex{C7}` -(reserved) :math:`\hex{C8}` -(reserved) :math:`\hex{C9}` -(reserved) :math:`\hex{CA}` -(reserved) :math:`\hex{CB}` -(reserved) :math:`\hex{CC}` -(reserved) :math:`\hex{CD}` -(reserved) :math:`\hex{CE}` -(reserved) :math:`\hex{CF}` -:math:`\REFNULL~t` :math:`\hex{D0}` :math:`[] \to [t]` :ref:`validation ` :ref:`execution ` -:math:`\REFISNULL~t` :math:`\hex{D1}` :math:`[t] \to [\I32]` :ref:`validation ` :ref:`execution ` -:math:`\REFFUNC~x` :math:`\hex{D2}` :math:`[] \to [\FUNCREF]` :ref:`validation ` :ref:`execution ` -:math:`\MEMORYINIT` :math:`\hex{FC08}` :math:`[\I32~\I32~\I32] \to []` :ref:`validation ` :ref:`execution ` -:math:`\DATADROP` :math:`\hex{FC09}` :math:`[] \to []` :ref:`validation ` :ref:`execution ` -:math:`\MEMORYCOPY` :math:`\hex{FC0A}` :math:`[\I32~\I32~\I32] \to []` :ref:`validation ` :ref:`execution ` -:math:`\MEMORYFILL` :math:`\hex{FC0B}` :math:`[\I32~\I32~\I32] \to []` :ref:`validation ` :ref:`execution ` -:math:`\TABLEINIT` :math:`\hex{FC0C}` :math:`[\I32~\I32~\I32] \to []` :ref:`validation ` :ref:`execution ` -:math:`\ELEMDROP` :math:`\hex{FC0D}` :math:`[] \to []` :ref:`validation ` :ref:`execution ` -:math:`\TABLECOPY` :math:`\hex{FC0E}` :math:`[\I32~\I32~\I32] \to []` :ref:`validation ` :ref:`execution ` -:math:`\TABLEGROW` :math:`\hex{FC0F}` :math:`[t~\I32] \to []` :ref:`validation ` :ref:`execution ` -:math:`\TABLESIZE` :math:`\hex{FC10}` :math:`[] \to []` :ref:`validation ` :ref:`execution ` -:math:`\TABLEFILL` :math:`\hex{FC11}` :math:`[\I32~t~\I32] \to []` :ref:`validation ` :ref:`execution ` -====================================== ================== ========================================== ======================================== =============================================================== +========================================= ========================= ============================================= ======================================== =============================================================== +Instruction Binary Opcode Type Validation Execution +========================================= ========================= ============================================= ======================================== =============================================================== +:math:`\UNREACHABLE` :math:`\hex{00}` :math:`[t_1^\ast] \to [t_2^\ast]` :ref:`validation ` :ref:`execution ` +:math:`\NOP` :math:`\hex{01}` :math:`[] \to []` :ref:`validation ` :ref:`execution ` +:math:`\BLOCK~\X{bt}` :math:`\hex{02}` :math:`[t_1^\ast] \to [t_2^\ast]` :ref:`validation ` :ref:`execution ` +:math:`\LOOP~\X{bt}` :math:`\hex{03}` :math:`[t_1^\ast] \to [t_2^\ast]` :ref:`validation ` :ref:`execution ` +:math:`\IF~\X{bt}` :math:`\hex{04}` :math:`[t_1^\ast] \to [t_2^\ast]` :ref:`validation ` :ref:`execution ` +:math:`\ELSE` :math:`\hex{05}` +(reserved) :math:`\hex{06}` +(reserved) :math:`\hex{07}` +(reserved) :math:`\hex{08}` +(reserved) :math:`\hex{09}` +(reserved) :math:`\hex{0A}` +:math:`\END` :math:`\hex{0B}` +:math:`\BR~l` :math:`\hex{0C}` :math:`[t_1^\ast~t^\ast] \to [t_2^\ast]` :ref:`validation ` :ref:`execution ` +:math:`\BRIF~l` :math:`\hex{0D}` :math:`[t^\ast~\I32] \to [t^\ast]` :ref:`validation ` :ref:`execution ` +:math:`\BRTABLE~l^\ast~l` :math:`\hex{0E}` :math:`[t_1^\ast~t^\ast~\I32] \to [t_2^\ast]` :ref:`validation ` :ref:`execution ` +:math:`\RETURN` :math:`\hex{0F}` :math:`[t_1^\ast~t^\ast] \to [t_2^\ast]` :ref:`validation ` :ref:`execution ` +:math:`\CALL~x` :math:`\hex{10}` :math:`[t_1^\ast] \to [t_2^\ast]` :ref:`validation ` :ref:`execution ` +:math:`\CALLINDIRECT~x` :math:`\hex{11}` :math:`[t_1^\ast~\I32] \to [t_2^\ast]` :ref:`validation ` :ref:`execution ` +(reserved) :math:`\hex{12}` +(reserved) :math:`\hex{13}` +(reserved) :math:`\hex{14}` +(reserved) :math:`\hex{15}` +(reserved) :math:`\hex{16}` +(reserved) :math:`\hex{17}` +(reserved) :math:`\hex{18}` +(reserved) :math:`\hex{19}` +:math:`\DROP` :math:`\hex{1A}` :math:`[t] \to []` :ref:`validation ` :ref:`execution ` +:math:`\SELECT` :math:`\hex{1B}` :math:`[t~t~\I32] \to [t]` :ref:`validation ` :ref:`execution ` +:math:`\SELECT~t` :math:`\hex{1C}` :math:`[t~t~\I32] \to [t]` :ref:`validation ` :ref:`execution ` +(reserved) :math:`\hex{1D}` +(reserved) :math:`\hex{1E}` +(reserved) :math:`\hex{1F}` +:math:`\LOCALGET~x` :math:`\hex{20}` :math:`[] \to [t]` :ref:`validation ` :ref:`execution ` +:math:`\LOCALSET~x` :math:`\hex{21}` :math:`[t] \to []` :ref:`validation ` :ref:`execution ` +:math:`\LOCALTEE~x` :math:`\hex{22}` :math:`[t] \to [t]` :ref:`validation ` :ref:`execution ` +:math:`\GLOBALGET~x` :math:`\hex{23}` :math:`[] \to [t]` :ref:`validation ` :ref:`execution ` +:math:`\GLOBALSET~x` :math:`\hex{24}` :math:`[t] \to []` :ref:`validation ` :ref:`execution ` +:math:`\TABLEGET~x` :math:`\hex{25}` :math:`[\I32] \to [t]` :ref:`validation ` :ref:`execution ` +:math:`\TABLESET~x` :math:`\hex{26}` :math:`[\I32~t] \to []` :ref:`validation ` :ref:`execution ` +(reserved) :math:`\hex{27}` +:math:`\I32.\LOAD~\memarg` :math:`\hex{28}` :math:`[\I32] \to [\I32]` :ref:`validation ` :ref:`execution ` +:math:`\I64.\LOAD~\memarg` :math:`\hex{29}` :math:`[\I32] \to [\I64]` :ref:`validation ` :ref:`execution ` +:math:`\F32.\LOAD~\memarg` :math:`\hex{2A}` :math:`[\I32] \to [\F32]` :ref:`validation ` :ref:`execution ` +:math:`\F64.\LOAD~\memarg` :math:`\hex{2B}` :math:`[\I32] \to [\F64]` :ref:`validation ` :ref:`execution ` +:math:`\I32.\LOAD\K{8\_s}~\memarg` :math:`\hex{2C}` :math:`[\I32] \to [\I32]` :ref:`validation ` :ref:`execution ` +:math:`\I32.\LOAD\K{8\_u}~\memarg` :math:`\hex{2D}` :math:`[\I32] \to [\I32]` :ref:`validation ` :ref:`execution ` +:math:`\I32.\LOAD\K{16\_s}~\memarg` :math:`\hex{2E}` :math:`[\I32] \to [\I32]` :ref:`validation ` :ref:`execution ` +:math:`\I32.\LOAD\K{16\_u}~\memarg` :math:`\hex{2F}` :math:`[\I32] \to [\I32]` :ref:`validation ` :ref:`execution ` +:math:`\I64.\LOAD\K{8\_s}~\memarg` :math:`\hex{30}` :math:`[\I32] \to [\I64]` :ref:`validation ` :ref:`execution ` +:math:`\I64.\LOAD\K{8\_u}~\memarg` :math:`\hex{31}` :math:`[\I32] \to [\I64]` :ref:`validation ` :ref:`execution ` +:math:`\I64.\LOAD\K{16\_s}~\memarg` :math:`\hex{32}` :math:`[\I32] \to [\I64]` :ref:`validation ` :ref:`execution ` +:math:`\I64.\LOAD\K{16\_u}~\memarg` :math:`\hex{33}` :math:`[\I32] \to [\I64]` :ref:`validation ` :ref:`execution ` +:math:`\I64.\LOAD\K{32\_s}~\memarg` :math:`\hex{34}` :math:`[\I32] \to [\I64]` :ref:`validation ` :ref:`execution ` +:math:`\I64.\LOAD\K{32\_u}~\memarg` :math:`\hex{35}` :math:`[\I32] \to [\I64]` :ref:`validation ` :ref:`execution ` +:math:`\I32.\STORE~\memarg` :math:`\hex{36}` :math:`[\I32~\I32] \to []` :ref:`validation ` :ref:`execution ` +:math:`\I64.\STORE~\memarg` :math:`\hex{37}` :math:`[\I32~\I64] \to []` :ref:`validation ` :ref:`execution ` +:math:`\F32.\STORE~\memarg` :math:`\hex{38}` :math:`[\I32~\F32] \to []` :ref:`validation ` :ref:`execution ` +:math:`\F64.\STORE~\memarg` :math:`\hex{39}` :math:`[\I32~\F64] \to []` :ref:`validation ` :ref:`execution ` +:math:`\I32.\STORE\K{8}~\memarg` :math:`\hex{3A}` :math:`[\I32~\I32] \to []` :ref:`validation ` :ref:`execution ` +:math:`\I32.\STORE\K{16}~\memarg` :math:`\hex{3B}` :math:`[\I32~\I32] \to []` :ref:`validation ` :ref:`execution ` +:math:`\I64.\STORE\K{8}~\memarg` :math:`\hex{3C}` :math:`[\I32~\I64] \to []` :ref:`validation ` :ref:`execution ` +:math:`\I64.\STORE\K{16}~\memarg` :math:`\hex{3D}` :math:`[\I32~\I64] \to []` :ref:`validation ` :ref:`execution ` +:math:`\I64.\STORE\K{32}~\memarg` :math:`\hex{3E}` :math:`[\I32~\I64] \to []` :ref:`validation ` :ref:`execution ` +:math:`\MEMORYSIZE` :math:`\hex{3F}` :math:`[] \to [\I32]` :ref:`validation ` :ref:`execution ` +:math:`\MEMORYGROW` :math:`\hex{40}` :math:`[\I32] \to [\I32]` :ref:`validation ` :ref:`execution ` +:math:`\I32.\CONST~\i32` :math:`\hex{41}` :math:`[] \to [\I32]` :ref:`validation ` :ref:`execution ` +:math:`\I64.\CONST~\i64` :math:`\hex{42}` :math:`[] \to [\I64]` :ref:`validation ` :ref:`execution ` +:math:`\F32.\CONST~\f32` :math:`\hex{43}` :math:`[] \to [\F32]` :ref:`validation ` :ref:`execution ` +:math:`\F64.\CONST~\f64` :math:`\hex{44}` :math:`[] \to [\F64]` :ref:`validation ` :ref:`execution ` +:math:`\I32.\EQZ` :math:`\hex{45}` :math:`[\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I32.\EQ` :math:`\hex{46}` :math:`[\I32~\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I32.\NE` :math:`\hex{47}` :math:`[\I32~\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I32.\LT\K{\_s}` :math:`\hex{48}` :math:`[\I32~\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I32.\LT\K{\_u}` :math:`\hex{49}` :math:`[\I32~\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I32.\GT\K{\_s}` :math:`\hex{4A}` :math:`[\I32~\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I32.\GT\K{\_u}` :math:`\hex{4B}` :math:`[\I32~\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I32.\LE\K{\_s}` :math:`\hex{4C}` :math:`[\I32~\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I32.\LE\K{\_u}` :math:`\hex{4D}` :math:`[\I32~\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I32.\GE\K{\_s}` :math:`\hex{4E}` :math:`[\I32~\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I32.\GE\K{\_u}` :math:`\hex{4F}` :math:`[\I32~\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I64.\EQZ` :math:`\hex{50}` :math:`[\I64] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I64.\EQ` :math:`\hex{51}` :math:`[\I64~\I64] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I64.\NE` :math:`\hex{52}` :math:`[\I64~\I64] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I64.\LT\K{\_s}` :math:`\hex{53}` :math:`[\I64~\I64] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I64.\LT\K{\_u}` :math:`\hex{54}` :math:`[\I64~\I64] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I64.\GT\K{\_s}` :math:`\hex{55}` :math:`[\I64~\I64] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I64.\GT\K{\_u}` :math:`\hex{56}` :math:`[\I64~\I64] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I64.\LE\K{\_s}` :math:`\hex{57}` :math:`[\I64~\I64] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I64.\LE\K{\_u}` :math:`\hex{58}` :math:`[\I64~\I64] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I64.\GE\K{\_s}` :math:`\hex{59}` :math:`[\I64~\I64] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I64.\GE\K{\_u}` :math:`\hex{5A}` :math:`[\I64~\I64] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\F32.\EQ` :math:`\hex{5B}` :math:`[\F32~\F32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\F32.\NE` :math:`\hex{5C}` :math:`[\F32~\F32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\F32.\LT` :math:`\hex{5D}` :math:`[\F32~\F32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\F32.\GT` :math:`\hex{5E}` :math:`[\F32~\F32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\F32.\LE` :math:`\hex{5F}` :math:`[\F32~\F32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\F32.\GE` :math:`\hex{60}` :math:`[\F32~\F32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\F64.\EQ` :math:`\hex{61}` :math:`[\F64~\F64] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\F64.\NE` :math:`\hex{62}` :math:`[\F64~\F64] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\F64.\LT` :math:`\hex{63}` :math:`[\F64~\F64] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\F64.\GT` :math:`\hex{64}` :math:`[\F64~\F64] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\F64.\LE` :math:`\hex{65}` :math:`[\F64~\F64] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\F64.\GE` :math:`\hex{66}` :math:`[\F64~\F64] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I32.\CLZ` :math:`\hex{67}` :math:`[\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I32.\CTZ` :math:`\hex{68}` :math:`[\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I32.\POPCNT` :math:`\hex{69}` :math:`[\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I32.\ADD` :math:`\hex{6A}` :math:`[\I32~\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I32.\SUB` :math:`\hex{6B}` :math:`[\I32~\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I32.\MUL` :math:`\hex{6C}` :math:`[\I32~\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I32.\DIV\K{\_s}` :math:`\hex{6D}` :math:`[\I32~\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I32.\DIV\K{\_u}` :math:`\hex{6E}` :math:`[\I32~\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I32.\REM\K{\_s}` :math:`\hex{6F}` :math:`[\I32~\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I32.\REM\K{\_u}` :math:`\hex{70}` :math:`[\I32~\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I32.\AND` :math:`\hex{71}` :math:`[\I32~\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I32.\OR` :math:`\hex{72}` :math:`[\I32~\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I32.\XOR` :math:`\hex{73}` :math:`[\I32~\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I32.\SHL` :math:`\hex{74}` :math:`[\I32~\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I32.\SHR\K{\_s}` :math:`\hex{75}` :math:`[\I32~\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I32.\SHR\K{\_u}` :math:`\hex{76}` :math:`[\I32~\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I32.\ROTL` :math:`\hex{77}` :math:`[\I32~\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I32.\ROTR` :math:`\hex{78}` :math:`[\I32~\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I64.\CLZ` :math:`\hex{79}` :math:`[\I64] \to [\I64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I64.\CTZ` :math:`\hex{7A}` :math:`[\I64] \to [\I64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I64.\POPCNT` :math:`\hex{7B}` :math:`[\I64] \to [\I64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I64.\ADD` :math:`\hex{7C}` :math:`[\I64~\I64] \to [\I64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I64.\SUB` :math:`\hex{7D}` :math:`[\I64~\I64] \to [\I64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I64.\MUL` :math:`\hex{7E}` :math:`[\I64~\I64] \to [\I64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I64.\DIV\K{\_s}` :math:`\hex{7F}` :math:`[\I64~\I64] \to [\I64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I64.\DIV\K{\_u}` :math:`\hex{80}` :math:`[\I64~\I64] \to [\I64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I64.\REM\K{\_s}` :math:`\hex{81}` :math:`[\I64~\I64] \to [\I64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I64.\REM\K{\_u}` :math:`\hex{82}` :math:`[\I64~\I64] \to [\I64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I64.\AND` :math:`\hex{83}` :math:`[\I64~\I64] \to [\I64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I64.\OR` :math:`\hex{84}` :math:`[\I64~\I64] \to [\I64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I64.\XOR` :math:`\hex{85}` :math:`[\I64~\I64] \to [\I64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I64.\SHL` :math:`\hex{86}` :math:`[\I64~\I64] \to [\I64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I64.\SHR\K{\_s}` :math:`\hex{87}` :math:`[\I64~\I64] \to [\I64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I64.\SHR\K{\_u}` :math:`\hex{88}` :math:`[\I64~\I64] \to [\I64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I64.\ROTL` :math:`\hex{89}` :math:`[\I64~\I64] \to [\I64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I64.\ROTR` :math:`\hex{8A}` :math:`[\I64~\I64] \to [\I64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\F32.\ABS` :math:`\hex{8B}` :math:`[\F32] \to [\F32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\F32.\NEG` :math:`\hex{8C}` :math:`[\F32] \to [\F32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\F32.\CEIL` :math:`\hex{8D}` :math:`[\F32] \to [\F32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\F32.\FLOOR` :math:`\hex{8E}` :math:`[\F32] \to [\F32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\F32.\TRUNC` :math:`\hex{8F}` :math:`[\F32] \to [\F32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\F32.\NEAREST` :math:`\hex{90}` :math:`[\F32] \to [\F32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\F32.\SQRT` :math:`\hex{91}` :math:`[\F32] \to [\F32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\F32.\ADD` :math:`\hex{92}` :math:`[\F32~\F32] \to [\F32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\F32.\SUB` :math:`\hex{93}` :math:`[\F32~\F32] \to [\F32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\F32.\MUL` :math:`\hex{94}` :math:`[\F32~\F32] \to [\F32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\F32.\DIV` :math:`\hex{95}` :math:`[\F32~\F32] \to [\F32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\F32.\FMIN` :math:`\hex{96}` :math:`[\F32~\F32] \to [\F32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\F32.\FMAX` :math:`\hex{97}` :math:`[\F32~\F32] \to [\F32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\F32.\COPYSIGN` :math:`\hex{98}` :math:`[\F32~\F32] \to [\F32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\F64.\ABS` :math:`\hex{99}` :math:`[\F64] \to [\F64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\F64.\NEG` :math:`\hex{9A}` :math:`[\F64] \to [\F64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\F64.\CEIL` :math:`\hex{9B}` :math:`[\F64] \to [\F64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\F64.\FLOOR` :math:`\hex{9C}` :math:`[\F64] \to [\F64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\F64.\TRUNC` :math:`\hex{9D}` :math:`[\F64] \to [\F64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\F64.\NEAREST` :math:`\hex{9E}` :math:`[\F64] \to [\F64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\F64.\SQRT` :math:`\hex{9F}` :math:`[\F64] \to [\F64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\F64.\ADD` :math:`\hex{A0}` :math:`[\F64~\F64] \to [\F64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\F64.\SUB` :math:`\hex{A1}` :math:`[\F64~\F64] \to [\F64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\F64.\MUL` :math:`\hex{A2}` :math:`[\F64~\F64] \to [\F64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\F64.\DIV` :math:`\hex{A3}` :math:`[\F64~\F64] \to [\F64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\F64.\FMIN` :math:`\hex{A4}` :math:`[\F64~\F64] \to [\F64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\F64.\FMAX` :math:`\hex{A5}` :math:`[\F64~\F64] \to [\F64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\F64.\COPYSIGN` :math:`\hex{A6}` :math:`[\F64~\F64] \to [\F64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I32.\WRAP\K{\_}\I64` :math:`\hex{A7}` :math:`[\I64] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I32.\TRUNC\K{\_}\F32\K{\_s}` :math:`\hex{A8}` :math:`[\F32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I32.\TRUNC\K{\_}\F32\K{\_u}` :math:`\hex{A9}` :math:`[\F32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I32.\TRUNC\K{\_}\F64\K{\_s}` :math:`\hex{AA}` :math:`[\F64] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I32.\TRUNC\K{\_}\F64\K{\_u}` :math:`\hex{AB}` :math:`[\F64] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I64.\EXTEND\K{\_}\I32\K{\_s}` :math:`\hex{AC}` :math:`[\I32] \to [\I64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I64.\EXTEND\K{\_}\I32\K{\_u}` :math:`\hex{AD}` :math:`[\I32] \to [\I64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I64.\TRUNC\K{\_}\F32\K{\_s}` :math:`\hex{AE}` :math:`[\F32] \to [\I64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I64.\TRUNC\K{\_}\F32\K{\_u}` :math:`\hex{AF}` :math:`[\F32] \to [\I64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I64.\TRUNC\K{\_}\F64\K{\_s}` :math:`\hex{B0}` :math:`[\F64] \to [\I64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I64.\TRUNC\K{\_}\F64\K{\_u}` :math:`\hex{B1}` :math:`[\F64] \to [\I64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\F32.\CONVERT\K{\_}\I32\K{\_s}` :math:`\hex{B2}` :math:`[\I32] \to [\F32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\F32.\CONVERT\K{\_}\I32\K{\_u}` :math:`\hex{B3}` :math:`[\I32] \to [\F32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\F32.\CONVERT\K{\_}\I64\K{\_s}` :math:`\hex{B4}` :math:`[\I64] \to [\F32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\F32.\CONVERT\K{\_}\I64\K{\_u}` :math:`\hex{B5}` :math:`[\I64] \to [\F32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\F32.\DEMOTE\K{\_}\F64` :math:`\hex{B6}` :math:`[\F64] \to [\F32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\F64.\CONVERT\K{\_}\I32\K{\_s}` :math:`\hex{B7}` :math:`[\I32] \to [\F64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\F64.\CONVERT\K{\_}\I32\K{\_u}` :math:`\hex{B8}` :math:`[\I32] \to [\F64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\F64.\CONVERT\K{\_}\I64\K{\_s}` :math:`\hex{B9}` :math:`[\I64] \to [\F64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\F64.\CONVERT\K{\_}\I64\K{\_u}` :math:`\hex{BA}` :math:`[\I64] \to [\F64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\F64.\PROMOTE\K{\_}\F32` :math:`\hex{BB}` :math:`[\F32] \to [\F64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I32.\REINTERPRET\K{\_}\F32` :math:`\hex{BC}` :math:`[\F32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I64.\REINTERPRET\K{\_}\F64` :math:`\hex{BD}` :math:`[\F64] \to [\I64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\F32.\REINTERPRET\K{\_}\I32` :math:`\hex{BE}` :math:`[\I32] \to [\F32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\F64.\REINTERPRET\K{\_}\I64` :math:`\hex{BF}` :math:`[\I64] \to [\F64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I32.\EXTEND\K{8\_s}` :math:`\hex{C0}` :math:`[\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I32.\EXTEND\K{16\_s}` :math:`\hex{C1}` :math:`[\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I64.\EXTEND\K{8\_s}` :math:`\hex{C2}` :math:`[\I64] \to [\I64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I64.\EXTEND\K{16\_s}` :math:`\hex{C3}` :math:`[\I64] \to [\I64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I64.\EXTEND\K{32\_s}` :math:`\hex{C4}` :math:`[\I64] \to [\I64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +(reserved) :math:`\hex{C0}` +(reserved) :math:`\hex{C1}` +(reserved) :math:`\hex{C2}` +(reserved) :math:`\hex{C3}` +(reserved) :math:`\hex{C4}` +(reserved) :math:`\hex{C5}` +(reserved) :math:`\hex{C6}` +(reserved) :math:`\hex{C7}` +(reserved) :math:`\hex{C8}` +(reserved) :math:`\hex{C9}` +(reserved) :math:`\hex{CA}` +(reserved) :math:`\hex{CB}` +(reserved) :math:`\hex{CC}` +(reserved) :math:`\hex{CD}` +(reserved) :math:`\hex{CE}` +(reserved) :math:`\hex{CF}` +:math:`\REFNULL~t` :math:`\hex{D0}` :math:`[] \to [t]` :ref:`validation ` :ref:`execution ` +:math:`\REFISNULL~t` :math:`\hex{D1}` :math:`[t] \to [\I32]` :ref:`validation ` :ref:`execution ` +:math:`\REFFUNC~x` :math:`\hex{D2}` :math:`[] \to [\FUNCREF]` :ref:`validation ` :ref:`execution ` +(reserved) :math:`\hex{D3}` +(reserved) :math:`\hex{D4}` +(reserved) :math:`\hex{D5}` +(reserved) :math:`\hex{D6}` +(reserved) :math:`\hex{D7}` +(reserved) :math:`\hex{D8}` +(reserved) :math:`\hex{D9}` +(reserved) :math:`\hex{DA}` +(reserved) :math:`\hex{DB}` +(reserved) :math:`\hex{DC}` +(reserved) :math:`\hex{DD}` +(reserved) :math:`\hex{DE}` +(reserved) :math:`\hex{DF}` +(reserved) :math:`\hex{F0}` +(reserved) :math:`\hex{F1}` +(reserved) :math:`\hex{F2}` +(reserved) :math:`\hex{F3}` +(reserved) :math:`\hex{F4}` +(reserved) :math:`\hex{F5}` +(reserved) :math:`\hex{F6}` +(reserved) :math:`\hex{F7}` +(reserved) :math:`\hex{F8}` +(reserved) :math:`\hex{F9}` +(reserved) :math:`\hex{FA}` +(reserved) :math:`\hex{FB}` +:math:`\I32.\TRUNC\K{\_sat\_}\F32\K{\_s}` :math:`\hex{FC}~\hex{00}` :math:`[\F32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I32.\TRUNC\K{\_sat\_}\F32\K{\_u}` :math:`\hex{FC}~\hex{01}` :math:`[\F32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I32.\TRUNC\K{\_sat\_}\F64\K{\_s}` :math:`\hex{FC}~\hex{02}` :math:`[\F64] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I32.\TRUNC\K{\_sat\_}\F64\K{\_u}` :math:`\hex{FC}~\hex{03}` :math:`[\F64] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I64.\TRUNC\K{\_sat\_}\F32\K{\_s}` :math:`\hex{FC}~\hex{04}` :math:`[\F32] \to [\I64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I64.\TRUNC\K{\_sat\_}\F32\K{\_u}` :math:`\hex{FC}~\hex{05}` :math:`[\F32] \to [\I64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I64.\TRUNC\K{\_sat}\_\F64\K{\_s}` :math:`\hex{FC}~\hex{06}` :math:`[\F64] \to [\I64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I64.\TRUNC\K{\_sat\_}\F64\K{\_u}` :math:`\hex{FC}~\hex{07}` :math:`[\F64] \to [\I64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\MEMORYINIT` :math:`\hex{FC}~\hex{08}` :math:`[\I32~\I32~\I32] \to []` :ref:`validation ` :ref:`execution ` +:math:`\DATADROP` :math:`\hex{FC}~\hex{09}` :math:`[] \to []` :ref:`validation ` :ref:`execution ` +:math:`\MEMORYCOPY` :math:`\hex{FC}~\hex{0A}` :math:`[\I32~\I32~\I32] \to []` :ref:`validation ` :ref:`execution ` +:math:`\MEMORYFILL` :math:`\hex{FC}~\hex{0B}` :math:`[\I32~\I32~\I32] \to []` :ref:`validation ` :ref:`execution ` +:math:`\TABLEINIT` :math:`\hex{FC}~\hex{0C}` :math:`[\I32~\I32~\I32] \to []` :ref:`validation ` :ref:`execution ` +:math:`\ELEMDROP` :math:`\hex{FC}~\hex{0D}` :math:`[] \to []` :ref:`validation ` :ref:`execution ` +:math:`\TABLECOPY` :math:`\hex{FC}~\hex{0E}` :math:`[\I32~\I32~\I32] \to []` :ref:`validation ` :ref:`execution ` +:math:`\TABLEGROW` :math:`\hex{FC}~\hex{0F}` :math:`[t~\I32] \to []` :ref:`validation ` :ref:`execution ` +:math:`\TABLESIZE` :math:`\hex{FC}~\hex{10}` :math:`[] \to []` :ref:`validation ` :ref:`execution ` +:math:`\TABLEFILL` :math:`\hex{FC}~\hex{11}` :math:`[\I32~t~\I32] \to []` :ref:`validation ` :ref:`execution ` +(reserved) :math:`\hex{FD}` +(reserved) :math:`\hex{FE}` +(reserved) :math:`\hex{FF}` +========================================= ========================= ============================================= ======================================== =============================================================== diff --git a/document/core/appendix/index-rules.rst b/document/core/appendix/index-rules.rst index 1beabe35a2..dde34900e8 100644 --- a/document/core/appendix/index-rules.rst +++ b/document/core/appendix/index-rules.rst @@ -15,6 +15,7 @@ Construct Judgement =============================================== =============================================================================== :ref:`Limits ` :math:`\vdashlimits \limits : k` :ref:`Function type ` :math:`\vdashfunctype \functype \ok` +:ref:`Block type ` :math:`\vdashblocktype \blocktype \ok` :ref:`Table type ` :math:`\vdashtabletype \tabletype \ok` :ref:`Memory type ` :math:`\vdashmemtype \memtype \ok` :ref:`Global type ` :math:`\vdashglobaltype \globaltype \ok` diff --git a/document/core/appendix/properties.rst b/document/core/appendix/properties.rst index f62e02b38d..30cb620c95 100644 --- a/document/core/appendix/properties.rst +++ b/document/core/appendix/properties.rst @@ -431,17 +431,17 @@ Finally, :ref:`frames ` are classified with *frame contexts*, whic * The :ref:`store ` :math:`S` must be :ref:`valid `. * Under no allowed return type, - the :ref:`thread ` :math:`T` must be :ref:`valid ` with some :ref:`result type ` :math:`[t^?]`. + the :ref:`thread ` :math:`T` must be :ref:`valid ` with some :ref:`result type ` :math:`[t^\ast]`. -* Then the configuration is valid with the :ref:`result type ` :math:`[t^?]`. +* Then the configuration is valid with the :ref:`result type ` :math:`[t^\ast]`. .. math:: \frac{ \vdashstore S \ok \qquad - S; \epsilon \vdashthread T : [t^?] + S; \epsilon \vdashthread T : [t^\ast] }{ - \vdashconfig S; T : [t^?] + \vdashconfig S; T : [t^\ast] } @@ -458,17 +458,17 @@ Finally, :ref:`frames ` are classified with *frame contexts*, whic * Let :math:`C'` be the same :ref:`context ` as :math:`C`, but with |CRETURN| set to :math:`\resulttype^?`. * Under context :math:`C'`, - the instruction sequence :math:`\instr^\ast` must be :ref:`valid ` with some type :math:`[] \to [t^?]`. + the instruction sequence :math:`\instr^\ast` must be :ref:`valid ` with some type :math:`[] \to [t^\ast]`. -* Then the thread is valid with the :ref:`result type ` :math:`[t^?]`. +* Then the thread is valid with the :ref:`result type ` :math:`[t^\ast]`. .. math:: \frac{ S \vdashframe F : C \qquad - S; C,\CRETURN~\resulttype^? \vdashinstrseq \instr^\ast : [] \to [t^?] + S; C,\CRETURN~\resulttype^? \vdashinstrseq \instr^\ast : [] \to [t^\ast] }{ - S; \resulttype^? \vdashthread F; \instr^\ast : [t^?] + S; \resulttype^? \vdashthread F; \instr^\ast : [t^\ast] } @@ -576,22 +576,22 @@ To that end, all previous typing judgements :math:`C \vdash \X{prop}` are genera :math:`\LABEL_n\{\instr_0^\ast\}~\instr^\ast~\END` .................................................. -* The instruction sequence :math:`\instr_0^\ast` must be :ref:`valid ` with some type :math:`[t_1^n] \to [t_2^?]`. +* The instruction sequence :math:`\instr_0^\ast` must be :ref:`valid ` with some type :math:`[t_1^n] \to [t_2^*]`. * Let :math:`C'` be the same :ref:`context ` as :math:`C`, but with the :ref:`result type ` :math:`[t_1^n]` prepended to the |CLABELS| vector. * Under context :math:`C'`, - the instruction sequence :math:`\instr^\ast` must be :ref:`valid ` with type :math:`[] \to [t_2^?]`. + the instruction sequence :math:`\instr^\ast` must be :ref:`valid ` with type :math:`[] \to [t_2^*]`. -* Then the compound instruction is valid with type :math:`[] \to [t_2^?]`. +* Then the compound instruction is valid with type :math:`[] \to [t_2^*]`. .. math:: \frac{ - S; C \vdashinstrseq \instr_0^\ast : [t_1^n] \to [t_2^?] + S; C \vdashinstrseq \instr_0^\ast : [t_1^n] \to [t_2^*] \qquad - S; C,\CLABELS\,[t_1^n] \vdashinstrseq \instr^\ast : [] \to [t_2^?] + S; C,\CLABELS\,[t_1^n] \vdashinstrseq \instr^\ast : [] \to [t_2^*] }{ - S; C \vdashadmininstr \LABEL_n\{\instr_0^\ast\}~\instr^\ast~\END : [] \to [t_2^?] + S; C \vdashadmininstr \LABEL_n\{\instr_0^\ast\}~\instr^\ast~\END : [] \to [t_2^*] } diff --git a/document/core/binary/instructions.rst b/document/core/binary/instructions.rst index a6fba1328b..b6c60661f4 100644 --- a/document/core/binary/instructions.rst +++ b/document/core/binary/instructions.rst @@ -13,8 +13,9 @@ The only exception are :ref:`structured control instructions ` have varying encodings. For structured instructions, the instruction sequences forming nested blocks are terminated with explicit opcodes for |END| and |ELSE|. +:ref:`Block types ` are encoded in special compressed form, by either the byte :math:`\hex{40}` indicating the empty type, as a single :ref:`value type `, or as a :ref:`type index ` encoded as a positive :ref:`signed integer `. + +.. _binary-blocktype: .. _binary-nop: .. _binary-unreachable: .. _binary-block: @@ -35,19 +39,23 @@ Control Instructions .. _binary-call_indirect: .. math:: - \begin{array}{llclll} + \begin{array}{llcllll} + \production{block type} & \Bblocktype &::=& + \hex{40} &\Rightarrow& \epsilon \\ &&|& + t{:}\Bvaltype &\Rightarrow& t \\ &&|& + x{:}\Bs33 &\Rightarrow& x & (\iff x \geq 0) \\ \production{instruction} & \Binstr &::=& \hex{00} &\Rightarrow& \UNREACHABLE \\ &&|& \hex{01} &\Rightarrow& \NOP \\ &&|& - \hex{02}~~\X{rt}{:}\Bblocktype~~(\X{in}{:}\Binstr)^\ast~~\hex{0B} - &\Rightarrow& \BLOCK~\X{rt}~\X{in}^\ast~\END \\ &&|& - \hex{03}~~\X{rt}{:}\Bblocktype~~(\X{in}{:}\Binstr)^\ast~~\hex{0B} - &\Rightarrow& \LOOP~\X{rt}~\X{in}^\ast~\END \\ &&|& - \hex{04}~~\X{rt}{:}\Bblocktype~~(\X{in}{:}\Binstr)^\ast~~\hex{0B} - &\Rightarrow& \IF~\X{rt}~\X{in}^\ast~\ELSE~\epsilon~\END \\ &&|& - \hex{04}~~\X{rt}{:}\Bblocktype~~(\X{in}_1{:}\Binstr)^\ast~~ + \hex{02}~~\X{bt}{:}\Bblocktype~~(\X{in}{:}\Binstr)^\ast~~\hex{0B} + &\Rightarrow& \BLOCK~\X{bt}~\X{in}^\ast~\END \\ &&|& + \hex{03}~~\X{bt}{:}\Bblocktype~~(\X{in}{:}\Binstr)^\ast~~\hex{0B} + &\Rightarrow& \LOOP~\X{bt}~\X{in}^\ast~\END \\ &&|& + \hex{04}~~\X{bt}{:}\Bblocktype~~(\X{in}{:}\Binstr)^\ast~~\hex{0B} + &\Rightarrow& \IF~\X{bt}~\X{in}^\ast~\ELSE~\epsilon~\END \\ &&|& + \hex{04}~~\X{bt}{:}\Bblocktype~~(\X{in}_1{:}\Binstr)^\ast~~ \hex{05}~~(\X{in}_2{:}\Binstr)^\ast~~\hex{0B} - &\Rightarrow& \IF~\X{rt}~\X{in}_1^\ast~\ELSE~\X{in}_2^\ast~\END \\ &&|& + &\Rightarrow& \IF~\X{bt}~\X{in}_1^\ast~\ELSE~\X{in}_2^\ast~\END \\ &&|& \hex{0C}~~l{:}\Blabelidx &\Rightarrow& \BR~l \\ &&|& \hex{0D}~~l{:}\Blabelidx &\Rightarrow& \BRIF~l \\ &&|& \hex{0E}~~l^\ast{:}\Bvec(\Blabelidx)~~l_N{:}\Blabelidx @@ -60,6 +68,12 @@ Control Instructions .. note:: The |ELSE| opcode :math:`\hex{05}` in the encoding of an |IF| instruction can be omitted if the following instruction sequence is empty. + Unlike any :ref:`other occurrence `, the :ref:`type index ` in a :ref:`block type ` is encoded as a positive :ref:`signed integer `, so that its |SignedLEB128| bit pattern cannot collide with the encoding of :ref:`value types ` or the special code :math:`\hex{40}`, which correspond to the LEB128 encoding of negative integers. + To avoid any loss in the range of allowed indices, it is treated as a 33 bit signed integer. + + In future versions of WebAssembly, the zero byte occurring in the encoding + of the |CALLINDIRECT| instruction may be used to index additional tables. + .. index:: reference instruction pair: binary format; instruction @@ -424,6 +438,34 @@ All other numeric instructions are plain opcodes without any immediates. \hex{BF} &\Rightarrow& \F64.\REINTERPRET\K{\_}\I64 \\ \end{array} +.. _binary-cvtop-trunc-sat: + +The saturating truncation instructions all have a one byte prefix. + +.. math:: + \begin{array}{llclll} + \production{instruction} & \Binstr &::=& \dots && \phantom{thisshouldbeenough} \\&&|& + \hex{FC}~\hex{00} &\Rightarrow& \I32.\TRUNC\K{\_sat\_}\F32\K{\_s} \\ &&|& + \hex{FC}~\hex{01} &\Rightarrow& \I32.\TRUNC\K{\_sat\_}\F32\K{\_u} \\ &&|& + \hex{FC}~\hex{02} &\Rightarrow& \I32.\TRUNC\K{\_sat\_}\F64\K{\_s} \\ &&|& + \hex{FC}~\hex{03} &\Rightarrow& \I32.\TRUNC\K{\_sat\_}\F64\K{\_u} \\ &&|& + \hex{FC}~\hex{04} &\Rightarrow& \I64.\TRUNC\K{\_sat\_}\F32\K{\_s} \\ &&|& + \hex{FC}~\hex{05} &\Rightarrow& \I64.\TRUNC\K{\_sat\_}\F32\K{\_u} \\ &&|& + \hex{FC}~\hex{06} &\Rightarrow& \I64.\TRUNC\K{\_sat\_}\F64\K{\_s} \\ &&|& + \hex{FC}~\hex{07} &\Rightarrow& \I64.\TRUNC\K{\_sat\_}\F64\K{\_u} \\ + \end{array} + + +.. math:: + \begin{array}{llclll} + \phantom{\production{instruction}} & \phantom{\Binstr} &\phantom{::=}& \phantom{\dots} && \phantom{thisshouldbeenough} \\[-2ex] &&|& + \hex{C0} &\Rightarrow& \I32.\EXTEND\K{8\_s} \\ &&|& + \hex{C1} &\Rightarrow& \I32.\EXTEND\K{16\_s} \\ &&|& + \hex{C2} &\Rightarrow& \I64.\EXTEND\K{8\_s} \\ &&|& + \hex{C3} &\Rightarrow& \I64.\EXTEND\K{16\_s} \\ &&|& + \hex{C4} &\Rightarrow& \I64.\EXTEND\K{32\_s} \\ + \end{array} + .. index:: expression pair: binary format; expression diff --git a/document/core/binary/types.rst b/document/core/binary/types.rst index 5154e4d8e4..7c462e029c 100644 --- a/document/core/binary/types.rst +++ b/document/core/binary/types.rst @@ -63,29 +63,25 @@ Value Types \end{array} .. note:: - The type :math:`\BOT` cannot occur in a module. + Value types can occur in contexts where :ref:`type indices ` are also allowed, such as in the case of :ref:`block types `. + Thus, the binary format for types corresponds to the |SignedLEB128|_ :ref:`encoding ` of small negative :math:`\sN` values, so that they can coexist with (positive) type indices in the future. .. index:: result type, value type pair: binary format; result type -.. _binary-blocktype: .. _binary-resulttype: Result Types ~~~~~~~~~~~~ -The only :ref:`result types ` occurring in the binary format are the types of blocks. These are encoded in special compressed form, by either the byte :math:`\hex{40}` indicating the empty type or as a single :ref:`value type `. +:ref:`Result types ` are encoded by the respective :ref:`vectors ` of :ref:`value types ``. .. math:: \begin{array}{llclll@{\qquad\qquad}l} - \production{result type} & \Bblocktype &::=& - \hex{40} &\Rightarrow& [] \\ &&|& - t{:}\Bvaltype &\Rightarrow& [t] \\ + \production{result type} & \Bresulttype &::=& + t^\ast{:\,}\Bvec(\Bvaltype) &\Rightarrow& [t^\ast] \\ \end{array} -.. note:: - In future versions of WebAssembly, this scheme may be extended to support multiple results or more general block types. - .. index:: function type, value type, result type pair: binary format; function type @@ -99,8 +95,8 @@ Function Types .. math:: \begin{array}{llclll@{\qquad\qquad}l} \production{function type} & \Bfunctype &::=& - \hex{60}~~t_1^\ast{:\,}\Bvec(\Bvaltype)~~t_2^\ast{:\,}\Bvec(\Bvaltype) - &\Rightarrow& [t_1^\ast] \to [t_2^\ast] \\ + \hex{60}~~\X{rt}_1{:\,}\Bresulttype~~\X{rt}_2{:\,}\Bresulttype + &\Rightarrow& \X{rt}_1 \to \X{rt}_2 \\ \end{array} diff --git a/document/core/conf.py b/document/core/conf.py index 056ba446aa..5f85c59ef6 100644 --- a/document/core/conf.py +++ b/document/core/conf.py @@ -68,7 +68,7 @@ # built documents. # # The short X.Y version. -version = u'1.0' +version = u'1.1' # The full version, including alpha/beta/rc tags. release = version + '' diff --git a/document/core/exec/instructions.rst b/document/core/exec/instructions.rst index ba0ade50d1..dd364c28ec 100644 --- a/document/core/exec/instructions.rst +++ b/document/core/exec/instructions.rst @@ -1526,70 +1526,92 @@ Control Instructions .. _exec-block: -:math:`\BLOCK~[t^?]~\instr^\ast~\END` -..................................... +:math:`\BLOCK~\blocktype~\instr^\ast~\END` +.......................................... + +1. Assert: due to :ref:`validation `, :math:`\expand_F(\blocktype)` is defined. + +2. Let :math:`[t_1^m] \to [t_2^n]` be the :ref:`function type ` :math:`\expand_F(\blocktype)`. + +3. Let :math:`L` be the label whose arity is :math:`n` and whose continuation is the end of the block. -1. Let :math:`n` be the arity :math:`|t^?|` of the :ref:`result type ` :math:`t^?`. +4. Assert: due to :ref:`validation `, there are at least :math:`m` values on the top of the stack. -2. Let :math:`L` be the label whose arity is :math:`n` and whose continuation is the end of the block. +5. Pop the values :math:`\val^m` from the stack. -3. :ref:`Enter ` the block :math:`\instr^\ast` with label :math:`L`. +6. :ref:`Enter ` the block :math:`\val^m~\instr^\ast` with label :math:`L`. .. math:: ~\\[-1ex] \begin{array}{lcl@{\qquad}l} - \BLOCK~[t^n]~\instr^\ast~\END &\stepto& - \LABEL_n\{\epsilon\}~\instr^\ast~\END + F; \val^m~\BLOCK~\X{bt}~\instr^\ast~\END &\stepto& + F; \LABEL_n\{\epsilon\}~\val^m~\instr^\ast~\END + & (\iff \expand_F(\X{bt}) = [t_1^m] \to [t_2^n]) \end{array} .. _exec-loop: -:math:`\LOOP~[t^?]~\instr^\ast~\END` -.................................... +:math:`\LOOP~\blocktype~\instr^\ast~\END` +......................................... + +1. Assert: due to :ref:`validation `, :math:`\expand_F(\blocktype)` is defined. + +2. Let :math:`[t_1^m] \to [t_2^n]` be the :ref:`function type ` :math:`\expand_F(\blocktype)`. + +3. Let :math:`L` be the label whose arity is :math:`m` and whose continuation is the start of the loop. + +4. Assert: due to :ref:`validation `, there are at least :math:`m` values on the top of the stack. -1. Let :math:`L` be the label whose arity is :math:`0` and whose continuation is the start of the loop. +5. Pop the values :math:`\val^m` from the stack. -2. :ref:`Enter ` the block :math:`\instr^\ast` with label :math:`L`. +6. :ref:`Enter ` the block :math:`\val^m~\instr^\ast` with label :math:`L`. .. math:: ~\\[-1ex] \begin{array}{lcl@{\qquad}l} - \LOOP~[t^?]~\instr^\ast~\END &\stepto& - \LABEL_0\{\LOOP~[t^?]~\instr^\ast~\END\}~\instr^\ast~\END + F; \val^m~\LOOP~\X{bt}~\instr^\ast~\END &\stepto& + F; \LABEL_m\{\LOOP~\X{bt}~\instr^\ast~\END\}~\val^m~\instr^\ast~\END + & (\iff \expand_F(\X{bt}) = [t_1^m] \to [t_2^n]) \end{array} .. _exec-if: -:math:`\IF~[t^?]~\instr_1^\ast~\ELSE~\instr_2^\ast~\END` -........................................................ +:math:`\IF~\blocktype~\instr_1^\ast~\ELSE~\instr_2^\ast~\END` +............................................................. -1. Assert: due to :ref:`validation `, a value of :ref:`value type ` |I32| is on the top of the stack. +1. Assert: due to :ref:`validation `, :math:`\expand_F(\blocktype)` is defined. -2. Pop the value :math:`\I32.\CONST~c` from the stack. +2. Let :math:`[t_1^m] \to [t_2^n]` be the :ref:`function type ` :math:`\expand_F(\blocktype)`. + +3. Let :math:`L` be the label whose arity is :math:`n` and whose continuation is the end of the |IF| instruction. + +4. Assert: due to :ref:`validation `, a value of :ref:`value type ` |I32| is on the top of the stack. -3. Let :math:`n` be the arity :math:`|t^?|` of the :ref:`result type ` :math:`t^?`. +5. Pop the value :math:`\I32.\CONST~c` from the stack. -4. Let :math:`L` be the label whose arity is :math:`n` and whose continuation is the end of the |IF| instruction. +6. Assert: due to :ref:`validation `, there are at least :math:`m` values on the top of the stack. -5. If :math:`c` is non-zero, then: +7. Pop the values :math:`\val^m` from the stack. - a. :ref:`Enter ` the block :math:`\instr_1^\ast` with label :math:`L`. +8. If :math:`c` is non-zero, then: -6. Else: + a. :ref:`Enter ` the block :math:`\val^m~\instr_1^\ast` with label :math:`L`. - a. :ref:`Enter ` the block :math:`\instr_2^\ast` with label :math:`L`. +9. Else: + + a. :ref:`Enter ` the block :math:`\val^m~\instr_2^\ast` with label :math:`L`. .. math:: ~\\[-1ex] \begin{array}{lcl@{\qquad}l} - (\I32.\CONST~c)~\IF~[t^n]~\instr_1^\ast~\ELSE~\instr_2^\ast~\END &\stepto& - \LABEL_n\{\epsilon\}~\instr_1^\ast~\END - & (\iff c \neq 0) \\ - (\I32.\CONST~c)~\IF~[t^n]~\instr_1^\ast~\ELSE~\instr_2^\ast~\END &\stepto& - \LABEL_n\{\epsilon\}~\instr_2^\ast~\END - & (\iff c = 0) \\ + F; \val^m~(\I32.\CONST~c)~\IF~\X{bt}~\instr_1^\ast~\ELSE~\instr_2^\ast~\END &\stepto& + F; \LABEL_n\{\epsilon\}~\val^m~\instr_1^\ast~\END + & (\iff c \neq 0 \wedge \expand_F(\X{bt}) = [t_1^m] \to [t_2^n]) \\ + F; \val^m~(\I32.\CONST~c)~\IF~\X{bt}~\instr_1^\ast~\ELSE~\instr_2^\ast~\END &\stepto& + F; \LABEL_n\{\epsilon\}~\val^m~\instr_2^\ast~\END + & (\iff c = 0 \wedge \expand_F(\X{bt}) = [t_1^m] \to [t_2^n]) \\ \end{array} @@ -1884,33 +1906,34 @@ Invocation of :ref:`function address ` :math:`a` 3. Let :math:`[t_1^n] \to [t_2^m]` be the :ref:`function type ` :math:`f.\FITYPE`. -4. Assert: due to :ref:`validation `, :math:`m \leq 1`. +4. Let :math:`t^\ast` be the list of :ref:`value types ` :math:`f.\FICODE.\FLOCALS`. -5. Let :math:`t^\ast` be the list of :ref:`value types ` :math:`f.\FICODE.\FLOCALS`. +5. Let :math:`\instr^\ast~\END` be the :ref:`expression ` :math:`f.\FICODE.\FBODY`. -6. Let :math:`\instr^\ast~\END` be the :ref:`expression ` :math:`f.\FICODE.\FBODY`. +6. Assert: due to :ref:`validation `, :math:`n` values are on the top of the stack. -7. Assert: due to :ref:`validation `, :math:`n` values are on the top of the stack. +7. Pop the values :math:`\val^n` from the stack. -8. Pop the values :math:`\val^n` from the stack. +8. Let :math:`\val_0^\ast` be the list of zero values of types :math:`t^\ast`. 9. Let :math:`F` be the :ref:`frame ` :math:`\{ \AMODULE~f.\FIMODULE, \ALOCALS~\val^n~(\default_t)^\ast \}`. 10. Push the activation of :math:`F` with arity :math:`m` to the stack. -11. :ref:`Execute ` the instruction :math:`\BLOCK~[t_2^m]~\instr^\ast~\END`. +11. Let :math:`L` be the :ref:`label ` whose arity is :math:`m` and whose continuation is the end of the function. + +12. :ref:`Enter ` the instruction sequence :math:`\instr^\ast` with label :math:`L`. .. math:: ~\\[-1ex] \begin{array}{l} \begin{array}{lcl@{\qquad}l} - S; \val^n~(\INVOKE~a) &\stepto& S; \FRAME_m\{F\}~\BLOCK~[t_2^m]~\instr^\ast~\END~\END + S; \val^n~(\INVOKE~a) &\stepto& S; \FRAME_m\{F\}~\LABEL_m\{\}~\instr^\ast~\END~\END \end{array} \\ \qquad \begin{array}[t]{@{}r@{~}l@{}} (\iff & S.\SFUNCS[a] = f \\ \wedge & f.\FITYPE = [t_1^n] \to [t_2^m] \\ - \wedge & m \leq 1 \\ \wedge & f.\FICODE = \{ \FTYPE~x, \FLOCALS~t^k, \FBODY~\instr^\ast~\END \} \\ \wedge & F = \{ \AMODULE~f.\FIMODULE, ~\ALOCALS~\val^n~(\default_t)^k \}) \end{array} \\ diff --git a/document/core/exec/numerics.rst b/document/core/exec/numerics.rst index b83ef1cee9..cd5596a904 100644 --- a/document/core/exec/numerics.rst +++ b/document/core/exec/numerics.rst @@ -612,6 +612,19 @@ The integer result of predicates -- i.e., :ref:`tests ` and :ref: \end{array} +.. _op-iextendn_s: + +:math:`\iextendMs_N(i)` +....................... + +* Return :math:`\extends_{M,N}(i)`. + +.. math:: + \begin{array}{lll@{\qquad}l} + \iextendMs_{N}(i) &=& \extends_{M,N}(i) \\ + \end{array} + + .. index:: floating-point, IEEE 754 .. _float-ops: @@ -1464,6 +1477,62 @@ Conversions It is not defined for NaNs, infinities, or values for which the result is out of range. +.. _op-trunc_sat_u: + +:math:`\truncsatu_{M,N}(z)` +........................... + +* If :math:`z` is a NaN, then return :math:`0`. + +* Else if :math:`z` is negative infinity, then return :math:`0`. + +* Else if :math:`z` is positive infinity, then return :math:`2^N - 1`. + +* Else if :math:`\trunc(z)` is less than :math:`0`, then return :math:`0`. + +* Else if :math:`\trunc(z)` is greater than :math:`2^N - 1`, then return :math:`2^N - 1`. + +* Else, return :math:`\trunc(z)`. + +.. math:: + \begin{array}{lll@{\qquad}l} + \truncsatu_{M,N}(\pm \NAN(n)) &=& 0 \\ + \truncsatu_{M,N}(- \infty) &=& 0 \\ + \truncsatu_{M,N}(+ \infty) &=& 2^N - 1 \\ + \truncsatu_{M,N}(- q) &=& 0 & (\iff \trunc(- q) < 0) \\ + \truncsatu_{M,N}(+ q) &=& 2^N - 1 & (\iff \trunc(+ q) > 2^N - 1) \\ + \truncsatu_{M,N}(\pm q) &=& \trunc(\pm q) & (otherwise) \\ + \end{array} + + +.. _op-trunc_sat_s: + +:math:`\truncsats_{M,N}(z)` +........................... + +* If :math:`z` is a NaN, then return :math:`0`. + +* Else if :math:`z` is negative infinity, then return :math:`-2^{N-1}`. + +* Else if :math:`z` is positive infinity, then return :math:`2^{N-1} - 1`. + +* Else if :math:`\trunc(z)` is less than :math:`-2^{N-1}`, then return :math:`-2^{N-1}`. + +* Else if :math:`\trunc(z)` is greater than :math:`2^{N-1} - 1`, then return :math:`2^{N-1} - 1`. + +* Else, return :math:`\trunc(z)`. + +.. math:: + \begin{array}{lll@{\qquad}l} + \truncsats_{M,N}(\pm \NAN(n)) &=& 0 \\ + \truncsats_{M,N}(- \infty) &=& -2^{N-1} \\ + \truncsats_{M,N}(+ \infty) &=& 2^{N-1}-1 \\ + \truncsats_{M,N}(- q) &=& -2^{N-1} & (\iff \trunc(- q) < -2^{N-1}) \\ + \truncsats_{M,N}(+ q) &=& 2^{N-1} - 1 & (\iff \trunc(+ q) > 2^{N-1} - 1) \\ + \truncsats_{M,N}(\pm q) &=& \trunc(\pm q) & (otherwise) \\ + \end{array} + + .. _op-promote: :math:`\promote_{M,N}(z)` diff --git a/document/core/exec/runtime.rst b/document/core/exec/runtime.rst index 568739e436..43c66efe25 100644 --- a/document/core/exec/runtime.rst +++ b/document/core/exec/runtime.rst @@ -414,6 +414,7 @@ It filters out entries of a specific kind in an order-preserving fashion: * :math:`\evglobals(\externval^\ast) = [\globaladdr ~|~ (\EVGLOBAL~\globaladdr) \in \externval^\ast]` + .. index:: ! stack, ! frame, ! label, instruction, store, activation, function, call, local, module instance pair: abstract syntax; frame pair: abstract syntax; label @@ -465,7 +466,7 @@ Intuitively, :math:`\instr^\ast` is the *continuation* to execute when the branc For example, a loop label has the form .. math:: - \LABEL_n\{\LOOP~[t^?]~\dots~\END\} + \LABEL_n\{\LOOP~\dots~\END\} When performing a branch to this label, this executes the loop, effectively restarting it from the beginning. Conversely, a simple block label has the form @@ -500,9 +501,13 @@ Conventions * The meta variable :math:`F` ranges over frames where clear from context. -.. note:: - In the current version of WebAssembly, the arities of labels and frames cannot be larger than :math:`1`. - This may be generalized in future versions. +* The following auxiliary definition takes a :ref:`block type ` and looks up the :ref:`function type ` that it denotes in the current frame: + +.. math:: + \begin{array}{lll} + \expand_F(\typeidx) &=& F.\AMODULE.\MITYPES[\typeidx] \\ + \expand_F([\valtype^?]) &=& [] \to [\valtype^?] \\ + \end{array} .. index:: ! administrative instructions, function, function instance, function address, label, frame, instruction, trap, call, memory, memory instance, table, table instance, element, data, segment diff --git a/document/core/syntax/instructions.rst b/document/core/syntax/instructions.rst index fd29a890c3..03db47d3cc 100644 --- a/document/core/syntax/instructions.rst +++ b/document/core/syntax/instructions.rst @@ -9,11 +9,6 @@ WebAssembly code consists of sequences of *instructions*. Its computational model is based on a *stack machine* in that instructions manipulate values on an implicit *operand stack*, consuming (popping) argument values and producing or returning (pushing) result values. -.. note:: - In the current version of WebAssembly, - at most one result value can be pushed by a single instruction. - This restriction may be lifted in future versions. - In addition to dynamic operands from the stack, some instructions also have static *immediate* arguments, typically :ref:`indices ` or type annotations, which are part of the instruction itself. @@ -64,9 +59,13 @@ These operations closely match respective operations available in hardware. \K{i}\X{nn}\K{.}\itestop \\&&|& \K{i}\X{nn}\K{.}\irelop ~|~ \K{f}\X{nn}\K{.}\frelop \\&&|& + \K{i}\X{nn}\K{.}\EXTEND\K{8\_s} ~|~ + \K{i}\X{nn}\K{.}\EXTEND\K{16\_s} ~|~ + \K{i64.}\EXTEND\K{32\_s} \\&&|& \K{i32.}\WRAP\K{\_i64} ~|~ \K{i64.}\EXTEND\K{\_i32}\K{\_}\sx ~|~ \K{i}\X{nn}\K{.}\TRUNC\K{\_f}\X{mm}\K{\_}\sx \\&&|& + \K{i}\X{nn}\K{.}\TRUNC\K{\_sat\_f}\X{mm}\K{\_}\sx \\&&|& \K{f32.}\DEMOTE\K{\_f64} ~|~ \K{f64.}\PROMOTE\K{\_f32} ~|~ \K{f}\X{nn}\K{.}\CONVERT\K{\_i}\X{mm}\K{\_}\sx \\&&|& @@ -152,7 +151,10 @@ Occasionally, it is convenient to group operators together according to the foll .. math:: \begin{array}{llll} - \production{unary operator} & \unop &::=& \iunop ~|~ \funop \\ + \production{unary operator} & \unop &::=& + \iunop ~|~ + \funop ~|~ + \EXTEND{N}\K{\_s} \\ \production{binary operator} & \binop &::=& \ibinop ~|~ \fbinop \\ \production{test operator} & \testop &::=& \itestop \\ \production{relational operator} & \relop &::=& \irelop ~|~ \frelop \\ @@ -160,6 +162,7 @@ Occasionally, it is convenient to group operators together according to the foll \WRAP ~|~ \EXTEND ~|~ \TRUNC ~|~ + \TRUNC\K{\_sat} ~|~ \CONVERT ~|~ \DEMOTE ~|~ \PROMOTE ~|~ @@ -347,8 +350,11 @@ The |DATADROP| instruction prevents further use of a passive data segment. This This restriction may be lifted in future versions. -.. index:: ! control instruction, ! structured control, ! label, ! block, ! branch, ! unwinding, result type, label index, function index, type index, vector, trap, function, table, function type +.. index:: ! control instruction, ! structured control, ! label, ! block, ! block type, ! branch, ! unwinding, result type, label index, function index, type index, vector, trap, function, table, function type, value type, type index pair: abstract syntax; instruction + pair: abstract syntax; block type + pair: block; type +.. _syntax-blocktype: .. _syntax-nop: .. _syntax-unreachable: .. _syntax-block: @@ -370,13 +376,15 @@ Instructions in this group affect the flow of control. .. math:: \begin{array}{llcl} + \production{block type} & \blocktype &::=& + \typeidx ~|~ \valtype^? \\ \production{instruction} & \instr &::=& \dots \\&&|& \NOP \\&&|& \UNREACHABLE \\&&|& - \BLOCK~\resulttype~\instr^\ast~\END \\&&|& - \LOOP~\resulttype~\instr^\ast~\END \\&&|& - \IF~\resulttype~\instr^\ast~\ELSE~\instr^\ast~\END \\&&|& + \BLOCK~\blocktype~\instr^\ast~\END \\&&|& + \LOOP~\blocktype~\instr^\ast~\END \\&&|& + \IF~\blocktype~\instr^\ast~\ELSE~\instr^\ast~\END \\&&|& \BR~\labelidx \\&&|& \BRIF~\labelidx \\&&|& \BRTABLE~\vec(\labelidx)~\labelidx \\&&|& @@ -392,7 +400,9 @@ The |UNREACHABLE| instruction causes an unconditional :ref:`trap `. The |BLOCK|, |LOOP| and |IF| instructions are *structured* instructions. They bracket nested sequences of instructions, called *blocks*, terminated with, or separated by, |END| or |ELSE| pseudo-instructions. As the grammar prescribes, they must be well-nested. -A structured instruction can produce a value as described by the annotated :ref:`result type `. + +A structured instruction can consume *input* and produce *output* on the operand stack according to its annotated *block type*. +It is given either as a :ref:`type index ` that refers to a suitable :ref:`function type `, or as an optional :ref:`value type ` inline, which is a shorthand for the function type :math:`[] \to [\valtype^?]`. Each structured control instruction introduces an implicit *label*. Labels are targets for branch instructions that reference them with :ref:`label indices `. @@ -418,7 +428,9 @@ Branch instructions come in several flavors: and |BRTABLE| performs an indirect branch through an operand indexing into the label vector that is an immediate to the instruction, or to a default target if the operand is out of bounds. The |RETURN| instruction is a shortcut for an unconditional branch to the outermost block, which implicitly is the body of the current function. Taking a branch *unwinds* the operand stack up to the height where the targeted structured control instruction was entered. -However, forward branches that target a control instruction with a non-empty result type consume matching operands first and push them back on the operand stack after unwinding, as a result for the terminated structured instruction. +However, branches may additionally consume operands themselves, which they push back on the operand stack after unwinding. +Forward branches require operands according to the output of the targeted block's type, i.e., represent the values produced by the terminated block. +Backward branches require operands according to the input of the targeted block's type, i.e., represent the values consumed by the restarted block. The |CALL| instruction invokes another :ref:`function `, consuming the necessary arguments from the stack and returning the result values of the call. The |CALLINDIRECT| instruction calls a function indirectly through an operand indexing into a :ref:`table ` that is denoted by a :ref:`table index ` and must have type |FUNCREF|. diff --git a/document/core/syntax/types.rst b/document/core/syntax/types.rst index 258224247f..5a6c3d92ba 100644 --- a/document/core/syntax/types.rst +++ b/document/core/syntax/types.rst @@ -88,7 +88,7 @@ Conventions * The meta variable :math:`t` ranges over value types or subclasses thereof where clear from context. -.. index:: ! result type, value type, instruction, execution, block +.. index:: ! result type, value type, instruction, execution, function pair: abstract syntax; result type pair: result; type .. _syntax-resulttype: @@ -96,21 +96,17 @@ Conventions Result Types ~~~~~~~~~~~~ -*Result types* classify the result of :ref:`executing ` :ref:`instructions ` or :ref:`blocks `, +*Result types* classify the result of :ref:`executing ` :ref:`instructions ` or :ref:`functions `, which is a sequence of values written with brackets. .. math:: \begin{array}{llll} \production{result type} & \resulttype &::=& - [\valtype^?] \\ + [\vec(\valtype)] \\ \end{array} -.. note:: - In the current version of WebAssembly, at most one value is allowed as a result. - However, this may be generalized to sequences of values in future versions. - -.. index:: ! function type, value type, vector, function, parameter, result +.. index:: ! function type, value type, vector, function, parameter, result, result type pair: abstract syntax; function type pair: function; type .. _syntax-functype: @@ -119,19 +115,15 @@ Function Types ~~~~~~~~~~~~~~ *Function types* classify the signature of :ref:`functions `, -mapping a vector of parameters to a vector of results, written as follows. +mapping a vector of parameters to a vector of results. +They are also used to classify the inputs and outputs of :ref:`instructions `. .. math:: \begin{array}{llll} \production{function type} & \functype &::=& - [\vec(\valtype)] \to [\vec(\valtype)] \\ + \resulttype \to \resulttype \\ \end{array} -.. note:: - In the current version of WebAssembly, - the length of the result type vector of a :ref:`valid ` function type may be at most :math:`1`. - This restriction may be removed in future versions. - .. index:: ! limits, memory type, table type pair: abstract syntax; limits diff --git a/document/core/text/instructions.rst b/document/core/text/instructions.rst index d27370fe86..786f263073 100644 --- a/document/core/text/instructions.rst +++ b/document/core/text/instructions.rst @@ -52,6 +52,7 @@ The following grammar handles the corresponding update to the :ref:`identifier c Control Instructions ~~~~~~~~~~~~~~~~~~~~ +.. _text-blocktype: .. _text-block: .. _text-loop: .. _text-if: @@ -60,21 +61,35 @@ Control Instructions :ref:`Structured control instructions ` can bind an optional symbolic :ref:`label identifier `. The same label identifier may optionally be repeated after the corresponding :math:`\T{end}` and :math:`\T{else}` pseudo instructions, to indicate the matching delimiters. +Their :ref:`block type ` is given as a :ref:`type use `, analogous to the type of :ref:`functions `. +However, the special case of a type use that is syntactically empty or consists of only a single :ref:`result ` is not regarded as an :ref:`abbreviation ` for an inline :ref:`function type `, but is parsed directly into an optional :ref:`value type `. + .. math:: \begin{array}{llclll} + \production{block type} & \Tblocktype_I & + \begin{array}[t]{@{}c@{}} ::= \\ | \\ \end{array} + & + \begin{array}[t]{@{}lcll@{}} + (t{:}\Tresult)^? &\Rightarrow& t^? \\ + x,I'{:}\Ttypeuse_I &\Rightarrow& x & (\iff I' = \{\}) \\ + \end{array} \\ \production{block instruction} & \Tblockinstr_I &::=& - \text{block}~~I'{:}\Tlabel_I~~\X{rt}{:}\Tresulttype~~(\X{in}{:}\Tinstr_{I'})^\ast~~\text{end}~~\Tid^? - \\ &&&\qquad \Rightarrow\quad \BLOCK~\X{rt}~\X{in}^\ast~\END + \text{block}~~I'{:}\Tlabel_I~~\X{bt}{:}\Tblocktype~~(\X{in}{:}\Tinstr_{I'})^\ast~~\text{end}~~\Tid^? + \\ &&&\qquad \Rightarrow\quad \BLOCK~\X{bt}~\X{in}^\ast~\END \qquad\quad~~ (\iff \Tid^? = \epsilon \vee \Tid^? = \Tlabel) \\ &&|& - \text{loop}~~I'{:}\Tlabel_I~~\X{rt}{:}\Tresulttype~~(\X{in}{:}\Tinstr_{I'})^\ast~~\text{end}~~\Tid^? - \\ &&&\qquad \Rightarrow\quad \LOOP~\X{rt}~\X{in}^\ast~\END + \text{loop}~~I'{:}\Tlabel_I~~\X{bt}{:}\Tblocktype~~(\X{in}{:}\Tinstr_{I'})^\ast~~\text{end}~~\Tid^? + \\ &&&\qquad \Rightarrow\quad \LOOP~\X{bt}~\X{in}^\ast~\END \qquad\qquad (\iff \Tid^? = \epsilon \vee \Tid^? = \Tlabel) \\ &&|& - \text{if}~~I'{:}\Tlabel_I~~\X{rt}{:}\Tresulttype~~(\X{in}_1{:}\Tinstr_{I'})^\ast~~ + \text{if}~~I'{:}\Tlabel_I~~\X{bt}{:}\Tblocktype~~(\X{in}_1{:}\Tinstr_{I'})^\ast~~ \text{else}~~\Tid_1^?~~(\X{in}_2{:}\Tinstr_{I'})^\ast~~\text{end}~~\Tid_2^? - \\ &&&\qquad \Rightarrow\quad \IF~\X{rt}~\X{in}_1^\ast~\ELSE~\X{in}_2^\ast~\END + \\ &&&\qquad \Rightarrow\quad \IF~\X{bt}~\X{in}_1^\ast~\ELSE~\X{in}_2^\ast~\END \qquad (\iff \Tid_1^? = \epsilon \vee \Tid_1^? = \Tlabel, \Tid_2^? = \epsilon \vee \Tid_2^? = \Tlabel) \\ \end{array} +.. note:: + The side condition stating that the :ref:`identifier context ` :math:`I'` must be empty in the rule for |Ttypeuse| block types enforces that no identifier can be bound in any |Tparam| declaration for a block type. + + .. _text-nop: .. _text-unreachable: .. _text-br: @@ -113,9 +128,9 @@ The :math:`\text{else}` keyword of an :math:`\text{if}` instruction can be omitt .. math:: \begin{array}{llclll} \production{block instruction} & - \text{if}~~\Tlabel~~\Tresulttype~~\Tinstr^\ast~~\text{end} + \text{if}~~\Tlabel~~\Tblocktype~~\Tinstr^\ast~~\text{end} &\equiv& - \text{if}~~\Tlabel~~\Tresulttype~~\Tinstr^\ast~~\text{else}~~\text{end} + \text{if}~~\Tlabel~~\Tblocktype~~\Tinstr^\ast~~\text{else}~~\text{end} \end{array} Also, for backwards compatibility, the table index to :math:`\text{call\_indirect}` can be omitted, defaulting to :math:`0`. @@ -477,12 +492,20 @@ Numeric Instructions \text{i32.trunc\_f32\_u} &\Rightarrow& \I32.\TRUNC\K{\_}\F32\K{\_u} \\ &&|& \text{i32.trunc\_f64\_s} &\Rightarrow& \I32.\TRUNC\K{\_}\F64\K{\_s} \\ &&|& \text{i32.trunc\_f64\_u} &\Rightarrow& \I32.\TRUNC\K{\_}\F64\K{\_u} \\ &&|& + \text{i32.trunc\_sat_f32\_s} &\Rightarrow& \I32.\TRUNC\K{\_sat\_}\F32\K{\_s} \\ &&|& + \text{i32.trunc\_sat_f32\_u} &\Rightarrow& \I32.\TRUNC\K{\_sat\_}\F32\K{\_u} \\ &&|& + \text{i32.trunc\_sat_f64\_s} &\Rightarrow& \I32.\TRUNC\K{\_sat\_}\F64\K{\_s} \\ &&|& + \text{i32.trunc\_sat_f64\_u} &\Rightarrow& \I32.\TRUNC\K{\_sat\_}\F64\K{\_u} \\ &&|& \text{i64.extend\_i32\_s} &\Rightarrow& \I64.\EXTEND\K{\_}\I32\K{\_s} \\ &&|& \text{i64.extend\_i32\_u} &\Rightarrow& \I64.\EXTEND\K{\_}\I32\K{\_u} \\ &&|& \text{i64.trunc\_f32\_s} &\Rightarrow& \I64.\TRUNC\K{\_}\F32\K{\_s} \\ &&|& \text{i64.trunc\_f32\_u} &\Rightarrow& \I64.\TRUNC\K{\_}\F32\K{\_u} \\ &&|& \text{i64.trunc\_f64\_s} &\Rightarrow& \I64.\TRUNC\K{\_}\F64\K{\_s} \\ &&|& \text{i64.trunc\_f64\_u} &\Rightarrow& \I64.\TRUNC\K{\_}\F64\K{\_u} \\ &&|& + \text{i64.trunc\_sat_f32\_s} &\Rightarrow& \I64.\TRUNC\K{\_sat\_}\F32\K{\_s} \\ &&|& + \text{i64.trunc\_sat_f32\_u} &\Rightarrow& \I64.\TRUNC\K{\_sat\_}\F32\K{\_u} \\ &&|& + \text{i64.trunc\_sat_f64\_s} &\Rightarrow& \I64.\TRUNC\K{\_sat\_}\F64\K{\_s} \\ &&|& + \text{i64.trunc\_sat_f64\_u} &\Rightarrow& \I64.\TRUNC\K{\_sat\_}\F64\K{\_u} \\ &&|& \text{f32.convert\_i32\_s} &\Rightarrow& \F32.\CONVERT\K{\_}\I32\K{\_s} \\ &&|& \text{f32.convert\_i32\_u} &\Rightarrow& \F32.\CONVERT\K{\_}\I32\K{\_u} \\ &&|& \text{f32.convert\_i64\_s} &\Rightarrow& \F32.\CONVERT\K{\_}\I64\K{\_s} \\ &&|& @@ -499,6 +522,16 @@ Numeric Instructions \text{f64.reinterpret\_i64} &\Rightarrow& \F64.\REINTERPRET\K{\_}\I64 \\ \end{array} +.. math:: + \begin{array}{llclll} + \phantom{\production{instruction}} & \phantom{\Tplaininstr_I} &\phantom{::=}& \phantom{thisisenough} && \phantom{thisshouldbeenough} \\[-2ex] &&|& + \text{i32.extend8\_s} &\Rightarrow& \I32.\EXTEND\K{8\_s} \\ &&|& + \text{i32.extend16\_s} &\Rightarrow& \I32.\EXTEND\K{16\_s} \\ &&|& + \text{i64.extend8\_s} &\Rightarrow& \I64.\EXTEND\K{8\_s} \\ &&|& + \text{i64.extend16\_s} &\Rightarrow& \I64.\EXTEND\K{16\_s} \\ &&|& + \text{i64.extend32\_s} &\Rightarrow& \I64.\EXTEND\K{32\_s} \\ + \end{array} + .. index:: ! folded instruction, S-expression .. _text-foldedinstr: @@ -521,14 +554,14 @@ Such a folded instruction can appear anywhere a regular instruction can. \production{instruction} & \text{(}~\Tplaininstr~~\Tfoldedinstr^\ast~\text{)} &\equiv\quad \Tfoldedinstr^\ast~~\Tplaininstr \\ & - \text{(}~\text{block}~~\Tlabel~~\Tresulttype~~\Tinstr^\ast~\text{)} - &\equiv\quad \text{block}~~\Tlabel~~\Tresulttype~~\Tinstr^\ast~~\text{end} \\ & - \text{(}~\text{loop}~~\Tlabel~~\Tresulttype~~\Tinstr^\ast~\text{)} - &\equiv\quad \text{loop}~~\Tlabel~~\Tresulttype~~\Tinstr^\ast~~\text{end} \\ & - \text{(}~\text{if}~~\Tlabel~~\Tresulttype~~\Tfoldedinstr^\ast + \text{(}~\text{block}~~\Tlabel~~\Tblocktype~~\Tinstr^\ast~\text{)} + &\equiv\quad \text{block}~~\Tlabel~~\Tblocktype~~\Tinstr^\ast~~\text{end} \\ & + \text{(}~\text{loop}~~\Tlabel~~\Tblocktype~~\Tinstr^\ast~\text{)} + &\equiv\quad \text{loop}~~\Tlabel~~\Tblocktype~~\Tinstr^\ast~~\text{end} \\ & + \text{(}~\text{if}~~\Tlabel~~\Tblocktype~~\Tfoldedinstr^\ast &\hspace{-3ex} \text{(}~\text{then}~~\Tinstr_1^\ast~\text{)}~~\text{(}~\text{else}~~\Tinstr_2^\ast~\text{)}^?~~\text{)} \quad\equiv \\ &\qquad - \Tfoldedinstr^\ast~~\text{if}~~\Tlabel~~\Tresulttype &\hspace{-1ex} \Tinstr_1^\ast~~\text{else}~~(\Tinstr_2^\ast)^?~\text{end} \\ + \Tfoldedinstr^\ast~~\text{if}~~\Tlabel~~\Tblocktype &\hspace{-1ex} \Tinstr_1^\ast~~\text{else}~~(\Tinstr_2^\ast)^?~\text{end} \\ \end{array} .. note:: diff --git a/document/core/text/modules.rst b/document/core/text/modules.rst index 59d2a88069..9ae3b2d114 100644 --- a/document/core/text/modules.rst +++ b/document/core/text/modules.rst @@ -140,7 +140,7 @@ where :math:`x` is the smallest existing :ref:`type index ` whos If no such index exists, then a new :ref:`type definition ` of the form .. math:: - \text{(}~\text{type}~~\text{(}~\text{func}~~\Tparam^\ast~~\Tresult~\text{)}~\text{)} + \text{(}~\text{type}~~\text{(}~\text{func}~~\Tparam^\ast~~\Tresult^\ast~\text{)}~\text{)} is inserted at the end of the module. diff --git a/document/core/text/types.rst b/document/core/text/types.rst index 5711fb5452..bfeb2b82b4 100644 --- a/document/core/text/types.rst +++ b/document/core/text/types.rst @@ -56,23 +56,6 @@ Value Types \end{array} -.. index:: result type, value type - pair: text format; result type -.. _text-resulttype: - -Result Types -~~~~~~~~~~~~ - -.. math:: - \begin{array}{llclll@{\qquad\qquad}l} - \production{result type} & \Tresulttype &::=& - (t{:}\Tresult)^? &\Rightarrow& [t^?] \\ - \end{array} - -.. note:: - In future versions of WebAssembly, this scheme may be extended to support multiple results or more general result types. - - .. index:: function type, value type, result type pair: text format; function type .. _text-param: @@ -95,6 +78,7 @@ Function Types &\Rightarrow& t \\ \end{array} + Abbreviations ............. diff --git a/document/core/text/values.rst b/document/core/text/values.rst index 918d35ab4e..1f4c1bbfdb 100644 --- a/document/core/text/values.rst +++ b/document/core/text/values.rst @@ -88,28 +88,26 @@ Floating-Point .. math:: \begin{array}{llclll@{\qquad\qquad}l} \production{decimal floating-point fraction} & \Tfrac &::=& - \epsilon &\Rightarrow& 0 \\ &&|& - d{:}\Tdigit~~q{:}\Tfrac &\Rightarrow& (d+q)/10 \\ &&|& - d{:}\Tdigit~~\text{\_}~~p{:}\Tdigit~~q{:}\Tfrac &\Rightarrow& (d+(p+q)/10)/10 \\ + d{:}\Tdigit &\Rightarrow& d/10 \\ &&|& + d{:}\Tdigit~~\text{\_}^?~~p{:}\Tfrac &\Rightarrow& (d+p/10)/10 \\ \production{hexadecimal floating-point fraction} & \Thexfrac &::=& - \epsilon &\Rightarrow& 0 \\ &&|& - h{:}\Thexdigit~~q{:}\Thexfrac &\Rightarrow& (h+q)/16 \\ &&|& - h{:}\Thexdigit~~\text{\_}~~~~p{:}\Thexdigit~~q{:}\Thexfrac &\Rightarrow& (h+(p+q)/16)/16 \\ + h{:}\Thexdigit &\Rightarrow& h/16 \\ &&|& + h{:}\Thexdigit~~\text{\_}^?~~p{:}\Thexfrac &\Rightarrow& (h+p/16)/16 \\ \production{decimal floating-point number} & \Tfloat &::=& - p{:}\Tnum + p{:}\Tnum~\text{.}^? &\Rightarrow& p \\ &&|& p{:}\Tnum~\text{.}~q{:}\Tfrac &\Rightarrow& p+q \\ &&|& - p{:}\Tnum~(\text{E}~|~\text{e})~{\pm}{:}\Tsign~e{:}\Tnum + p{:}\Tnum~\text{.}^?~(\text{E}~|~\text{e})~{\pm}{:}\Tsign~e{:}\Tnum &\Rightarrow& p\cdot 10^{\pm e} \\ &&|& p{:}\Tnum~\text{.}~q{:}\Tfrac~(\text{E}~|~\text{e})~{\pm}{:}\Tsign~e{:}\Tnum &\Rightarrow& (p+q)\cdot 10^{\pm e} \\ \production{hexadecimal floating-point number} & \Thexfloat &::=& - \text{0x}~p{:}\Thexnum + \text{0x}~p{:}\Thexnum~\text{.}^? &\Rightarrow& p \\ &&|& \text{0x}~p{:}\Thexnum~\text{.}~q{:}\Thexfrac &\Rightarrow& p+q \\ &&|& - \text{0x}~p{:}\Thexnum~(\text{P}~|~\text{p})~{\pm}{:}\Tsign~e{:}\Tnum + \text{0x}~p{:}\Thexnum~\text{.}^?~(\text{P}~|~\text{p})~{\pm}{:}\Tsign~e{:}\Tnum &\Rightarrow& p\cdot 2^{\pm e} \\ &&|& \text{0x}~p{:}\Thexnum~\text{.}~q{:}\Thexfrac~(\text{P}~|~\text{p})~{\pm}{:}\Tsign~e{:}\Tnum &\Rightarrow& (p+q)\cdot 2^{\pm e} diff --git a/document/core/util/macros.def b/document/core/util/macros.def index a74a9f56c9..360b9d84ca 100644 --- a/document/core/util/macros.def +++ b/document/core/util/macros.def @@ -170,8 +170,6 @@ .. |to| mathdef:: \xref{syntax/types}{syntax-functype}{\rightarrow} -.. |BOT| mathdef:: \xref{syntax/types}{syntax-valtype}{\K{bot}} - .. |I8| mathdef:: \xref{exec/runtime}{syntax-storagetype}{\K{i8}} .. |I16| mathdef:: \xref{exec/runtime}{syntax-storagetype}{\K{i16}} .. |I32| mathdef:: \xref{syntax/types}{syntax-valtype}{\K{i32}} @@ -201,6 +199,7 @@ .. |valtype| mathdef:: \xref{syntax/types}{syntax-valtype}{\X{valtype}} .. |resulttype| mathdef:: \xref{syntax/types}{syntax-resulttype}{\X{resulttype}} .. |functype| mathdef:: \xref{syntax/types}{syntax-functype}{\X{functype}} + .. |globaltype| mathdef:: \xref{syntax/types}{syntax-globaltype}{\X{globaltype}} .. |tabletype| mathdef:: \xref{syntax/types}{syntax-tabletype}{\X{tabletype}} .. |memtype| mathdef:: \xref{syntax/types}{syntax-memtype}{\X{memtype}} @@ -443,6 +442,8 @@ .. |sx| mathdef:: \xref{syntax/instructions}{syntax-sx}{\X{sx}} .. |memarg| mathdef:: \xref{syntax/instructions}{syntax-memarg}{\X{memarg}} +.. |blocktype| mathdef:: \xref{syntax/instructions}{syntax-blocktype}{\X{blocktype}} + .. |instr| mathdef:: \xref{syntax/instructions}{syntax-instr}{\X{instr}} .. |expr| mathdef:: \xref{syntax/instructions}{syntax-expr}{\X{expr}} @@ -475,6 +476,7 @@ .. |BsN| mathdef:: \xref{binary/values}{binary-int}{\BsX{N}} .. |Bs7| mathdef:: \xref{binary/values}{binary-int}{\BsX{\B{7}}} .. |Bs32| mathdef:: \xref{binary/values}{binary-int}{\BsX{\B{32}}} +.. |Bs33| mathdef:: \xref{binary/values}{binary-int}{\BsX{\B{33}}} .. |Bs64| mathdef:: \xref{binary/values}{binary-int}{\BsX{\B{64}}} .. |BiN| mathdef:: \xref{binary/values}{binary-int}{\BiX{N}} @@ -499,7 +501,6 @@ .. |Breftype| mathdef:: \xref{binary/types}{binary-reftype}{\B{reftype}} .. |Bvaltype| mathdef:: \xref{binary/types}{binary-valtype}{\B{valtype}} .. |Bresulttype| mathdef:: \xref{binary/types}{binary-resulttype}{\B{resulttype}} -.. |Bblocktype| mathdef:: \xref{binary/types}{binary-blocktype}{\B{blocktype}} .. |Bfunctype| mathdef:: \xref{binary/types}{binary-functype}{\B{functype}} .. |Bglobaltype| mathdef:: \xref{binary/types}{binary-globaltype}{\B{globaltype}} .. |Btabletype| mathdef:: \xref{binary/types}{binary-tabletype}{\B{tabletype}} @@ -565,6 +566,7 @@ .. Instructions, non-terminals .. |Bmemarg| mathdef:: \xref{binary/instructions}{binary-memarg}{\B{memarg}} +.. |Bblocktype| mathdef:: \xref{binary/instructions}{binary-blocktype}{\B{blocktype}} .. |Binstr| mathdef:: \xref{binary/instructions}{binary-instr}{\B{instr}} .. |Bexpr| mathdef:: \xref{binary/instructions}{binary-expr}{\B{expr}} @@ -660,13 +662,13 @@ .. |Treftype| mathdef:: \xref{text/types}{text-reftype}{\T{reftype}} .. |Trefedtype| mathdef:: \xref{text/types}{text-refedtype}{\T{refedtype}} .. |Tvaltype| mathdef:: \xref{text/types}{text-valtype}{\T{valtype}} -.. |Tresulttype| mathdef:: \xref{text/types}{text-resulttype}{\T{resulttype}} -.. |Tblocktype| mathdef:: \xref{text/types}{text-blocktype}{\T{blocktype}} .. |Tfunctype| mathdef:: \xref{text/types}{text-functype}{\T{functype}} + .. |Tglobaltype| mathdef:: \xref{text/types}{text-globaltype}{\T{globaltype}} .. |Ttabletype| mathdef:: \xref{text/types}{text-tabletype}{\T{tabletype}} .. |Tmemtype| mathdef:: \xref{text/types}{text-memtype}{\T{memtype}} .. |Tlimits| mathdef:: \xref{text/types}{text-limits}{\T{limits}} + .. |Tparam| mathdef:: \xref{text/types}{text-functype}{\T{param}} .. |Tresult| mathdef:: \xref{text/types}{text-functype}{\T{result}} @@ -726,6 +728,8 @@ .. |Talign| mathdef:: \xref{text/instructions}{text-memarg}{\T{align}} .. |Toffset| mathdef:: \xref{text/instructions}{text-memarg}{\T{offset}} +.. |Tblocktype| mathdef:: \xref{text/instructions}{text-blocktype}{\T{blocktype}} + .. |Tlabel| mathdef:: \xref{text/instructions}{text-label}{\T{label}} .. |Tinstr| mathdef:: \xref{text/instructions}{text-instr}{\T{instr}} .. |Tplaininstr| mathdef:: \xref{text/instructions}{text-plaininstr}{\T{plaininstr}} @@ -787,6 +791,7 @@ .. Judgments .. |vdashlimits| mathdef:: \xref{valid/types}{valid-limits}{\vdash} +.. |vdashblocktype| mathdef:: \xref{valid/types}{valid-blocktype}{\vdash} .. |vdashfunctype| mathdef:: \xref{valid/types}{valid-functype}{\vdash} .. |vdashtabletype| mathdef:: \xref{valid/types}{valid-tabletype}{\vdash} .. |vdashmemtype| mathdef:: \xref{valid/types}{valid-memtype}{\vdash} @@ -944,6 +949,11 @@ .. |frame| mathdef:: \xref{exec/runtime}{syntax-frame}{\X{frame}} +.. Stack, meta functions + +.. |expand| mathdef:: \xref{exec/runtime}{syntax-frame}{\F{expand}} + + .. Administrative Instructions, terminals .. |REFFUNCADDR| mathdef:: \xref{exec/runtime}{syntax-ref}{\K{ref}} @@ -1007,6 +1017,7 @@ .. |iles| mathdef:: \xref{exec/numerics}{op-ile_s}{\F{ile\_s}} .. |igeu| mathdef:: \xref{exec/numerics}{op-ige_u}{\F{ige\_u}} .. |iges| mathdef:: \xref{exec/numerics}{op-ige_s}{\F{ige\_s}} +.. |iextendMs| mathdef:: \xref{exec/numerics}{op-iextendn_s}{\F{iextend}M\F{\_s}} .. |fadd| mathdef:: \xref{exec/numerics}{op-fadd}{\F{fadd}} .. |fsub| mathdef:: \xref{exec/numerics}{op-fsub}{\F{fsub}} @@ -1035,6 +1046,8 @@ .. |wrap| mathdef:: \xref{exec/numerics}{op-wrap}{\F{wrap}} .. |truncu| mathdef:: \xref{exec/numerics}{op-trunc_u}{\F{trunc}^{\K{u}}} .. |truncs| mathdef:: \xref{exec/numerics}{op-trunc_s}{\F{trunc}^{\K{s}}} +.. |truncsatu| mathdef:: \xref{exec/numerics}{op-trunc_sat_u}{\F{trunc\_sat\_u}} +.. |truncsats| mathdef:: \xref{exec/numerics}{op-trunc_sat_s}{\F{trunc\_sat\_s}} .. |promote| mathdef:: \xref{exec/numerics}{op-promote}{\F{promote}} .. |demote| mathdef:: \xref{exec/numerics}{op-demote}{\F{demote}} .. |convertu| mathdef:: \xref{exec/numerics}{op-convert_u}{\F{convert}^{\K{u}}} diff --git a/document/core/valid/conventions.rst b/document/core/valid/conventions.rst index 727d9ecb71..405ad23e28 100644 --- a/document/core/valid/conventions.rst +++ b/document/core/valid/conventions.rst @@ -174,15 +174,17 @@ and there is one respective rule for each relevant construct :math:`A` of the ab .. math:: \frac{ - C,\LABEL\,[t^?] \vdash \instr^\ast : [] \to [t^?] + C \vdash \blocktype : [t_1^\ast] \to [t_2^\ast] + \qquad + C,\LABEL\,[t_2^\ast] \vdash \instr^\ast : [t_1^\ast] \to [t_2^\ast] }{ - C \vdash \BLOCK~[t^?]~\instr^\ast~\END : [] \to [t^?] + C \vdash \BLOCK~\blocktype~\instr^\ast~\END : [t_1^\ast] \to [t_2^\ast] } A |BLOCK| instruction is only valid when the instruction sequence in its body is. - Moreover, the result type must match the block's annotation :math:`[t^?]`. + Moreover, the result type must match the block's annotation :math:`\blocktype`. If so, then the |BLOCK| instruction has the same type as the body. - Inside the body an additional label of the same type is available, + Inside the body an additional label of the corresponding result type is available, which is expressed by extending the context :math:`C` with the additional label information for the premise. diff --git a/document/core/valid/instructions.rst b/document/core/valid/instructions.rst index 1982139541..b01f92f355 100644 --- a/document/core/valid/instructions.rst +++ b/document/core/valid/instructions.rst @@ -745,7 +745,7 @@ Memory Instructions } -.. index:: control instructions, structured control, label, block, branch, result type, label index, function index, type index, vector, polymorphism, context +.. index:: control instructions, structured control, label, block, branch, block type, label index, function index, type index, vector, polymorphism, context pair: validation; instruction single: abstract syntax; instruction .. _valid-label: @@ -787,85 +787,88 @@ Control Instructions .. _valid-block: -:math:`\BLOCK~[t^?]~\instr^\ast~\END` -..................................... +:math:`\BLOCK~\blocktype~\instr^\ast~\END` +.......................................... + +* The :ref:`block type ` must be :ref:`valid ` as some :ref:`function type ` :math:`[t_1^\ast] \to [t_2^\ast]`. -* Let :math:`C'` be the same :ref:`context ` as :math:`C`, but with the :ref:`result type ` :math:`[t^?]` prepended to the |CLABELS| vector. +* Let :math:`C'` be the same :ref:`context ` as :math:`C`, but with the :ref:`result type ` :math:`[t_2^\ast]` prepended to the |CLABELS| vector. * Under context :math:`C'`, - the instruction sequence :math:`\instr^\ast` must be :ref:`valid ` with type :math:`[] \to [t^?]`. + the instruction sequence :math:`\instr^\ast` must be :ref:`valid ` with type :math:`[t_1^\ast] \to [t_2^\ast]`. -* Then the compound instruction is valid with type :math:`[] \to [t^?]`. +* Then the compound instruction is valid with type :math:`[t_1^\ast] \to [t_2^\ast]`. .. math:: \frac{ - C,\CLABELS\,[t^?] \vdashinstrseq \instr^\ast : [] \to [t^?] + C \vdashblocktype \blocktype : [t_1^\ast] \to [t_2^\ast] + \qquad + C,\CLABELS\,[t_2^\ast] \vdashinstrseq \instr^\ast : [t_1^\ast] \to [t_2^\ast] }{ - C \vdashinstr \BLOCK~[t^?]~\instr^\ast~\END : [] \to [t^?] + C \vdashinstr \BLOCK~\blocktype~\instr^\ast~\END : [t_1^\ast] \to [t_2^\ast] } .. note:: - The :ref:`notation ` :math:`C,\CLABELS\,[t^?]` inserts the new label type at index :math:`0`, shifting all others. - - The fact that the nested instruction sequence :math:`\instr^\ast` must have type :math:`[] \to [t^?]` implies that it cannot access operands that have been pushed on the stack before the block was entered. - This may be generalized in future versions of WebAssembly. + The :ref:`notation ` :math:`C,\CLABELS\,[t^\ast]` inserts the new label type at index :math:`0`, shifting all others. .. _valid-loop: -:math:`\LOOP~[t^?]~\instr^\ast~\END` -.................................... +:math:`\LOOP~\blocktype~\instr^\ast~\END` +......................................... + +* The :ref:`block type ` must be :ref:`valid ` as some :ref:`function type ` :math:`[t_1^\ast] \to [t_2^\ast]`. -* Let :math:`C'` be the same :ref:`context ` as :math:`C`, but with the empty :ref:`result type ` :math:`[]` prepended to the |CLABELS| vector. +* Let :math:`C'` be the same :ref:`context ` as :math:`C`, but with the :ref:`result type ` :math:`[t_1^\ast]` prepended to the |CLABELS| vector. * Under context :math:`C'`, - the instruction sequence :math:`\instr^\ast` must be :ref:`valid ` with type :math:`[] \to [t^?]`. + the instruction sequence :math:`\instr^\ast` must be :ref:`valid ` with type :math:`[t_1^\ast] \to [t_2^\ast]`. -* Then the compound instruction is valid with type :math:`[] \to [t^?]`. +* Then the compound instruction is valid with type :math:`[t_1^\ast] \to [t_2^\ast]`. .. math:: \frac{ - C,\CLABELS\,[] \vdashinstrseq \instr^\ast : [] \to [t^?] + C \vdashblocktype \blocktype : [t_1^\ast] \to [t_2^\ast] + \qquad + C,\CLABELS\,[t_1^\ast] \vdashinstrseq \instr^\ast : [t_1^\ast] \to [t_2^\ast] }{ - C \vdashinstr \LOOP~[t^?]~\instr^\ast~\END : [] \to [t^?] + C \vdashinstr \LOOP~\blocktype~\instr^\ast~\END : [t_1^\ast] \to [t_2^\ast] } .. note:: - The :ref:`notation ` :math:`C,\CLABELS\,[]` inserts the new label type at index :math:`0`, shifting all others. - - The fact that the nested instruction sequence :math:`\instr^\ast` must have type :math:`[] \to [t^?]` implies that it cannot access operands that have been pushed on the stack before the loop was entered. - This may be generalized in future versions of WebAssembly. + The :ref:`notation ` :math:`C,\CLABELS\,[t^\ast]` inserts the new label type at index :math:`0`, shifting all others. .. _valid-if: -:math:`\IF~[t^?]~\instr_1^\ast~\ELSE~\instr_2^\ast~\END` -........................................................ +:math:`\IF~\blocktype~\instr_1^\ast~\ELSE~\instr_2^\ast~\END` +............................................................. + +* The :ref:`block type ` must be :ref:`valid ` as some :ref:`function type ` :math:`[t_1^\ast] \to [t_2^\ast]`. -* Let :math:`C'` be the same :ref:`context ` as :math:`C`, but with the :ref:`result type ` :math:`[t^?]` prepended to the |CLABELS| vector. +* Let :math:`C'` be the same :ref:`context ` as :math:`C`, but with the :ref:`result type ` :math:`[t_2^\ast]` prepended to the |CLABELS| vector. * Under context :math:`C'`, - the instruction sequence :math:`\instr_1^\ast` must be :ref:`valid ` with type :math:`[] \to [t^?]`. + the instruction sequence :math:`\instr_1^\ast` must be :ref:`valid ` with type :math:`[t_1^\ast] \to [t_2^\ast]`. * Under context :math:`C'`, - the instruction sequence :math:`\instr_2^\ast` must be :ref:`valid ` with type :math:`[] \to [t^?]`. + the instruction sequence :math:`\instr_2^\ast` must be :ref:`valid ` with type :math:`[t_1^\ast] \to [t_2^\ast]`. -* Then the compound instruction is valid with type :math:`[\I32] \to [t^?]`. +* Then the compound instruction is valid with type :math:`[t_1^\ast~\I32] \to [t_2^\ast]`. .. math:: \frac{ - C,\CLABELS\,[t^?] \vdashinstrseq \instr_1^\ast : [] \to [t^?] + C \vdashblocktype \blocktype : [t_1^\ast] \to [t_2^\ast] + \qquad + C,\CLABELS\,[t_2^\ast] \vdashinstrseq \instr_1^\ast : [t_1^\ast] \to [t_2^\ast] \qquad - C,\CLABELS\,[t^?] \vdashinstrseq \instr_2^\ast : [] \to [t^?] + C,\CLABELS\,[t_2^\ast] \vdashinstrseq \instr_2^\ast : [t_1^\ast] \to [t_2^\ast] }{ - C \vdashinstr \IF~[t^?]~\instr_1^\ast~\ELSE~\instr_2^\ast~\END : [\I32] \to [t^?] + C \vdashinstr \IF~\blocktype~\instr_1^\ast~\ELSE~\instr_2^\ast~\END : [t_1^\ast~\I32] \to [t_2^\ast] } .. note:: - The :ref:`notation ` :math:`C,\CLABELS\,[t^?]` inserts the new label type at index :math:`0`, shifting all others. - - The fact that the nested instruction sequence :math:`\instr^\ast` must have type :math:`[] \to [t^?]` implies that it cannot access operands that have been pushed on the stack before the conditional was entered. - This may be generalized in future versions of WebAssembly. + The :ref:`notation ` :math:`C,\CLABELS\,[t^\ast]` inserts the new label type at index :math:`0`, shifting all others. .. _valid-br: @@ -875,15 +878,15 @@ Control Instructions * The label :math:`C.\CLABELS[l]` must be defined in the context. -* Let :math:`[t^?]` be the :ref:`result type ` :math:`C.\CLABELS[l]`. +* Let :math:`[t^\ast]` be the :ref:`result type ` :math:`C.\CLABELS[l]`. -* Then the instruction is valid with type :math:`[t_1^\ast~t^?] \to [t_2^\ast]`, for any sequences of :ref:`value types ` :math:`t_1^\ast` and :math:`t_2^\ast`. +* Then the instruction is valid with type :math:`[t_1^\ast~t^\ast] \to [t_2^\ast]`, for any sequences of :ref:`value types ` :math:`t_1^\ast` and :math:`t_2^\ast`. .. math:: \frac{ - C.\CLABELS[l] = [t^?] + C.\CLABELS[l] = [t^\ast] }{ - C \vdashinstr \BR~l : [t_1^\ast~t^?] \to [t_2^\ast] + C \vdashinstr \BR~l : [t_1^\ast~t^\ast] \to [t_2^\ast] } .. note:: @@ -899,15 +902,15 @@ Control Instructions * The label :math:`C.\CLABELS[l]` must be defined in the context. -* Let :math:`[t^?]` be the :ref:`result type ` :math:`C.\CLABELS[l]`. +* Let :math:`[t^\ast]` be the :ref:`result type ` :math:`C.\CLABELS[l]`. -* Then the instruction is valid with type :math:`[t^?~\I32] \to [t^?]`. +* Then the instruction is valid with type :math:`[t^\ast~\I32] \to [t^\ast]`. .. math:: \frac{ - C.\CLABELS[l] = [t^?] + C.\CLABELS[l] = [t^\ast] }{ - C \vdashinstr \BRIF~l : [t^?~\I32] \to [t^?] + C \vdashinstr \BRIF~l : [t^\ast~\I32] \to [t^\ast] } .. note:: @@ -921,21 +924,23 @@ Control Instructions * The label :math:`C.\CLABELS[l_N]` must be defined in the context. +* Let :math:`[t^\ast]` be the :ref:`result type ` :math:`C.\CLABELS[l_N]`. + * For all :math:`l_i` in :math:`l^\ast`, the label :math:`C.\CLABELS[l_i]` must be defined in the context. * For all :math:`l_i` in :math:`l^\ast`, - :math:`C.\CLABELS[l_i]` must be :math:`[t^?]`. + :math:`C.\CLABELS[l_i]` must be :math:`[t^\ast]`. -* Then the instruction is valid with type :math:`[t_1^\ast~t^?~\I32] \to [t_2^\ast]`, for any sequences of :ref:`value types ` :math:`t_1^\ast` and :math:`t_2^\ast`. +* Then the instruction is valid with type :math:`[t_1^\ast~t^\ast~\I32] \to [t_2^\ast]`, for any sequences of :ref:`value types ` :math:`t_1^\ast` and :math:`t_2^\ast`. .. math:: \frac{ - (C.\CLABELS[l] = [t^?])^\ast + (C.\CLABELS[l] = [t^\ast])^\ast \qquad - C.\CLABELS[l_N] = [t^?] + C.\CLABELS[l_N] = [t^\ast] }{ - C \vdashinstr \BRTABLE~l^\ast~l_N : [t_1^\ast~t^?~\I32] \to [t_2^\ast] + C \vdashinstr \BRTABLE~l^\ast~l_N : [t_1^\ast~t^\ast~\I32] \to [t_2^\ast] } .. note:: @@ -951,15 +956,15 @@ Control Instructions * The return type :math:`C.\CRETURN` must not be absent in the context. -* Let :math:`[t^?]` be the :ref:`result type ` of :math:`C.\CRETURN`. +* Let :math:`[t^\ast]` be the :ref:`result type ` of :math:`C.\CRETURN`. -* Then the instruction is valid with type :math:`[t_1^\ast~t^?] \to [t_2^\ast]`, for any sequences of :ref:`value types ` :math:`t_1^\ast` and :math:`t_2^\ast`. +* Then the instruction is valid with type :math:`[t_1^\ast~t^\ast] \to [t_2^\ast]`, for any sequences of :ref:`value types ` :math:`t_1^\ast` and :math:`t_2^\ast`. .. math:: \frac{ - C.\CRETURN = [t^?] + C.\CRETURN = [t^\ast] }{ - C \vdashinstr \RETURN : [t_1^\ast~t^?] \to [t_2^\ast] + C \vdashinstr \RETURN : [t_1^\ast~t^\ast] \to [t_2^\ast] } .. note:: @@ -1060,7 +1065,7 @@ Non-empty Instruction Sequence: :math:`\instr^\ast~\instr_N` } -.. index:: expression +.. index:: expression,result type pair: validation; expression single: abstract syntax; expression single: expression; constant @@ -1069,22 +1074,22 @@ Non-empty Instruction Sequence: :math:`\instr^\ast~\instr_N` Expressions ~~~~~~~~~~~ -Expressions :math:`\expr` are classified by :ref:`result types ` of the form :math:`[t^?]`. +Expressions :math:`\expr` are classified by :ref:`result types ` of the form :math:`[t^\ast]`. :math:`\instr^\ast~\END` ........................ -* The instruction sequence :math:`\instr^\ast` must be :ref:`valid ` with type :math:`[] \to [t^?]`, - for some optional :ref:`value type ` :math:`t^?`. +* The instruction sequence :math:`\instr^\ast` must be :ref:`valid ` with type :math:`[] \to [t^\ast]`, + for some :ref:`result type ` :math:`[t^\ast]`. -* Then the expression is valid with :ref:`result type ` :math:`[t^?]`. +* Then the expression is valid with :ref:`result type ` :math:`[t^\ast]`. .. math:: \frac{ - C \vdashinstrseq \instr^\ast : [] \to [t^?] + C \vdashinstrseq \instr^\ast : [] \to [t^\ast] }{ - C \vdashexpr \instr^\ast~\END : [t^?] + C \vdashexpr \instr^\ast~\END : [t^\ast] } diff --git a/document/core/valid/modules.rst b/document/core/valid/modules.rst index 40b25a7646..b86a62f086 100644 --- a/document/core/valid/modules.rst +++ b/document/core/valid/modules.rst @@ -14,7 +14,7 @@ Furthermore, most definitions are themselves classified with a suitable type. Functions ~~~~~~~~~ -Functions :math:`\func` are classified by :ref:`function types ` of the form :math:`[t_1^\ast] \to [t_2^?]`. +Functions :math:`\func` are classified by :ref:`function types ` of the form :math:`[t_1^\ast] \to [t_2^\ast]`. :math:`\{ \FTYPE~x, \FLOCALS~t^\ast, \FBODY~\expr \}` @@ -22,34 +22,31 @@ Functions :math:`\func` are classified by :ref:`function types * The type :math:`C.\CTYPES[x]` must be defined in the context. -* Let :math:`[t_1^\ast] \to [t_2^?]` be the :ref:`function type ` :math:`C.\CTYPES[x]`. +* Let :math:`[t_1^\ast] \to [t_2^\ast]` be the :ref:`function type ` :math:`C.\CTYPES[x]`. * Let :math:`C'` be the same :ref:`context ` as :math:`C`, but with: * |CLOCALS| set to the sequence of :ref:`value types ` :math:`t_1^\ast~t^\ast`, concatenating parameters and locals, - * |CLABELS| set to the singular sequence containing only :ref:`result type ` :math:`[t_2^?]`. + * |CLABELS| set to the singular sequence containing only :ref:`result type ` :math:`[t_2^\ast]`. - * |CRETURN| set to the :ref:`result type ` :math:`[t_2^?]`. + * |CRETURN| set to the :ref:`result type ` :math:`[t_2^\ast]`. * Under the context :math:`C'`, - the expression :math:`\expr` must be valid with type :math:`t_2^?`. + the expression :math:`\expr` must be valid with type :math:`[t_2^\ast]`. -* Then the function definition is valid with type :math:`[t_1^\ast] \to [t_2^?]`. +* Then the function definition is valid with type :math:`[t_1^\ast] \to [t_2^\ast]`. .. math:: \frac{ - C.\CTYPES[x] = [t_1^\ast] \to [t_2^?] + C.\CTYPES[x] = [t_1^\ast] \to [t_2^\ast] \qquad - C,\CLOCALS\,t_1^\ast~t^\ast,\CLABELS~[t_2^?],\CRETURN~[t_2^?] \vdashexpr \expr : [t_2^?] + C,\CLOCALS\,t_1^\ast~t^\ast,\CLABELS~[t_2^\ast],\CRETURN~[t_2^\ast] \vdashexpr \expr : [t_2^\ast] }{ - C \vdashfunc \{ \FTYPE~x, \FLOCALS~t^\ast, \FBODY~\expr \} : [t_1^\ast] \to [t_2^?] + C \vdashfunc \{ \FTYPE~x, \FLOCALS~t^\ast, \FBODY~\expr \} : [t_1^\ast] \to [t_2^\ast] } -.. note:: - The restriction on the length of the result types :math:`t_2^\ast` may be lifted in future versions of WebAssembly. - .. index:: table, table type pair: validation; table diff --git a/document/core/valid/types.rst b/document/core/valid/types.rst index a18907a099..8c97856910 100644 --- a/document/core/valid/types.rst +++ b/document/core/valid/types.rst @@ -2,7 +2,8 @@ Types ----- Most :ref:`types ` are universally valid. -However, restrictions apply to :ref:`function types ` as well as the :ref:`limits ` of :ref:`table types ` and :ref:`memory types `, which must be checked during validation. +However, restrictions apply to :ref:`limits `, which must be checked during validation. +Moreover, :ref:`block types ` are converted to plain :ref:`function types ` for ease of processing. .. index:: limits @@ -40,6 +41,43 @@ Limits } +.. index:: block type + pair: validation; block type + single: abstract syntax; block type +.. _valid-blocktype: + +Block Types +~~~~~~~~~~~ + +:ref:`Block types ` may be expressed in one of two forms, both of which are converted to plain :ref:`function types ` by the following rules. + +:math:`\typeidx` +................ + +* The type :math:`C.\CTYPES[\typeidx]` must be defined in the context. + +* Then the block type is valid as :ref:`function type ` :math:`C.\CTYPES[\typeidx]`. + +.. math:: + \frac{ + C.\CTYPES[\typeidx] = \functype + }{ + C \vdashblocktype \typeidx : \functype + } + + +:math:`[\valtype^?]` +.................... + +* The block type is valid as :ref:`function type ` :math:`[] \to [\valtype^?]`. + +.. math:: + \frac{ + }{ + C \vdashblocktype [\valtype^?] : [] \to [\valtype^?] + } + + .. index:: function type pair: validation; function type single: abstract syntax; function type @@ -48,24 +86,19 @@ Limits Function Types ~~~~~~~~~~~~~~ -:ref:`Function types ` may not specify more than one result. +:ref:`Function types ` are always valid. :math:`[t_1^n] \to [t_2^m]` ........................... -* The arity :math:`m` must not be larger than :math:`1`. - -* Then the function type is valid. +* The function type is valid. .. math:: \frac{ }{ - \vdashfunctype [t_1^\ast] \to [t_2^?] \ok + \vdashfunctype [t_1^\ast] \to [t_2^\ast] \ok } -.. note:: - The restriction to at most one result may be removed in future versions of WebAssembly. - .. index:: table type, reference type, limits pair: validation; table type diff --git a/document/index.html b/document/index.html index f95c9a1d40..37eed9762e 100644 --- a/document/index.html +++ b/document/index.html @@ -33,8 +33,8 @@

    Core specification

    instantiation, and execution.

    diff --git a/document/js-api/index.bs b/document/js-api/index.bs index 4ab7e0e59c..55ebf5f156 100644 --- a/document/js-api/index.bs +++ b/document/js-api/index.bs @@ -86,6 +86,9 @@ urlPrefix: https://tc39.github.io/ecma262/; spec: ECMASCRIPT text: NumberToRawBytes; url: sec-numbertorawbytes text: Built-in Function Objects; url: sec-built-in-function-objects text: NativeError Object Structure; url: sec-nativeerror-object-structure + text: CreateArrayFromList; url: sec-createarrayfromlist + text: GetMethod; url: sec-getmethod + text: IterableToList; url: sec-iterabletolist type: abstract-op text: CreateMethodProperty; url: sec-createmethodproperty urlPrefix: https://webassembly.github.io/spec/core/; spec: WebAssembly; type: dfn @@ -101,13 +104,12 @@ urlPrefix: https://webassembly.github.io/spec/core/; spec: WebAssembly; type: df text: trap; url: exec/runtime.html#syntax-trap url: exec/runtime.html#values text: WebAssembly value - text: 𝗂𝟨𝟦.𝖼𝗈𝗇𝗌𝗍 - text: 𝗂𝟥𝟤.𝖼𝗈𝗇𝗌𝗍 - text: 𝖿𝟥𝟤.𝖼𝗈𝗇𝗌𝗍 - text: 𝖿𝟨𝟦.𝖼𝗈𝗇𝗌𝗍 + text: i64.const + text: i32.const + text: f32.const + text: f64.const text: ref.null text: ref.func - text: ref.host text: function index; url: syntax/modules.html#syntax-funcidx text: function instance; url: exec/runtime.html#function-instances text: store_init; url: appendix/embedding.html#embed-store-init @@ -143,29 +145,28 @@ urlPrefix: https://webassembly.github.io/spec/core/; spec: WebAssembly; type: df text: function address; url: exec/runtime.html#syntax-funcaddr text: memory address; url: exec/runtime.html#syntax-memaddr text: global address; url: exec/runtime.html#syntax-globaladdr - text: host address; url: exec/runtime.html#syntax-hostaddr url: syntax/types.html#syntax-numtype - text: 𝗂𝟥𝟤 - text: 𝗂𝟨𝟦 - text: 𝖿𝟥𝟤 - text: 𝖿𝟨𝟦 + text: i32 + text: i64 + text: f32 + text: f64 url: syntax/types.html#syntax-reftype - text: externref text: funcref + text: externref text: function element; url: exec/runtime.html#syntax-funcelem text: import component; url: syntax/modules.html#imports text: external value; url: exec/runtime.html#syntax-externval text: host function; url: exec/runtime.html#syntax-hostfunc text: the instantiation algorithm; url: exec/modules.html#instantiation text: module; url: syntax/modules.html#syntax-module - text: 𝗂𝗆𝗉𝗈𝗋𝗍𝗌; url: syntax/modules.html#syntax-module + text: imports; url: syntax/modules.html#syntax-module text: import; url: syntax/modules.html#syntax-import url: syntax/types.html#external-types text: external type - text: 𝖿𝗎𝗇𝖼 - text: 𝗍𝖺𝖻𝗅𝖾 - text: 𝗆𝖾𝗆 - text: 𝗀𝗅𝗈𝖻𝖺𝗅 + text: func + text: table + text: mem + text: global text: global type; url: syntax/types.html#syntax-globaltype url: syntax/types.html#syntax-mut text: var @@ -174,8 +175,8 @@ urlPrefix: https://webassembly.github.io/spec/core/; spec: WebAssembly; type: df text: signed_32; url: exec/numerics.html#aux-signed text: memory.grow; url: exec/instructions.html#exec-memory-grow text: current frame; url: exec/conventions.html#exec-notation-textual - text: 𝗆𝗈𝖽𝗎𝗅𝖾; url: exec/runtime.html#syntax-frame - text: 𝗆𝖾𝗆𝖺𝖽𝖽𝗋𝗌; url: exec/runtime.html#syntax-moduleinst + text: module; for: frame; url: exec/runtime.html#syntax-frame + text: memaddrs; for: moduleinst; url: exec/runtime.html#syntax-moduleinst text: sequence; url: syntax/conventions.html#grammar-notation urlPrefix: https://heycam.github.io/webidl/; spec: WebIDL type: dfn @@ -301,12 +302,10 @@ Note: 1. Return true. -
    A {{Module}} object represents a single WebAssembly module. Each {{Module}} object has the following internal slots: - * \[[Module]] : a WebAssembly [=module=] + * \[[Module]] : a WebAssembly [=/module=] * \[[Bytes]] : the source bytes of \[[Module]]. -
    To construct a WebAssembly module object from a module |module| and source bytes |bytes|, perform the following steps: @@ -339,24 +338,24 @@ A {{Module}} object represents a single WebAssembly module. Each {{Module}} obje
    To read the imports from a WebAssembly module |module| from imports object |importObject|, perform the following steps: - 1. If |module|.[=𝗂𝗆𝗉𝗈𝗋𝗍𝗌=] is not an empty list, and |importObject| is undefined, throw a {{TypeError}} exception. + 1. If |module|.[=imports=] is not an empty list, and |importObject| is undefined, throw a {{TypeError}} exception. 1. Let |imports| be an empty [=list=] of [=external value=]s. 1. [=list/iterate|For each=] (|moduleName|, |componentName|, |externtype|) of [=module_imports=](|module|), 1. Let |o| be ? [=Get=](|importObject|, |moduleName|). 1. If [=Type=](|o|) is not Object, throw a {{TypeError}} exception. 1. Let |v| be ? [=Get=](|o|, |componentName|). - 1. If |externtype| is of the form [=𝖿𝗎𝗇𝖼=] |functype|, + 1. If |externtype| is of the form [=func=] |functype|, 1. If [=IsCallable=](|v|) is false, throw a {{LinkError}} exception. 1. If |v| has a \[[FunctionAddress]] internal slot, and therefore is an [=Exported Function=], 1. Let |funcaddr| be the value of |v|'s \[[FunctionAddress]] internal slot. 1. Otherwise, 1. [=Create a host function=] from |v| and |functype|, and let |funcaddr| be the result. 1. Let |index| be the number of external functions in |imports|. This value |index| is known as the index of the host function |funcaddr|. - 1. Let |externfunc| be the [=external value=] [=external value|𝖿𝗎𝗇𝖼=] |funcaddr|. + 1. Let |externfunc| be the [=external value=] [=external value|func=] |funcaddr|. 1. [=list/Append=] |externfunc| to |imports|. - 1. If |externtype| is of the form [=𝗀𝗅𝗈𝖻𝖺𝗅=] mut |valtype|, + 1. If |externtype| is of the form [=global=] mut |valtype|, 1. If [=Type=](|v|) is Number, - 1. If |valtype| is [=𝗂𝟨𝟦=], throw a {{LinkError}} exception. + 1. If |valtype| is [=i64=], throw a {{LinkError}} exception. 1. Let |value| be [=ToWebAssemblyValue=](|v|, |valtype|). 1. Let |store| be the [=surrounding agent=]'s [=associated store=]. 1. Let (|store|, |globaladdr|) be [=global_alloc=](|store|, [=const=] |valtype|, |value|). @@ -365,16 +364,16 @@ A {{Module}} object represents a single WebAssembly module. Each {{Module}} obje 1. Let |globaladdr| be |v|.\[[Global]]. 1. Otherwise, 1. Throw a {{LinkError}} exception. - 1. Let |externglobal| be [=external value|𝗀𝗅𝗈𝖻𝖺𝗅=] |globaladdr|. + 1. Let |externglobal| be [=external value|global=] |globaladdr|. 1. [=list/Append=] |externglobal| to |imports|. - 1. If |externtype| is of the form [=𝗆𝖾𝗆=] memtype, + 1. If |externtype| is of the form [=mem=] memtype, 1. If |v| is not a {{Memory}} object, throw a {{LinkError}} exception. - 1. Let |externmem| be the [=external value=] [=external value|𝗆𝖾𝗆=] |v|.\[[Memory]]. + 1. Let |externmem| be the [=external value=] [=external value|mem=] |v|.\[[Memory]]. 1. [=list/Append=] |externmem| to |imports|. - 1. If |externtype| is of the form [=𝗍𝖺𝖻𝗅𝖾=] tabletype, + 1. If |externtype| is of the form [=table=] tabletype, 1. If |v| is not a {{Table}} instance, throw a {{LinkError}} exception. 1. Let |tableaddr| be |v|.\[[Table]]. - 1. Let |externtable| be the [=external value=] [=external value|𝗍𝖺𝖻𝗅𝖾=] |tableaddr|. + 1. Let |externtable| be the [=external value=] [=external value|table=] |tableaddr|. 1. [=list/Append=] |externtable| to |imports|. 1. Return |imports|. @@ -389,24 +388,24 @@ The verification of WebAssembly type requirements is deferred to the 1. [=list/iterate|For each=] (|name|, |externtype|) of [=module_exports=](|module|), 1. Let |externval| be [=instance_export=](|instance|, |name|). 1. Assert: |externval| is not [=error=]. - 1. If |externtype| is of the form [=𝖿𝗎𝗇𝖼=] functype, - 1. Assert: |externval| is of the form [=external value|𝖿𝗎𝗇𝖼=] |funcaddr|. - 1. Let [=external value|𝖿𝗎𝗇𝖼=] |funcaddr| be |externval|. + 1. If |externtype| is of the form [=func=] functype, + 1. Assert: |externval| is of the form [=external value|func=] |funcaddr|. + 1. Let [=external value|func=] |funcaddr| be |externval|. 1. Let |func| be the result of creating [=a new Exported Function=] from |funcaddr|. 1. Let |value| be |func|. - 1. If |externtype| is of the form [=𝗀𝗅𝗈𝖻𝖺𝗅=] globaltype, - 1. Assert: |externval| is of the form [=external value|𝗀𝗅𝗈𝖻𝖺𝗅=] |globaladdr|. - 1. Let [=external value|𝗀𝗅𝗈𝖻𝖺𝗅=] |globaladdr| be |externval|. + 1. If |externtype| is of the form [=global=] mut globaltype, + 1. Assert: |externval| is of the form [=external value|global=] |globaladdr|. + 1. Let [=external value|global=] |globaladdr| be |externval|. 1. Let |global| be [=create a global object|a new Global object=] created from |globaladdr|. 1. Let |value| be |global|. - 1. If |externtype| is of the form [=𝗆𝖾𝗆=] memtype, - 1. Assert: |externval| is of the form [=external value|𝗆𝖾𝗆=] |memaddr|. - 1. Let [=external value|𝗆𝖾𝗆=] |memaddr| be |externval|. + 1. If |externtype| is of the form [=mem=] memtype, + 1. Assert: |externval| is of the form [=external value|mem=] |memaddr|. + 1. Let [=external value|mem=] |memaddr| be |externval|. 1. Let |memory| be [=create a memory object|a new Memory object=] created from |memaddr|. 1. Let |value| be |memory|. - 1. Otherwise, |externtype| is of the form [=𝗍𝖺𝖻𝗅𝖾=] tabletype, - 1. Assert: |externval| is of the form [=external value|𝗍𝖺𝖻𝗅𝖾=] |tableaddr|. - 1. Let [=external value|𝗍𝖺𝖻𝗅𝖾=] |tableaddr| be |externval|. + 1. Otherwise, |externtype| is of the form [=table=] tabletype, + 1. Assert: |externval| is of the form [=external value|table=] |tableaddr|. + 1. Let [=external value|table=] |tableaddr| be |externval|. 1. Let |table| be [=create a Table object|a new Table object=] created from |tableaddr|. 1. Let |value| be |table|. 1. Let |status| be ! [=CreateDataProperty=](|exportsObject|, |name|, |value|). @@ -470,7 +469,7 @@ The verification of WebAssembly type requirements is deferred to the 1. Let |promise| be [=a new promise=]. 1. [=Upon fulfillment=] of |promiseOfModule| with value |module|: 1. [=instantiate a WebAssembly module|Instantiate the WebAssembly module=] |module| importing |importObject|, and let |instance| be the result. If this throws an exception, catch it, [=reject=] |promise| with the exception, and abort these substeps. - 1. Let |result| be a {{WebAssemblyInstantiatedSource}} dictionary with {{WebAssemblyInstantiatedSource/module}} set to |module| and {{WebAssemblyInstantiatedSource/instance}} set to |instance|. + 1. Let |result| be the {{WebAssemblyInstantiatedSource}} value «[ "{{WebAssemblyInstantiatedSource/module}}" → |module|, "{{WebAssemblyInstantiatedSource/instance}}" → |instance| ]». 1. [=Resolve=] |promise| with |result|. 1. [=Upon rejection=] of |promiseOfModule| with reason |reason|: 1. [=Reject=] |promise| with |reason|. @@ -526,10 +525,10 @@ interface Module {
    The string value of the extern type |type| is - * "function" if |type| is of the form [=𝖿𝗎𝗇𝖼=] functype - * "table" if |type| is of the form [=𝗍𝖺𝖻𝗅𝖾=] tabletype - * "memory" if |type| is of the form [=𝗆𝖾𝗆=] memtype - * "global" if |type| is of the form [=𝗀𝗅𝗈𝖻𝖺𝗅=] globaltype + * "function" if |type| is of the form [=func=] functype + * "table" if |type| is of the form [=table=] tabletype + * "memory" if |type| is of the form [=mem=] memtype + * "global" if |type| is of the form [=global=] globaltype
    @@ -538,8 +537,8 @@ interface Module { 1. Let |exports| be an empty [=list=]. 1. [=list/iterate|For each=] (|name|, |type|) of [=module_exports=](|module|), 1. Let |kind| be the [=string value of the extern type=] |type|. - 1. Let |obj| be a new {{ModuleExportDescriptor}} dictionary with {{ModuleExportDescriptor/name}} |name| and {{ModuleExportDescriptor/kind}} |kind|. - 1. [=list/Append=] |obj| to the end of |exports|. + 1. Let |obj| be «[ "{{ModuleExportDescriptor/name}}" → |name|, "{{ModuleExportDescriptor/kind}}" → |kind| ]». + 1. [=list/Append=] |obj| to |exports|. 1. Return |exports|.
    @@ -549,8 +548,8 @@ interface Module { 1. Let |imports| be an empty [=list=]. 1. [=list/iterate|For each=] (|moduleName|, |name|, |type|) of [=module_imports=](|module|), 1. Let |kind| be the [=string value of the extern type=] |type|. - 1. Let |obj| be a new {{ModuleImportDescriptor}} dictionary with {{ModuleImportDescriptor/module}} |moduleName|, {{ModuleImportDescriptor/name}} |name| and {{ModuleImportDescriptor/kind}} |kind|. - 1. [=list/Append=] |obj| to the end of |imports|. + 1. Let |obj| be «[ "{{ModuleImportDescriptor/module}}" → |moduleName|, "{{ModuleImportDescriptor/name}}" → |name|, "{{ModuleImportDescriptor/kind}}" → |kind| ]». + 1. [=list/Append=] |obj| to |imports|. 1. Return |imports|.
    @@ -614,14 +613,12 @@ interface Memory { };
    -
    A {{Memory}} object represents a single [=memory instance=] 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 -
    To create a memory buffer from a [=memory address=] |memaddr|, perform the following steps: @@ -656,7 +653,7 @@ which can be simultaneously referenced by multiple {{Instance}} objects. Each
    The Memory(|descriptor|) constructor, when invoked, performs the following steps: 1. Let |initial| be |descriptor|["initial"]. - 1. If |descriptor|["maximum"] is [=present=], let |maximum| be |descriptor|["maximum"]; otherwise, let |maximum| be empty. + 1. If |descriptor|["maximum"] [=map/exists=], 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 |store| be the [=surrounding agent=]'s [=associated store=]. @@ -691,10 +688,10 @@ which can be simultaneously referenced by multiple {{Instance}} objects. Each Immediately after a WebAssembly [=memory.grow=] instruction executes, perform the following steps:
    - 1. If the top of the stack is not [=𝗂𝟥𝟤.𝖼𝗈𝗇𝗌𝗍=] (−1), + 1. If the top of the stack is not [=i32.const=] (−1), 1. Let |frame| be the [=current frame=]. - 1. Assert: due to validation, |frame|.[=𝗆𝗈𝖽𝗎𝗅𝖾=].[=𝗆𝖾𝗆𝖺𝖽𝖽𝗋𝗌=][0] exists. - 1. Let |memaddr| be the memory address |frame|.[=𝗆𝗈𝖽𝗎𝗅𝖾=].[=𝗆𝖾𝗆𝖺𝖽𝖽𝗋𝗌=][0]. + 1. Assert: due to validation, |frame|.[=frame/module=].[=moduleinst/memaddrs=][0] exists. + 1. Let |memaddr| be the memory address |frame|.[=frame/module=].[=moduleinst/memaddrs=][0]. 1. [=Reset the memory buffer=] of |memaddr|.
    @@ -759,13 +756,13 @@ Each {{Table}} object has the following internal slots: The Table(|descriptor|, |value|) constructor, when invoked, performs the following steps: 1. Let |elementType| be ToValueType(descriptor|["element"]). 1. let |initial| be |descriptor|["initial"]. - 1. If |descriptor|["maximum"] is [=present=], let |maximum| be |descriptor|["maximum"]; otherwise, let |maximum| be empty. + 1. If |descriptor|["maximum"] [=map/exists=], let |maximum| be |descriptor|["maximum"]; otherwise, let |maximum| be empty. 1. If |maximum| is not empty and |maximum| < |initial|, throw a {{RangeError}} exception. 1. If |value| is missing, 1. Let |ref| be [=DefaultValue=](|elementType|). 1. Otherwise, 1. Let |ref| be ? [=ToWebAssemblyValue=](|value|, |elementType|). - 1. Let |type| be the [=table type=] {[=table type|𝗆𝗂𝗇=] |initial|, [=table type|𝗆𝖺𝗑=] |maximum|} |elementType|. + 1. Let |type| be the [=table type=] {[=table type|min=] |initial|, [=table type|ma𝗑=] |maximum|} [=table type|an𝗒func=]. 1. Let |store| be the [=surrounding agent=]'s [=associated store=]. 1. Let (|store|, |tableaddr|) be [=table_alloc=](|store|, |type|, |ref|). 1. Set the [=surrounding agent=]'s [=associated store=] to |store|. @@ -855,13 +852,11 @@ interface Global { }; -
    A {{Global}} object represents a single [=global instance=] which can be simultaneously referenced by multiple {{Instance}} objects. Each {{Global}} object has one internal slot: * \[[Global]] : a [=global address=] -
    To initialize a global object |global| from a [=global address=] |globaladdr|, perform the following steps: @@ -883,10 +878,10 @@ which can be simultaneously referenced by multiple {{Instance}} objects. Each
    The algorithm ToValueType(|s|) performs the following steps: - 1. If |s| equals "i32", return [=𝗂𝟥𝟤=]. - 1. If |s| equals "i64", return [=𝗂𝟨𝟦=]. - 1. If |s| equals "f32", return [=𝖿𝟥𝟤=]. - 1. If |s| equals "f64", return [=𝖿𝟨𝟦=]. + 1. If |s| equals "i32", return [=i32=]. + 1. If |s| equals "i64", return [=i64=]. + 1. If |s| equals "f32", return [=f32=]. + 1. If |s| equals "f64", return [=f64=]. 1. If |s| equals "funcref", return [=funcref=]. 1. If |s| equals "externref", return [=externref=]. 1. Assert: This step is not reached. @@ -894,10 +889,10 @@ which can be simultaneously referenced by multiple {{Instance}} objects. Each
    The algorithm DefaultValue(|valuetype|) performs the following steps: - 1. If |valuetype| equals [=𝗂𝟥𝟤=], return [=𝗂𝟥𝟤.𝖼𝗈𝗇𝗌𝗍=] 0. - 1. If |valuetype| equals [=𝗂𝟨𝟦=], return [=𝗂𝟨𝟦.𝖼𝗈𝗇𝗌𝗍=] 0. - 1. If |valuetype| equals [=𝖿𝟥𝟤=], return [=𝖿𝟥𝟤.𝖼𝗈𝗇𝗌𝗍=] 0. - 1. If |valuetype| equals [=𝖿𝟨𝟦=], return [=𝖿𝟨𝟦.𝖼𝗈𝗇𝗌𝗍=] 0. + 1. If |valuetype| equals [=i32=], return [=i32.const=] 0. + 1. If |valuetype| equals [=i64=], return [=i64.const=] 0. + 1. If |valuetype| equals [=f32=], return [=f32.const=] 0. + 1. If |valuetype| equals [=f64=], return [=f64.const=] 0. 1. If |valuetype| equals [=externref=], return [=ToWebAssemblyValue=](undefined, |valuetype|). 1. Assert: This step is not reached.
    @@ -909,7 +904,7 @@ which can be simultaneously referenced by multiple {{Instance}} objects. Each 1. If |v| is missing, 1. let |value| be [=DefaultValue=](|valuetype|). 1. Otherwise, - 1. If |valuetype| is [=𝗂𝟨𝟦=], throw a {{TypeError}} exception. + 1. If |valuetype| is [=i64=], throw a {{TypeError}} exception. 1. Let |value| be [=ToWebAssemblyValue=](|v|, |valuetype|). 1. If |mutable| is true, let |globaltype| be [=var=] |valuetype|; otherwise, let |globaltype| be [=const=] |valuetype|. 1. Let |store| be the current agent's [=associated store=]. @@ -923,7 +918,7 @@ which can be simultaneously referenced by multiple {{Instance}} objects. Each 1. Let |store| be the current agent's [=associated store=]. 1. Let |globaladdr| be |global|.\[[Global]]. 1. Let |globaltype| be [=global_type=](|store|, |globaladdr|). - 1. If |globaltype| is of the form mut [=𝗂𝟨𝟦=], throw a {{TypeError}}. + 1. If |globaltype| is of the form mut [=i64=], throw a {{TypeError}}. 1. Let |value| be [=global_read=](|store|, |globaladdr|). 1. Return [=ToJSValue=](|value|).
    @@ -935,9 +930,9 @@ which can be simultaneously referenced by multiple {{Instance}} objects. Each The setter of the value attribute of {{Global}}, when invoked, performs the following steps: 1. Let |store| be the current agent's [=associated store=]. 1. Let |globaladdr| be **this**.\[[Global]]. - 1. Let |globaltype| be [=global_type=](|store|, |globaladdr|), where |globaltype| is of the form |mut| |valuetype|. + 1. Let |mut| |valuetype| be [=global_type=](|store|, |globaladdr|). 1. If |mut| is [=const=], throw a {{TypeError}}. - 1. If |valuetype| is [=𝗂𝟨𝟦=], throw a {{TypeError}}. + 1. If |valuetype| is [=i64=], throw a {{TypeError}}. 1. Let |value| be [=ToWebAssemblyValue=](**the given value**, |valuetype|). 1. Let |store| be [=global_write=](|store|, |globaladdr|, |value|). 1. If |store| is [=error=], throw a {{RangeError}} exception. @@ -959,14 +954,14 @@ This slot holds a [=function address=] relative to the [=surrounding agent=]'s [ The name of the WebAssembly function |funcaddr| is found by performing the following steps: 1. Let |store| be the [=surrounding agent=]'s [=associated store=]. - 1. Let |funcinst| be |store|.𝖿𝗎𝗇𝖼𝗌[|funcaddr|]. - 1. If |funcinst| is of the form {𝗍𝗒𝗉𝖾 functype, 𝗁𝗈𝗌𝗍𝖼𝗈𝖽𝖾 |hostfunc|}, + 1. Let |funcinst| be |store|.funcs[|funcaddr|]. + 1. If |funcinst| is of the form {t𝗒pe functype, 𝗁ostcode |hostfunc|}, 1. Assert: |hostfunc| is a JavaScript object and [=IsCallable=](|hostfunc|) is true. 1. Let |index| be the [=index of the host function=] |funcaddr|. 1. Otherwise, - 1. Let |moduleinst| be |funcinst|.𝗆𝗈𝖽𝗎𝗅𝖾. - 1. Assert: |funcaddr| is contained in |moduleinst|.𝖿𝗎𝗇𝖼𝖺𝖽𝖽𝗋𝗌. - 1. Let |index| be the index of |moduleinst|.𝖿𝗎𝗇𝖼𝖺𝖽𝖽𝗋𝗌 where |funcaddr| is found. + 1. Let |moduleinst| be |funcinst|.module. + 1. Assert: |funcaddr| is contained in |moduleinst|.funcaddrs. + 1. Let |index| be the index of |moduleinst|.funcaddrs where |funcaddr| is found. 1. Return ! [=ToString=](|index|).
    @@ -997,7 +992,7 @@ This slot holds a [=function address=] relative to the [=surrounding agent=]'s [ 1. Let |store| be the [=surrounding agent=]'s [=associated store=]. 1. Let |functype| be [=func_type=](|store|, |funcaddr|). 1. Let [|parameters|] → [|results|] be |functype|. - 1. If |parameters| or |results| contains an [=𝗂𝟨𝟦=], throw a {{TypeError}}. + 1. If |parameters| or |results| contains an [=i64=], throw a {{TypeError}}. Note: the above error is thrown each time the \[[Call]] method is invoked. @@ -1012,8 +1007,13 @@ This slot holds a [=function address=] relative to the [=surrounding agent=]'s [ 1. Let (|store|, |ret|) be the result of [=func_invoke=](|store|, |funcaddr|, |argsSeq|). 1. Set the [=surrounding agent=]'s [=associated store=] to |store|. 1. If |ret| is [=error=], throw an exception. This exception should be a WebAssembly {{RuntimeError}} exception, unless otherwise indicated by the WebAssembly error mapping. - 1. If |ret| is empty, return undefined. - 1. Otherwise, return [=ToJSValue=](|v|), where |v| is the singular element of |ret|. + 1. Let |outArity| be the [=list/size=] of |ret|. + 1. If |outArity| is 0, return undefined. + 1. Otherwise, if |outArity| is 1, return [=ToJSValue=](|ret|[0]). + 1. Otherwise, + 1. Let |values| be a new, empty [=list=]. + 1. For each |r| in |ret|, [=list/append=] [=ToJSValue=](|r|) to |values|. + 1. Return [=CreateArrayFromList=](|values|).
    Note: [=call an Exported Function|Calling an Exported Function=] executes in the \[[Realm]] of the callee Exported Function, as per the definition of [=built-in function objects=]. @@ -1024,14 +1024,23 @@ Note: Exported Functions do not have a \[[Construct]] method and thus it is not To run a host function from the JavaScript object |func|, type |functype|, and [=list=] of [=WebAssembly values=] |arguments|, perform the following steps: 1. Let [|parameters|] → [|results|] be |functype|. - 1. Assert: |results|'s [=list/size=] is at most one. - 1. If either |parameters| or |results| contains [=𝗂𝟨𝟦=], throw a {{TypeError}}. + 1. If either |parameters| or |results| contains [=i64=], throw a {{TypeError}}. 1. Let |jsArguments| be an empty [=list=]. 1. [=list/iterate|For each=] |arg| of |arguments|, 1. [=list/Append=] ! [=ToJSValue=](|arg|) to |jsArguments|. 1. Let |ret| be ? [=Call=](|func|, undefined, |jsArguments|). - 1. If |results| [=list/is empty=], return « ». - 1. Otherwise, return « ? [=ToWebAssemblyValue=](|ret|, |results|[0]) ». + 1. Let |resultsSize| be |results|'s [=list/size=]. + 1. If |resultsSize| is 0, return « ». + 1. Otherwise, if |resultsSize| is 1, return « ? [=ToWebAssemblyValue=](|ret|, |results|[0]) ». + 1. Otherwise, + 1. Let |method| be ? [=GetMethod=](|ret|, [=@@iterator=]). + 1. If |method| is undefined, [=throw=] a {{TypeError}}. + 1. Let |values| be ? [=IterableToList=](|ret|, |method|). + 1. Let |wasmValues| be a new, empty [=list=]. + 1. If |values|'s [=list/size=] is not |resultsSize|, throw a {{TypeError}} exception. + 1. For each |value| and |resultType| in |values| and |results|, paired linearly, + 1. [=list/Append=] [=ToWebAssemblyValue=](|value|, |resultType|) to |wasmValues|. + 1. Return |wasmValues|.
    @@ -1052,10 +1061,10 @@ Note: Exported Functions do not have a \[[Construct]] method and thus it is not
    The algorithm ToJSValue(|w|) coerces a [=WebAssembly value=] to a JavaScript value by performing the following steps: -1. Assert: |w| is not of the form [=𝗂𝟨𝟦.𝖼𝗈𝗇𝗌𝗍=] i64. -1. If |w| is of the form [=𝗂𝟥𝟤.𝖼𝗈𝗇𝗌𝗍=] |i32|, return [=the Number value=] for [=signed_32=](|i32|). -1. If |w| is of the form [=𝖿𝟥𝟤.𝖼𝗈𝗇𝗌𝗍=] |f32|, return [=the Number value=] for |f32|. -1. If |w| is of the form [=𝖿𝟨𝟦.𝖼𝗈𝗇𝗌𝗍=] |f64|, return [=the Number value=] for |f64|. +1. Assert: |w| is not of the form [=i64.const=] i64. +1. If |w| is of the form [=i32.const=] |i32|, return [=the Number value=] for [=signed_32=](|i32|). +1. If |w| is of the form [=f32.const=] |f32|, return [=the Number value=] for |f32|. +1. If |w| is of the form [=f64.const=] |f64|, return [=the Number value=] for |f64|. 1. If |w| is of the form [=ref.null=], return null. 1. If |w| is of the form [=ref.func=] |funcaddr|, return the result of creating [=a new Exported Function=] from |funcaddr|. 1. If |w| is of the form [=ref.host=] |hostaddr|, return the result of [=retrieving a host value=] from |hostaddr|. @@ -1076,16 +1085,16 @@ Note: Number values which are equal to NaN may have various observable NaN paylo The algorithm ToWebAssemblyValue(|v|, |type|) coerces a JavaScript value to a [=WebAssembly value=] performs the following steps: -1. Assert: |type| is not [=𝗂𝟨𝟦=]. -1. If |type| is [=𝗂𝟥𝟤=], +1. Assert: |type| is not [=i64=]. +1. If |type| is [=i32=], 1. Let |i32| be ? [=ToInt32=](|v|). - 1. Return [=𝗂𝟥𝟤.𝖼𝗈𝗇𝗌𝗍=] |i32|. -1. If |type| is [=𝖿𝟥𝟤=], + 1. Return [=i32.const=] |i32|. +1. If |type| is [=f32=], 1. Let |f32| be ? [=ToNumber=](|v|) rounded to the nearest representable value using IEEE 754-2008 round to nearest, ties to even mode. - 1. Return [=𝖿𝟥𝟤.𝖼𝗈𝗇𝗌𝗍=] |f32|. -1. If |type| is [=𝖿𝟨𝟦=], + 1. Return [=f32.const=] |f32|. +1. If |type| is [=f64=], 1. Let |f64| be ? [=ToNumber=](|v|). - 1. Return [=𝖿𝟨𝟦.𝖼𝗈𝗇𝗌𝗍=] |f64|. + 1. Return [=f64.const=] |f64|. 1. Assert: |type| is a reference type. 1. If |type| is [=externref=], 1. Do nothing. @@ -1193,11 +1202,10 @@ In practice, an implementation may run out of resources for valid modules below
  • The maximum size of a table is 10000000.
  • The maximum number of table entries in any table initialization is 10000000.
  • The maximum number of memories, including declared or imported memories, is 1.
  • -
  • The initial number of pages for any memory, declared or imported, is at most 32767.
  • -
  • The maximum number of pages for any memory, declared or imported, is at most 65536.
  • +
  • The initial or maximum number of pages for any memory, declared or imported, is at most 65536.
  • -
  • The maximum number of parameters to any function is 1000.
  • -
  • The maximum number of return values for any function is 1.
  • +
  • The maximum number of parameters to any function or block is 1000.
  • +
  • The maximum number of return values for any function or block is 1000.
  • The maximum size of a function body, including locals declarations, is 7654321 bytes.
  • The maximum number of locals declared in a function, including implicitly declared as parameters, is 50000.
  • diff --git a/document/web-api/index.bs b/document/web-api/index.bs index de9df38b1b..10c41060b5 100644 --- a/document/web-api/index.bs +++ b/document/web-api/index.bs @@ -273,7 +273,7 @@ application/wasm
    None
    Person & email address to contact for further information:
    -
    Eric Prud'hommeaux
    +
    Eric Prud'hommeaux <eric@w3.org>
    Intended usage:
    Common
    Restrictions on usage:
    diff --git a/interpreter/Makefile b/interpreter/Makefile index b726ced610..2948ddb5cb 100644 --- a/interpreter/Makefile +++ b/interpreter/Makefile @@ -126,7 +126,7 @@ debugtest/%: $(UNOPT) run/%: $(OPT) ./$(OPT) $(@:run/%=../test/core/%.wast) -debug/%: $(UNOPT) +debug/%: $(UNOPT) ./$(UNOPT) $(@:debug/%=../test/core/%.wast) diff --git a/interpreter/README.md b/interpreter/README.md index 8af4fd7795..5377223145 100644 --- a/interpreter/README.md +++ b/interpreter/README.md @@ -164,8 +164,8 @@ The implementation consumes a WebAssembly AST given in S-expression syntax. Here Note: The grammar is shown here for convenience, the definite source is the [specification of the text format](https://webassembly.github.io/spec/core/text/). ``` -num: (_? )* -hexnum: (_? )* +num: (_? )* +hexnum: (_? )* nat: | 0x int: | + | - float: .?(e|E )? | 0x.?(p|P )? @@ -334,7 +334,6 @@ script: * cmd: ;; define, validate, and initialize module ( register ? ) ;; register module for imports -module with given failure string ;; perform action and print results ;; assert result of an action ;; meta command @@ -388,11 +387,61 @@ A module of the form `(module quote *)` is given in textual form and wil There are also a number of meta commands. The `script` command is a simple mechanism to name sub-scripts themselves. This is mainly useful for converting scripts with the `output` command. Commands inside a `script` will be executed normally, but nested meta are expanded in place (`input`, recursively) or elided (`output`) in the named script. -The `input` and `output` meta commands determine the requested file format from the file name extension. They can handle both `.wasm`, `.wat`, and `.wast` files. In the case of input, a `.wast` script will be recursively executed. Output additionally handles `.js` as a target, which will convert the referenced script to an equivalent, self-contained JavaScript runner. It also recognises `.bin.wast` specially, which creates a script where module definitions are in binary. +The `input` and `output` meta commands determine the requested file format from the file name extension. They can handle both `.wasm`, `.wat`, and `.wast` files. In the case of input, a `.wast` script will be recursively executed. Output additionally handles `.js` as a target, which will convert the referenced script to an equivalent, self-contained JavaScript runner. It also recognises `.bin.wast` specially, which creates a _binary script_ where module definitions are in binary, as defined below. The interpreter supports a "dry" mode (flag `-d`), in which modules are only validated. In this mode, all actions and assertions are ignored. It also supports an "unchecked" mode (flag `-u`), in which module definitions are not validated before use. +### Binary Scripts + +The grammar of binary scripts is a subset of the grammar for general scripts: +``` +binscript: * + +cmd: + ;; define, validate, and initialize module + ( register ? ) ;; register module for imports + ;; perform action and print results + ;; assert result of an action + +module: + ( module ? binary * ) ;; module in binary format (may be malformed) + +action: + ( invoke ? * ) ;; invoke function export + ( get ? ) ;; get global export + +assertion: + ( assert_return * ) ;; assert action has expected results + ( assert_trap ) ;; assert action traps with given failure string + ( assert_exhaustion ) ;; assert action exhausts system resources + ( assert_malformed ) ;; assert module cannot be decoded with given failure string + ( assert_invalid ) ;; assert module is invalid with given failure string + ( assert_unlinkable ) ;; assert module fails to link + ( assert_trap ) ;; assert module traps on instantiation + +result: + ( .const ) + +numpat: + ;; literal result + nan:canonical ;; NaN in canonical form + nan:arithmetic ;; NaN with 1 in MSB of payload + +value: | +int: 0x +float: 0x.?(p|P )? +hexnum: (_? )* + +name: $( | | _ | . | + | - | * | / | \ | ^ | ~ | = | < | > | ! | ? | @ | # | $ | % | & | | | : | ' | `)+ +string: "( | \n | \t | \\ | \' | \" | \ | \u{+})*" +``` +This grammar removes meta commands, textual and quoted modules. +All numbers are in hex notation. + +Moreover, float values are required to be precise, that is, they may not contain bits that would lead to rounding. + + ## Abstract Syntax The abstract WebAssembly syntax, as described above and in the [design doc](https://github.com/WebAssembly/design/blob/master/Semantics.md), is defined in [ast.ml](syntax/ast.ml). diff --git a/interpreter/binary/decode.ml b/interpreter/binary/decode.ml index 4c1b135f3c..e9561c4c52 100644 --- a/interpreter/binary/decode.ml +++ b/interpreter/binary/decode.ml @@ -100,6 +100,7 @@ let vu1 s = Int64.to_int (vuN 1 s) let vu32 s = Int64.to_int32 (vuN 32 s) let vs7 s = Int64.to_int (vsN 7 s) let vs32 s = Int64.to_int32 (vsN 32 s) +let vs33 s = I32_convert.wrap_i64 (vsN 33 s) let vs64 s = vsN 64 s let f32 s = F32.of_bits (u32 s) let f64 s = F64.of_bits (u64 s) @@ -152,16 +153,12 @@ let value_type s = | Some n when n > 0x70 -> NumType (num_type s) | _ -> RefType (ref_type s) -let stack_type s = - match peek s with - | Some 0x40 -> skip 1 s; [] - | _ -> [value_type s] - +let stack_type s = vec value_type s let func_type s = match vs7 s with | -0x20 -> - let ins = vec value_type s in - let out = vec value_type s in + let ins = stack_type s in + let out = stack_type s in FuncType (ins, out) | _ -> error s (pos s - 1) "malformed function type" @@ -209,6 +206,12 @@ let memop s = let offset = vu32 s in Int32.to_int align, offset +let block_type s = + match peek s with + | Some 0x40 -> skip 1 s; ValBlockType None + | Some b when b land 0xc0 = 0x40 -> ValBlockType (Some (value_type s)) + | _ -> VarBlockType (at vs33 s) + let rec instr s = let pos = pos s in match op s with @@ -216,26 +219,26 @@ let rec instr s = | 0x01 -> nop | 0x02 -> - let ts = stack_type s in + let bt = block_type s in let es' = instr_block s in end_ s; - block ts es' + block bt es' | 0x03 -> - let ts = stack_type s in + let bt = block_type s in let es' = instr_block s in end_ s; - loop ts es' + loop bt es' | 0x04 -> - let ts = stack_type s in + let bt = block_type s in let es1 = instr_block s in if peek s = Some 0x05 then begin expect 0x05 s "ELSE or END opcode expected"; let es2 = instr_block s in end_ s; - if_ ts es1 es2 + if_ bt es1 es2 end else begin end_ s; - if_ ts es1 [] + if_ bt es1 [] end | 0x05 -> error s pos "misplaced ELSE opcode" @@ -440,8 +443,14 @@ let rec instr s = | 0xbe -> f32_reinterpret_i32 | 0xbf -> f64_reinterpret_i64 - | 0xc0 | 0xc1 | 0xc2 | 0xc3 | 0xc4 | 0xc5 | 0xc6 | 0xc7 - | 0xc8 | 0xc9 | 0xca | 0xcb | 0xcc | 0xcd | 0xce | 0xcf as b -> illegal s pos b + | 0xc0 -> i32_extend8_s + | 0xc1 -> i32_extend16_s + | 0xc2 -> i64_extend8_s + | 0xc3 -> i64_extend16_s + | 0xc4 -> i64_extend32_s + + | 0xc5 | 0xc6 | 0xc7 | 0xc8 | 0xc9 | 0xca | 0xcb + | 0xcc | 0xcd | 0xce | 0xcf as b -> illegal s pos b | 0xd0 -> ref_null (ref_type s) | 0xd1 -> ref_is_null (ref_type s) @@ -449,8 +458,14 @@ let rec instr s = | 0xfc as b1 -> (match op s with - | 0x00 | 0x01 | 0x02 | 0x03 | 0x04 | 0x05 | 0x06 | 0x07 as b2 -> - illegal2 s pos b1 b2 + | 0x00 -> i32_trunc_sat_f32_s + | 0x01 -> i32_trunc_sat_f32_u + | 0x02 -> i32_trunc_sat_f64_s + | 0x03 -> i32_trunc_sat_f64_u + | 0x04 -> i64_trunc_sat_f32_s + | 0x05 -> i64_trunc_sat_f32_u + | 0x06 -> i64_trunc_sat_f64_s + | 0x07 -> i64_trunc_sat_f64_u | 0x08 -> let x = at var s in diff --git a/interpreter/binary/encode.ml b/interpreter/binary/encode.ml index c0263df559..0132d0d4eb 100644 --- a/interpreter/binary/encode.ml +++ b/interpreter/binary/encode.ml @@ -60,6 +60,7 @@ let encode m = let vu32 i = vu64 Int64.(logand (of_int32 i) 0xffffffffL) let vs7 i = vs64 (Int64.of_int i) let vs32 i = vs64 (Int64.of_int32 i) + let vs33 i = vs64 (I64_convert.extend_i32_s i) let f32 x = u32 (F32.to_bits x) let f64 x = u64 (F64.to_bits x) @@ -104,16 +105,9 @@ let encode m = | NumType t -> num_type t | RefType t -> ref_type t - let stack_type = function - | [] -> vs7 (-0x40) - | [t] -> value_type t - | _ -> - Code.error Source.no_region - "cannot encode stack type with arity > 1 (yet)" - let func_type = function - | FuncType (ins, out) -> - vs7 (-0x20); vec value_type ins; vec value_type out + | FuncType (ts1, ts2) -> + vs7 (-0x20); vec value_type ts1; vec value_type ts2 let limits vu {min; max} = bool (max <> None); vu min; opt vu max @@ -136,7 +130,6 @@ let encode m = open Source open Ast open Values - open Memory let op n = u8 n let end_ () = op 0x0b @@ -145,15 +138,20 @@ let encode m = let var x = vu32 x.it + let block_type = function + | VarBlockType x -> vs33 x.it + | ValBlockType None -> vs7 (-0x40) + | ValBlockType (Some t) -> value_type t + let rec instr e = match e.it with | Unreachable -> op 0x00 | Nop -> op 0x01 - | Block (ts, es) -> op 0x02; stack_type ts; list instr es; end_ () - | Loop (ts, es) -> op 0x03; stack_type ts; list instr es; end_ () - | If (ts, es1, es2) -> - op 0x04; stack_type ts; list instr es1; + | Block (bt, es) -> op 0x02; block_type bt; list instr es; end_ () + | Loop (bt, es) -> op 0x03; block_type bt; list instr es; end_ () + | If (bt, es1, es2) -> + op 0x04; block_type bt; list instr es1; if es2 <> [] then op 0x05; list instr es2; end_ () @@ -284,10 +282,16 @@ let encode m = | Unary (I32 I32Op.Clz) -> op 0x67 | Unary (I32 I32Op.Ctz) -> op 0x68 | Unary (I32 I32Op.Popcnt) -> op 0x69 + | Unary (I32 (I32Op.ExtendS Pack8)) -> op 0xc0 + | Unary (I32 (I32Op.ExtendS Pack16)) -> op 0xc1 + | Unary (I32 (I32Op.ExtendS Pack32)) -> assert false | Unary (I64 I64Op.Clz) -> op 0x79 | Unary (I64 I64Op.Ctz) -> op 0x7a | Unary (I64 I64Op.Popcnt) -> op 0x7b + | Unary (I64 (I64Op.ExtendS Pack8)) -> op 0xc2 + | Unary (I64 (I64Op.ExtendS Pack16)) -> op 0xc3 + | Unary (I64 (I64Op.ExtendS Pack32)) -> op 0xc4 | Unary (F32 F32Op.Abs) -> op 0x8b | Unary (F32 F32Op.Neg) -> op 0x8c @@ -360,6 +364,10 @@ let encode m = | Convert (I32 I32Op.TruncUF32) -> op 0xa9 | Convert (I32 I32Op.TruncSF64) -> op 0xaa | Convert (I32 I32Op.TruncUF64) -> op 0xab + | Convert (I32 I32Op.TruncSatSF32) -> op 0xfc; op 0x00 + | Convert (I32 I32Op.TruncSatUF32) -> op 0xfc; op 0x01 + | Convert (I32 I32Op.TruncSatSF64) -> op 0xfc; op 0x02 + | Convert (I32 I32Op.TruncSatUF64) -> op 0xfc; op 0x03 | Convert (I32 I32Op.ReinterpretFloat) -> op 0xbc | Convert (I64 I64Op.ExtendSI32) -> op 0xac @@ -369,6 +377,10 @@ let encode m = | Convert (I64 I64Op.TruncUF32) -> op 0xaf | Convert (I64 I64Op.TruncSF64) -> op 0xb0 | Convert (I64 I64Op.TruncUF64) -> op 0xb1 + | Convert (I64 I64Op.TruncSatSF32) -> op 0xfc; op 0x04 + | Convert (I64 I64Op.TruncSatUF32) -> op 0xfc; op 0x05 + | Convert (I64 I64Op.TruncSatSF64) -> op 0xfc; op 0x06 + | Convert (I64 I64Op.TruncSatUF64) -> op 0xfc; op 0x07 | Convert (I64 I64Op.ReinterpretFloat) -> op 0xbd | Convert (F32 F32Op.ConvertSI32) -> op 0xb2 diff --git a/interpreter/exec/eval.ml b/interpreter/exec/eval.ml index aae2a0ce5b..813f75d4f7 100644 --- a/interpreter/exec/eval.ml +++ b/interpreter/exec/eval.ml @@ -62,8 +62,8 @@ and admin_instr' = | Trapping of string | Returning of value stack | Breaking of int32 * value stack - | Label of int * instr list * code - | Frame of int * frame * code + | Label of int32 * instr list * code + | Frame of int32 * frame * code type config = { @@ -100,11 +100,21 @@ let func_ref inst x i at = | NullRef _ -> Trap.error at ("uninitialized element " ^ Int32.to_string i) | _ -> Crash.error at ("type mismatch for element " ^ Int32.to_string i) +let func_type_of = function + | Func.AstFunc (t, inst, f) -> t + | Func.HostFunc (t, _) -> t + +let block_type inst bt = + match bt with + | VarBlockType x -> type_ inst x + | ValBlockType None -> FuncType ([], []) + | ValBlockType (Some t) -> FuncType ([], [t]) + let take n (vs : 'a stack) at = - try Lib.List.take n vs with Failure _ -> Crash.error at "stack underflow" + try Lib.List32.take n vs with Failure _ -> Crash.error at "stack underflow" let drop n (vs : 'a stack) at = - try Lib.List.drop n vs with Failure _ -> Crash.error at "stack underflow" + try Lib.List32.drop n vs with Failure _ -> Crash.error at "stack underflow" (* Evaluation *) @@ -147,17 +157,24 @@ let rec step (c : config) : config = | Nop, vs -> vs, [] - | Block (ts, es'), vs -> - vs, [Label (List.length ts, [], ([], List.map plain es')) @@ e.at] + | Block (bt, es'), vs -> + let FuncType (ts1, ts2) = block_type frame.inst bt in + let n1 = Lib.List32.length ts1 in + let n2 = Lib.List32.length ts2 in + let args, vs' = take n1 vs e.at, drop n1 vs e.at in + vs', [Label (n2, [], (args, List.map plain es')) @@ e.at] - | Loop (ts, es'), vs -> - vs, [Label (0, [e' @@ e.at], ([], List.map plain es')) @@ e.at] + | Loop (bt, es'), vs -> + let FuncType (ts1, ts2) = block_type frame.inst bt in + let n1 = Lib.List32.length ts1 in + let args, vs' = take n1 vs e.at, drop n1 vs e.at in + vs', [Label (n1, [e' @@ e.at], (args, List.map plain es')) @@ e.at] - | If (ts, es1, es2), Num (I32 i) :: vs' -> + | If (bt, es1, es2), Num (I32 i) :: vs' -> if i = 0l then - vs', [Plain (Block (ts, es2)) @@ e.at] + vs', [Plain (Block (bt, es2)) @@ e.at] else - vs', [Plain (Block (ts, es1)) @@ e.at] + vs', [Plain (Block (bt, es1)) @@ e.at] | Br x, vs -> [], [Breaking (x.it, vs) @@ e.at] @@ -344,7 +361,7 @@ let rec step (c : config) : config = Plain (Const (I32 i @@ e.at)); Plain (Const (k @@ e.at)); Plain (Store - {ty = I32Type; align = 0; offset = 0l; sz = Some Memory.Pack8}); + {ty = I32Type; align = 0; offset = 0l; sz = Some Pack8}); Plain (Const (I32 (I32.add i 1l) @@ e.at)); Plain (Const (k @@ e.at)); Plain (Const (I32 (I32.sub n 1l) @@ e.at)); @@ -361,9 +378,9 @@ let rec step (c : config) : config = Plain (Const (I32 d @@ e.at)); Plain (Const (I32 s @@ e.at)); Plain (Load - {ty = I32Type; align = 0; offset = 0l; sz = Some Memory.(Pack8, ZX)}); + {ty = I32Type; align = 0; offset = 0l; sz = Some (Pack8, ZX)}); Plain (Store - {ty = I32Type; align = 0; offset = 0l; sz = Some Memory.Pack8}); + {ty = I32Type; align = 0; offset = 0l; sz = Some Pack8}); Plain (Const (I32 (I32.add d 1l) @@ e.at)); Plain (Const (I32 (I32.add s 1l) @@ e.at)); Plain (Const (I32 (I32.sub n 1l) @@ e.at)); @@ -378,9 +395,9 @@ let rec step (c : config) : config = Plain (Const (I32 d @@ e.at)); Plain (Const (I32 s @@ e.at)); Plain (Load - {ty = I32Type; align = 0; offset = 0l; sz = Some Memory.(Pack8, ZX)}); + {ty = I32Type; align = 0; offset = 0l; sz = Some (Pack8, ZX)}); Plain (Store - {ty = I32Type; align = 0; offset = 0l; sz = Some Memory.Pack8}); + {ty = I32Type; align = 0; offset = 0l; sz = Some Pack8}); ] | MemoryInit x, Num (I32 n) :: Num (I32 s) :: Num (I32 d) :: vs' -> @@ -395,7 +412,7 @@ let rec step (c : config) : config = Plain (Const (I32 d @@ e.at)); Plain (Const (I32 b @@ e.at)); Plain (Store - {ty = I32Type; align = 0; offset = 0l; sz = Some Memory.Pack8}); + {ty = I32Type; align = 0; offset = 0l; sz = Some Pack8}); Plain (Const (I32 (I32.add d 1l) @@ e.at)); Plain (Const (I32 (I32.add s 1l) @@ e.at)); Plain (Const (I32 (I32.sub n 1l) @@ e.at)); @@ -500,15 +517,15 @@ let rec step (c : config) : config = Exhaustion.error e.at "call stack exhausted" | Invoke func, vs -> - let FuncType (ins, out) = Func.type_of func in - let n = List.length ins in - let args, vs' = take n vs e.at, drop n vs e.at in + let FuncType (ins, out) = func_type_of func in + let n1, n2 = Lib.List32.length ins, Lib.List32.length out in + let args, vs' = take n1 vs e.at, drop n1 vs e.at in (match func with | Func.AstFunc (t, inst', f) -> let locals' = List.rev args @ List.map default_value f.it.locals in - let code' = [], [Plain (Block (out, f.it.body)) @@ f.at] in let frame' = {inst = !inst'; locals = List.map ref locals'} in - vs', [Frame (List.length out, frame', code') @@ e.at] + let instr' = [Label (n2, [], ([], List.map plain f.it.body)) @@ f.at] in + vs', [Frame (n2, frame', ([], instr')) @@ e.at] | Func.HostFunc (t, f) -> try List.rev (f (List.rev args)) @ vs', [] diff --git a/interpreter/exec/eval_numeric.ml b/interpreter/exec/eval_numeric.ml index 0294557993..3caf4d45e7 100644 --- a/interpreter/exec/eval_numeric.ml +++ b/interpreter/exec/eval_numeric.ml @@ -54,6 +54,7 @@ struct | Clz -> IXX.clz | Ctz -> IXX.ctz | Popcnt -> IXX.popcnt + | ExtendS sz -> IXX.extend_s (8 * packed_size sz) in fun v -> to_num (f (of_num 1 v)) let binop op = @@ -154,13 +155,17 @@ struct let cvtop op v = let i = match op with | WrapI64 -> I32_convert.wrap_i64 (I64Num.of_num 1 v) - | TruncSF32 -> I32_convert.trunc_f32_s (F32Num.of_num 1 v) | TruncUF32 -> I32_convert.trunc_f32_u (F32Num.of_num 1 v) - | TruncSF64 -> I32_convert.trunc_f64_s (F64Num.of_num 1 v) + | TruncSF32 -> I32_convert.trunc_f32_s (F32Num.of_num 1 v) | TruncUF64 -> I32_convert.trunc_f64_u (F64Num.of_num 1 v) + | TruncSF64 -> I32_convert.trunc_f64_s (F64Num.of_num 1 v) + | TruncSatUF32 -> I32_convert.trunc_sat_f32_u (F32Num.of_num 1 v) + | TruncSatSF32 -> I32_convert.trunc_sat_f32_s (F32Num.of_num 1 v) + | TruncSatUF64 -> I32_convert.trunc_sat_f64_u (F64Num.of_num 1 v) + | TruncSatSF64 -> I32_convert.trunc_sat_f64_s (F64Num.of_num 1 v) | ReinterpretFloat -> I32_convert.reinterpret_f32 (F32Num.of_num 1 v) - | ExtendSI32 -> raise (TypeError (1, v, I32Type)) | ExtendUI32 -> raise (TypeError (1, v, I32Type)) + | ExtendSI32 -> raise (TypeError (1, v, I32Type)) in I32Num.to_num i end @@ -170,12 +175,16 @@ struct let cvtop op v = let i = match op with - | ExtendSI32 -> I64_convert.extend_i32_s (I32Num.of_num 1 v) | ExtendUI32 -> I64_convert.extend_i32_u (I32Num.of_num 1 v) - | TruncSF32 -> I64_convert.trunc_f32_s (F32Num.of_num 1 v) + | ExtendSI32 -> I64_convert.extend_i32_s (I32Num.of_num 1 v) | TruncUF32 -> I64_convert.trunc_f32_u (F32Num.of_num 1 v) - | TruncSF64 -> I64_convert.trunc_f64_s (F64Num.of_num 1 v) + | TruncSF32 -> I64_convert.trunc_f32_s (F32Num.of_num 1 v) | TruncUF64 -> I64_convert.trunc_f64_u (F64Num.of_num 1 v) + | TruncSF64 -> I64_convert.trunc_f64_s (F64Num.of_num 1 v) + | TruncSatUF32 -> I64_convert.trunc_sat_f32_u (F32Num.of_num 1 v) + | TruncSatSF32 -> I64_convert.trunc_sat_f32_s (F32Num.of_num 1 v) + | TruncSatUF64 -> I64_convert.trunc_sat_f64_u (F64Num.of_num 1 v) + | TruncSatSF64 -> I64_convert.trunc_sat_f64_s (F64Num.of_num 1 v) | ReinterpretFloat -> I64_convert.reinterpret_f64 (F64Num.of_num 1 v) | WrapI64 -> raise (TypeError (1, v, I64Type)) in I64Num.to_num i diff --git a/interpreter/exec/float.ml b/interpreter/exec/float.ml index b47fd308ae..f05fe3d389 100644 --- a/interpreter/exec/float.ml +++ b/interpreter/exec/float.ml @@ -36,6 +36,7 @@ sig val to_float : t -> float val of_string : string -> t val to_string : t -> string + val to_hex_string : t -> string val of_bits : bits -> t val to_bits : t -> bits val add : t -> t -> t @@ -322,35 +323,43 @@ struct (* String conversion that groups digits for readability *) let is_digit c = '0' <= c && c <= '9' - let isnt_digit c = not (is_digit c) + let is_hex_digit c = is_digit c || 'a' <= c && c <= 'f' - let rec add_digits buf s i j k = + let rec add_digits buf s i j k n = if i < j then begin if k = 0 then Buffer.add_char buf '_'; Buffer.add_char buf s.[i]; - add_digits buf s (i + 1) j ((k + 2) mod 3) + add_digits buf s (i + 1) j ((k + n - 1) mod n) n end - let group_digits s = + let group_digits is_digit n s = + let isnt_digit c = not (is_digit c) in let len = String.length s in - let mant = Lib.Option.get (Lib.String.find_from_opt is_digit s 0) len in + let x = Lib.Option.get (Lib.String.find_from_opt ((=) 'x') s 0) 0 in + let mant = Lib.Option.get (Lib.String.find_from_opt is_digit s x) len in let point = Lib.Option.get (Lib.String.find_from_opt isnt_digit s mant) len in let frac = Lib.Option.get (Lib.String.find_from_opt is_digit s point) len in let exp = Lib.Option.get (Lib.String.find_from_opt isnt_digit s frac) len in - let buf = Buffer.create (len*4/3) in + let buf = Buffer.create (len*(n+1)/n) in Buffer.add_substring buf s 0 mant; - add_digits buf s mant point ((point - mant) mod 3 + 3); + add_digits buf s mant point ((point - mant) mod n + n) n; Buffer.add_substring buf s point (frac - point); - add_digits buf s frac exp 3; + add_digits buf s frac exp n n; Buffer.add_substring buf s exp (len - exp); Buffer.contents buf - let to_string x = + let to_string' convert is_digit n x = (if x < Rep.zero then "-" else "") ^ if is_nan x then let payload = Rep.logand (abs x) (Rep.lognot bare_nan) in - "nan:0x" ^ Rep.to_hex_string payload + "nan:0x" ^ group_digits is_hex_digit 4 (Rep.to_hex_string payload) else - let s = Printf.sprintf "%.17g" (to_float (abs x)) in - group_digits (if s.[String.length s - 1] = '.' then s ^ "0" else s) + let s = convert (to_float (abs x)) in + group_digits is_digit n + (if s.[String.length s - 1] = '.' then s ^ "0" else s) + + let to_string = to_string' (Printf.sprintf "%.17g") is_digit 3 + let to_hex_string x = + if is_inf x then to_string x else + to_string' (Printf.sprintf "%h") is_hex_digit 4 x end diff --git a/interpreter/exec/i32.ml b/interpreter/exec/i32.ml index 3b90885fc1..573622a602 100644 --- a/interpreter/exec/i32.ml +++ b/interpreter/exec/i32.ml @@ -4,4 +4,5 @@ include Int.Make (struct include Int32 let bitwidth = 32 + let to_hex_string = Printf.sprintf "%lx" end) diff --git a/interpreter/exec/i32_convert.ml b/interpreter/exec/i32_convert.ml index ac4b0f89ad..482783a221 100644 --- a/interpreter/exec/i32_convert.ml +++ b/interpreter/exec/i32_convert.ml @@ -42,4 +42,52 @@ let trunc_f64_u x = else Int64.(to_int32 (of_float xf)) +let trunc_sat_f32_s x = + if F32.ne x x then + 0l + else + let xf = F32.to_float x in + if xf < Int32.(to_float min_int) then + Int32.min_int + else if xf >= -.Int32.(to_float min_int) then + Int32.max_int + else + Int32.of_float xf + +let trunc_sat_f32_u x = + if F32.ne x x then + 0l + else + let xf = F32.to_float x in + if xf <= -1.0 then + 0l + else if xf >= -.Int32.(to_float min_int) *. 2.0 then + -1l + else + Int64.(to_int32 (of_float xf)) + +let trunc_sat_f64_s x = + if F64.ne x x then + 0l + else + let xf = F64.to_float x in + if xf < Int32.(to_float min_int) then + Int32.min_int + else if xf >= -.Int32.(to_float min_int) then + Int32.max_int + else + Int32.of_float xf + +let trunc_sat_f64_u x = + if F64.ne x x then + 0l + else + let xf = F64.to_float x in + if xf <= -1.0 then + 0l + else if xf >= -.Int32.(to_float min_int) *. 2.0 then + -1l + else + Int64.(to_int32 (of_float xf)) + let reinterpret_f32 = F32.to_bits diff --git a/interpreter/exec/i32_convert.mli b/interpreter/exec/i32_convert.mli index 20e4eb40d9..706ef6d8b6 100644 --- a/interpreter/exec/i32_convert.mli +++ b/interpreter/exec/i32_convert.mli @@ -5,4 +5,8 @@ val trunc_f32_s : F32.t -> I32.t val trunc_f32_u : F32.t -> I32.t val trunc_f64_s : F64.t -> I32.t val trunc_f64_u : F64.t -> I32.t +val trunc_sat_f32_s : F32.t -> I32.t +val trunc_sat_f32_u : F32.t -> I32.t +val trunc_sat_f64_s : F64.t -> I32.t +val trunc_sat_f64_u : F64.t -> I32.t val reinterpret_f32 : F32.t -> I32.t diff --git a/interpreter/exec/i64.ml b/interpreter/exec/i64.ml index d44a3e1b08..c6d7a84d6f 100644 --- a/interpreter/exec/i64.ml +++ b/interpreter/exec/i64.ml @@ -4,4 +4,5 @@ include Int.Make (struct include Int64 let bitwidth = 64 + let to_hex_string = Printf.sprintf "%Lx" end) diff --git a/interpreter/exec/i64_convert.ml b/interpreter/exec/i64_convert.ml index 0919d32409..f71e9ff702 100644 --- a/interpreter/exec/i64_convert.ml +++ b/interpreter/exec/i64_convert.ml @@ -48,4 +48,56 @@ let trunc_f64_u x = else Int64.of_float xf +let trunc_sat_f32_s x = + if F32.ne x x then + 0L + else + let xf = F32.to_float x in + if xf < Int64.(to_float min_int) then + Int64.min_int + else if xf >= -.Int64.(to_float min_int) then + Int64.max_int + else + Int64.of_float xf + +let trunc_sat_f32_u x = + if F32.ne x x then + 0L + else + let xf = F32.to_float x in + if xf <= -1.0 then + 0L + else if xf >= -.Int64.(to_float min_int) *. 2.0 then + -1L + else if xf >= -.Int64.(to_float min_int) then + Int64.(logxor (of_float (xf -. 9223372036854775808.0)) min_int) + else + Int64.of_float xf + +let trunc_sat_f64_s x = + if F64.ne x x then + 0L + else + let xf = F64.to_float x in + if xf < Int64.(to_float min_int) then + Int64.min_int + else if xf >= -.Int64.(to_float min_int) then + Int64.max_int + else + Int64.of_float xf + +let trunc_sat_f64_u x = + if F64.ne x x then + 0L + else + let xf = F64.to_float x in + if xf <= -1.0 then + 0L + else if xf >= -.Int64.(to_float min_int) *. 2.0 then + -1L + else if xf >= -.Int64.(to_float min_int) then + Int64.(logxor (of_float (xf -. 9223372036854775808.0)) min_int) + else + Int64.of_float xf + let reinterpret_f64 = F64.to_bits diff --git a/interpreter/exec/i64_convert.mli b/interpreter/exec/i64_convert.mli index 02a0ce4506..5b0a47b337 100644 --- a/interpreter/exec/i64_convert.mli +++ b/interpreter/exec/i64_convert.mli @@ -6,4 +6,8 @@ val trunc_f32_s : F32.t -> I64.t val trunc_f32_u : F32.t -> I64.t val trunc_f64_s : F64.t -> I64.t val trunc_f64_u : F64.t -> I64.t +val trunc_sat_f32_s : F32.t -> I64.t +val trunc_sat_f32_u : F32.t -> I64.t +val trunc_sat_f64_s : F64.t -> I64.t +val trunc_sat_f64_u : F64.t -> I64.t val reinterpret_f64 : F64.t -> I64.t diff --git a/interpreter/exec/int.ml b/interpreter/exec/int.ml index 81674b15fc..c3e3a58f8f 100644 --- a/interpreter/exec/int.ml +++ b/interpreter/exec/int.ml @@ -26,6 +26,7 @@ sig val of_int : int -> t val to_int : t -> int val to_string : t -> string + val to_hex_string : t -> string val bitwidth : int end @@ -58,6 +59,7 @@ sig val clz : t -> t val ctz : t -> t val popcnt : t -> t + val extend_s : int -> t -> t val eqz : t -> bool val eq : t -> t -> bool val ne : t -> t -> bool @@ -77,6 +79,7 @@ sig val of_string : string -> t val to_string_s : t -> string val to_string_u : t -> string + val to_hex_string : t -> string end module Make (Rep : RepType) : S with type bits = Rep.t and type t = Rep.t = @@ -201,6 +204,10 @@ struct loop acc' (i - 1) (Rep.shift_right_logical n 1) in Rep.of_int (loop 0 Rep.bitwidth x) + let extend_s n x = + let shift = Rep.bitwidth - n in + Rep.shift_right (Rep.shift_left x shift) shift + let eqz x = x = Rep.zero let eq x y = x = y @@ -277,25 +284,27 @@ struct (* String conversion that groups digits for readability *) - let rec add_digits buf s i j k = + let rec add_digits buf s i j k n = if i < j then begin if k = 0 then Buffer.add_char buf '_'; Buffer.add_char buf s.[i]; - add_digits buf s (i + 1) j ((k + 2) mod 3) + add_digits buf s (i + 1) j ((k + n - 1) mod n) n end - let group_digits s = + let group_digits n s = let len = String.length s in let num = if s.[0] = '-' then 1 else 0 in - let buf = Buffer.create (len*4/3) in + let buf = Buffer.create (len*(n+1)/n) in Buffer.add_substring buf s 0 num; - add_digits buf s num len ((len - num) mod 3 + 3); + add_digits buf s num len ((len - num) mod n + n) n; Buffer.contents buf - let to_string_s i = group_digits (Rep.to_string i) + let to_string_s i = group_digits 3 (Rep.to_string i) let to_string_u i = if i >= Rep.zero then - group_digits (Rep.to_string i) + group_digits 3 (Rep.to_string i) else - group_digits (Rep.to_string (div_u i ten) ^ Rep.to_string (rem_u i ten)) + group_digits 3 (Rep.to_string (div_u i ten) ^ Rep.to_string (rem_u i ten)) + + let to_hex_string i = "0x" ^ group_digits 4 (Rep.to_hex_string i) end diff --git a/interpreter/runtime/memory.ml b/interpreter/runtime/memory.ml index fc3562d907..263c9687ab 100644 --- a/interpreter/runtime/memory.ml +++ b/interpreter/runtime/memory.ml @@ -8,9 +8,6 @@ type address = int64 type offset = int32 type count = int32 -type pack_size = Pack8 | Pack16 | Pack32 -type extension = SX | ZX - type memory' = (int, int8_unsigned_elt, c_layout) Array1.t type memory = {mutable ty : memory_type; mutable content : memory'} type t = memory @@ -23,11 +20,6 @@ exception OutOfMemory let page_size = 0x10000L (* 64 KiB *) -let packed_size = function - | Pack8 -> 1 - | Pack16 -> 2 - | Pack32 -> 4 - let valid_limits {min; max} = match max with | None -> true diff --git a/interpreter/runtime/memory.mli b/interpreter/runtime/memory.mli index c8e55df3d3..2ed721e89f 100644 --- a/interpreter/runtime/memory.mli +++ b/interpreter/runtime/memory.mli @@ -9,9 +9,6 @@ type address = int64 type offset = int32 type count = int32 -type pack_size = Pack8 | Pack16 | Pack32 -type extension = SX | ZX - exception Type exception Bounds exception SizeOverflow @@ -19,7 +16,6 @@ exception SizeLimit exception OutOfMemory val page_size : int64 -val packed_size : pack_size -> int val alloc : memory_type -> memory (* raises Type, SizeOverflow, OutOfMemory *) val type_of : memory -> memory_type diff --git a/interpreter/script/js.ml b/interpreter/script/js.ml index 66efeb730e..a68e224186 100644 --- a/interpreter/script/js.ml +++ b/interpreter/script/js.ml @@ -144,31 +144,42 @@ function assert_exhaustion(action) { throw new Error("Wasm resource exhaustion expected"); } -function assert_return(action, expected) { +function assert_return(action, ...expected) { let actual = action(); - switch (expected) { - case "nan:canonical": - case "nan:arithmetic": - // Note that JS can't reliably distinguish different NaN values, - // so there's no good way to test that it's a canonical NaN. - if (!Number.isNaN(actual)) { - throw new Error("Wasm NaN return value expected, got " + actual); - }; - return; - case "ref.func": - if (typeof actual !== "function") { - throw new Error("Wasm function return value expected, got " + actual); - }; - return; - case "ref.extern": - if (actual === null) { - throw new Error("Wasm reference return value expected, got " + actual); - }; - return; - default: - if (!Object.is(actual, expected)) { - throw new Error("Wasm return value " + expected + " expected, got " + actual); - }; + if (actual === undefined) { + actual = []; + } else if (!Array.isArray(actual)) { + actual = [actual]; + } + if (actual.length !== expected.length) { + throw new Error(expected.length + " value(s) expected, got " + actual.length); + } + for (let i = 0; i < actual.length; ++i) { + switch (expected[i]) { + case "nan:canonical": + case "nan:arithmetic": + case "nan:any": + // Note that JS can't reliably distinguish different NaN values, + // so there's no good way to test that it's a canonical NaN. + if (!Number.isNaN(actual[i])) { + throw new Error("Wasm return value NaN expected, got " + actual[i]); + }; + return; + case "ref.func": + if (typeof actual !== "function") { + throw new Error("Wasm function return value expected, got " + actual); + }; + return; + case "ref.extern": + if (actual === null) { + throw new Error("Wasm reference return value expected, got " + actual); + }; + return; + default: + if (!Object.is(actual[i], expected[i])) { + throw new Error("Wasm return value " + expected[i] + " expected, got " + actual[i]); + }; + } } } |} @@ -351,7 +362,7 @@ let wrap item_name wrap_action wrap_assertion at = let edesc = FuncExport item @@ at in let exports = [{name = Utf8.decode "run"; edesc} @@ at] in let body = - [ Block ([], action @ assertion @ [Return @@ at]) @@ at; + [ Block (ValBlockType None, action @ assertion @ [Return @@ at]) @@ at; Unreachable @@ at ] in let funcs = [{ftype = 0l @@ at; locals; body} @@ at] in diff --git a/interpreter/script/script.ml b/interpreter/script/script.ml index 50531b2fa3..6fe11950cc 100644 --- a/interpreter/script/script.ml +++ b/interpreter/script/script.ml @@ -1,7 +1,7 @@ type var = string Source.phrase type Values.ref_ += ExternRef of int32 -type value = Values.value Source.phrase +type literal = Values.value Source.phrase type definition = definition' Source.phrase and definition' = @@ -11,16 +11,16 @@ and definition' = type action = action' Source.phrase and action' = - | Invoke of var option * Ast.name * value list + | Invoke of var option * Ast.name * literal list | Get of var option * Ast.name type nanop = nanop' Source.phrase -and nanop' = (unit, unit, nan, nan) Values.op +and nanop' = (Lib.void, Lib.void, nan, nan) Values.op and nan = CanonicalNan | ArithmeticNan type result = result' Source.phrase and result' = - | LitResult of Values.value Source.phrase + | LitResult of literal | NanResult of nanop | RefResult of Types.ref_type diff --git a/interpreter/syntax/ast.ml b/interpreter/syntax/ast.ml index c78a671a5a..8add923dc3 100644 --- a/interpreter/syntax/ast.ml +++ b/interpreter/syntax/ast.ml @@ -23,13 +23,14 @@ open Types module IntOp = struct - type unop = Clz | Ctz | Popcnt + type unop = Clz | Ctz | Popcnt | ExtendS of pack_size type binop = Add | Sub | Mul | DivS | DivU | RemS | RemU | And | Or | Xor | Shl | ShrS | ShrU | Rotl | Rotr type testop = Eqz type relop = Eq | Ne | LtS | LtU | GtS | GtU | LeS | LeU | GeS | GeU type cvtop = ExtendSI32 | ExtendUI32 | WrapI64 | TruncSF32 | TruncUF32 | TruncSF64 | TruncUF64 + | TruncSatSF32 | TruncSatUF32 | TruncSatSF64 | TruncSatUF64 | ReinterpretFloat end @@ -56,8 +57,8 @@ type relop = (I32Op.relop, I64Op.relop, F32Op.relop, F64Op.relop) Values.op type cvtop = (I32Op.cvtop, I64Op.cvtop, F32Op.cvtop, F64Op.cvtop) Values.op type 'a memop = {ty : num_type; align : int; offset : int32; sz : 'a option} -type loadop = (Memory.pack_size * Memory.extension) memop -type storeop = Memory.pack_size memop +type loadop = (pack_size * extension) memop +type storeop = pack_size memop (* Expressions *) @@ -66,15 +67,17 @@ type var = int32 Source.phrase type num = Values.num Source.phrase type name = int list +type block_type = VarBlockType of var | ValBlockType of value_type option + type instr = instr' Source.phrase and instr' = | Unreachable (* trap unconditionally *) | Nop (* do nothing *) | Drop (* forget a value *) | Select of value_type list option (* branchless conditional *) - | Block of stack_type * instr list (* execute in sequence *) - | Loop of stack_type * instr list (* loop header *) - | If of stack_type * instr list * instr list (* conditional *) + | Block of block_type * instr list (* execute in sequence *) + | Loop of block_type * instr list (* loop header *) + | If of block_type * instr list * instr list (* conditional *) | Br of var (* break to n-th surrounding label *) | BrIf of var (* conditional break *) | BrTable of var list * var (* indexed break *) diff --git a/interpreter/syntax/operators.ml b/interpreter/syntax/operators.ml index 4a5d5a4809..f9583188b1 100644 --- a/interpreter/syntax/operators.ml +++ b/interpreter/syntax/operators.ml @@ -1,7 +1,6 @@ open Source open Types open Values -open Memory open Ast @@ -17,12 +16,12 @@ let unreachable = Unreachable let nop = Nop let drop = Drop let select t = Select t -let block ts es = Block (ts, es) -let loop ts es = Loop (ts, es) +let block bt es = Block (bt, es) +let loop bt es = Loop (bt, es) +let if_ bt es1 es2 = If (bt, es1, es2) let br x = Br x let br_if x = BrIf x let br_table xs x = BrTable (xs, x) -let if_ ts es1 es2 = If (ts, es1, es2) let return = Return let call x = Call x @@ -192,11 +191,21 @@ let f64_le = Compare (F64 F64Op.Le) let f64_gt = Compare (F64 F64Op.Gt) let f64_ge = Compare (F64 F64Op.Ge) +let i32_extend8_s = Unary (I32 (I32Op.ExtendS Pack8)) +let i32_extend16_s = Unary (I32 (I32Op.ExtendS Pack16)) +let i64_extend8_s = Unary (I64 (I64Op.ExtendS Pack8)) +let i64_extend16_s = Unary (I64 (I64Op.ExtendS Pack16)) +let i64_extend32_s = Unary (I64 (I64Op.ExtendS Pack32)) + let i32_wrap_i64 = Convert (I32 I32Op.WrapI64) let i32_trunc_f32_s = Convert (I32 I32Op.TruncSF32) let i32_trunc_f32_u = Convert (I32 I32Op.TruncUF32) let i32_trunc_f64_s = Convert (I32 I32Op.TruncSF64) let i32_trunc_f64_u = Convert (I32 I32Op.TruncUF64) +let i32_trunc_sat_f32_s = Convert (I32 I32Op.TruncSatSF32) +let i32_trunc_sat_f32_u = Convert (I32 I32Op.TruncSatUF32) +let i32_trunc_sat_f64_s = Convert (I32 I32Op.TruncSatSF64) +let i32_trunc_sat_f64_u = Convert (I32 I32Op.TruncSatUF64) let i64_extend_i32_s = Convert (I64 I64Op.ExtendSI32) let i64_extend_i32_u = Convert (I64 I64Op.ExtendUI32) let i64_trunc_f32_s = Convert (I64 I64Op.TruncSF32) @@ -207,6 +216,10 @@ let f32_convert_i32_s = Convert (F32 F32Op.ConvertSI32) let f32_convert_i32_u = Convert (F32 F32Op.ConvertUI32) let f32_convert_i64_s = Convert (F32 F32Op.ConvertSI64) let f32_convert_i64_u = Convert (F32 F32Op.ConvertUI64) +let i64_trunc_sat_f32_s = Convert (I64 I64Op.TruncSatSF32) +let i64_trunc_sat_f32_u = Convert (I64 I64Op.TruncSatUF32) +let i64_trunc_sat_f64_s = Convert (I64 I64Op.TruncSatSF64) +let i64_trunc_sat_f64_u = Convert (I64 I64Op.TruncSatUF64) let f32_demote_f64 = Convert (F32 F32Op.DemoteF64) let f64_convert_i32_s = Convert (F64 F64Op.ConvertSI32) let f64_convert_i32_u = Convert (F64 F64Op.ConvertUI32) diff --git a/interpreter/syntax/types.ml b/interpreter/syntax/types.ml index 82faaf6e9b..6a80308ef7 100644 --- a/interpreter/syntax/types.ml +++ b/interpreter/syntax/types.ml @@ -17,6 +17,9 @@ type extern_type = | ExternMemoryType of memory_type | ExternGlobalType of global_type +type pack_size = Pack8 | Pack16 | Pack32 +type extension = SX | ZX + (* Attributes *) @@ -24,6 +27,11 @@ let size = function | I32Type | F32Type -> 4 | I64Type | F64Type -> 8 +let packed_size = function + | Pack8 -> 1 + | Pack16 -> 2 + | Pack32 -> 4 + let is_num_type = function | NumType _ -> true | RefType _ -> false diff --git a/interpreter/text/arrange.ml b/interpreter/text/arrange.ml index a6733c1a51..ffb12794ee 100644 --- a/interpreter/text/arrange.ml +++ b/interpreter/text/arrange.ml @@ -62,8 +62,6 @@ let value_type t = string_of_value_type t let decls kind ts = tab kind (atom value_type) ts -let stack_type ts = decls "result" ts - let func_type (FuncType (ins, out)) = Node ("func", decls "param" ins @ decls "result" out) @@ -76,6 +74,15 @@ let global_type = function | GlobalType (t, Immutable) -> atom string_of_value_type t | GlobalType (t, Mutable) -> Node ("mut", [atom string_of_value_type t]) +let pack_size = function + | Pack8 -> "8" + | Pack16 -> "16" + | Pack32 -> "32" + +let extension = function + | SX -> "_s" + | ZX -> "_u" + (* Operators *) @@ -102,6 +109,7 @@ struct | Clz -> "clz" | Ctz -> "ctz" | Popcnt -> "popcnt" + | ExtendS sz -> "extend" ^ pack_size sz ^ "_s" let binop xx = function | Add -> "add" @@ -128,6 +136,10 @@ struct | TruncUF32 -> "trunc_f32_u" | TruncSF64 -> "trunc_f64_s" | TruncUF64 -> "trunc_f64_u" + | TruncSatSF32 -> "trunc_sat_f32_s" + | TruncSatUF32 -> "trunc_sat_f32_u" + | TruncSatSF64 -> "trunc_sat_f64_s" + | TruncSatUF64 -> "trunc_sat_f64_u" | ReinterpretFloat -> "reinterpret_f" ^ xx end @@ -188,15 +200,6 @@ let testop = oper (IntOp.testop, FloatOp.testop) let relop = oper (IntOp.relop, FloatOp.relop) let cvtop = oper (IntOp.cvtop, FloatOp.cvtop) -let pack_size = function - | Memory.Pack8 -> "8" - | Memory.Pack16 -> "16" - | Memory.Pack32 -> "32" - -let extension = function - | Memory.SX -> "_s" - | Memory.ZX -> "_u" - let memop name {ty; align; offset; _} sz = num_type ty ^ "." ^ name ^ (if offset = 0l then "" else " offset=" ^ nat32 offset) ^ @@ -206,12 +209,12 @@ let loadop op = match op.sz with | None -> memop "load" op (size op.ty) | Some (sz, ext) -> - memop ("load" ^ pack_size sz ^ extension ext) op (Memory.packed_size sz) + memop ("load" ^ pack_size sz ^ extension ext) op (packed_size sz) let storeop op = match op.sz with | None -> memop "store" op (size op.ty) - | Some sz -> memop ("store" ^ pack_size sz) op (Memory.packed_size sz) + | Some sz -> memop ("store" ^ pack_size sz) op (packed_size sz) (* Expressions *) @@ -220,6 +223,10 @@ let var x = nat32 x.it let num v = string_of_num v.it let constop v = num_type (type_of_num v.it) ^ ".const" +let block_type = function + | VarBlockType x -> [Node ("type " ^ var x, [])] + | ValBlockType ts -> decls "result" (list_of_opt ts) + let rec instr e = let head, inner = match e.it with @@ -229,10 +236,10 @@ let rec instr e = | Select None -> "select", [] | Select (Some []) -> "select", [Node ("result", [])] | Select (Some ts) -> "select", decls "result" ts - | Block (ts, es) -> "block", stack_type ts @ list instr es - | Loop (ts, es) -> "loop", stack_type ts @ list instr es - | If (ts, es1, es2) -> - "if", stack_type ts @ + | Block (bt, es) -> "block", block_type bt @ list instr es + | Loop (bt, es) -> "loop", block_type bt @ list instr es + | If (bt, es1, es2) -> + "if", block_type bt @ [Node ("then", list instr es1); Node ("else", list instr es2)] | Br x -> "br " ^ var x, [] | BrIf x -> "br_if " ^ var x, [] @@ -426,15 +433,26 @@ let module_ = module_with_var_opt None (* Scripts *) -let value v = - match v.it with - | Num (Values.I32 i) -> Node ("i32.const " ^ I32.to_string_s i, []) - | Num (Values.I64 i) -> Node ("i64.const " ^ I64.to_string_s i, []) - | Num (Values.F32 z) -> Node ("f32.const " ^ F32.to_string z, []) - | Num (Values.F64 z) -> Node ("f64.const " ^ F64.to_string z, []) - | Ref (NullRef t) -> Node ("ref.null", [Atom (refed_type t)]) - | Ref (ExternRef n) -> Node ("ref.extern " ^ Int32.to_string n, []) - | _ -> assert false +let literal mode lit = + match lit.it with + | Num (Values.I32 i) -> + let f = if mode = `Binary then I32.to_hex_string else I32.to_string_s in + Node ("i32.const " ^ f i, []) + | Num (Values.I64 i) -> + let f = if mode = `Binary then I64.to_hex_string else I64.to_string_s in + Node ("i64.const " ^ f i, []) + | Num (Values.F32 z) -> + let f = if mode = `Binary then F32.to_hex_string else F32.to_string in + Node ("f32.const " ^ f z, []) + | Num (Values.F64 z) -> + let f = if mode = `Binary then F64.to_hex_string else F64.to_string in + Node ("f64.const " ^ f z, []) + | Ref (NullRef t) -> + Node ("ref.null " ^ refed_type t, []) + | Ref (ExternRef n) -> + Node ("ref.extern " ^ nat32 n, []) + | Ref _ -> + assert false let definition mode x_opt def = try @@ -464,10 +482,10 @@ let definition mode x_opt def = let access x_opt n = String.concat " " [var_opt x_opt; name n] -let action act = +let action mode act = match act.it with - | Invoke (x_opt, name, vs) -> - Node ("invoke" ^ access x_opt name, List.map value vs) + | Invoke (x_opt, name, lits) -> + Node ("invoke" ^ access x_opt name, List.map (literal mode) lits) | Get (x_opt, name) -> Node ("get" ^ access x_opt name, []) @@ -475,9 +493,9 @@ let nan = function | CanonicalNan -> "nan:canonical" | ArithmeticNan -> "nan:arithmetic" -let result res = +let result mode res = match res.it with - | LitResult lit -> value lit + | LitResult lit -> literal mode lit | NanResult nanop -> (match nanop.it with | Values.I32 _ | Values.I64 _ -> assert false @@ -489,27 +507,30 @@ let result res = let assertion mode ass = match ass.it with | AssertMalformed (def, re) -> - Node ("assert_malformed", [definition `Original None def; Atom (string re)]) + (match mode, def.it with + | `Binary, Quoted _ -> [] + | _ -> + [Node ("assert_malformed", [definition `Original None def; Atom (string re)])] + ) | AssertInvalid (def, re) -> - Node ("assert_invalid", [definition mode None def; Atom (string re)]) + [Node ("assert_invalid", [definition mode None def; Atom (string re)])] | AssertUnlinkable (def, re) -> - Node ("assert_unlinkable", [definition mode None def; Atom (string re)]) + [Node ("assert_unlinkable", [definition mode None def; Atom (string re)])] | AssertUninstantiable (def, re) -> - Node ("assert_trap", [definition mode None def; Atom (string re)]) + [Node ("assert_trap", [definition mode None def; Atom (string re)])] | AssertReturn (act, results) -> - Node ("assert_return", action act :: List.map result results) + [Node ("assert_return", action mode act :: List.map (result mode) results)] | AssertTrap (act, re) -> - Node ("assert_trap", [action act; Atom (string re)]) + [Node ("assert_trap", [action mode act; Atom (string re)])] | AssertExhaustion (act, re) -> - Node ("assert_exhaustion", [action act; Atom (string re)]) + [Node ("assert_exhaustion", [action mode act; Atom (string re)])] let command mode cmd = match cmd.it with - | Module (x_opt, def) -> definition mode x_opt def - | Register (n, x_opt) -> - Node ("register " ^ name n ^ var_opt x_opt, []) - | Action act -> action act + | Module (x_opt, def) -> [definition mode x_opt def] + | Register (n, x_opt) -> [Node ("register " ^ name n ^ var_opt x_opt, [])] + | Action act -> [action mode act] | Assertion ass -> assertion mode ass | Meta _ -> assert false -let script mode scr = List.map (command mode) scr +let script mode scr = Lib.List.concat_map (command mode) scr diff --git a/interpreter/text/lexer.mll b/interpreter/text/lexer.mll index 36524d236a..e2f675f381 100644 --- a/interpreter/text/lexer.mll +++ b/interpreter/text/lexer.mll @@ -261,6 +261,9 @@ rule token = parse | (ixx as t)".clz" { UNARY (intop t i32_clz i64_clz) } | (ixx as t)".ctz" { UNARY (intop t i32_ctz i64_ctz) } | (ixx as t)".popcnt" { UNARY (intop t i32_popcnt i64_popcnt) } + | (ixx as t)".extend8_s" { UNARY (intop t i32_extend8_s i64_extend8_s) } + | (ixx as t)".extend16_s" { UNARY (intop t i32_extend16_s i64_extend16_s) } + | "i64.extend32_s" { UNARY i64_extend32_s } | (fxx as t)".neg" { UNARY (floatop t f32_neg f64_neg) } | (fxx as t)".abs" { UNARY (floatop t f32_abs f64_abs) } | (fxx as t)".sqrt" { UNARY (floatop t f32_sqrt f64_sqrt) } @@ -324,6 +327,14 @@ rule token = parse { CONVERT (intop t i32_trunc_f64_s i64_trunc_f64_s) } | (ixx as t)".trunc_f64_u" { CONVERT (intop t i32_trunc_f64_u i64_trunc_f64_u) } + | (ixx as t)".trunc_sat_f32_s" + { CONVERT (intop t i32_trunc_sat_f32_s i64_trunc_sat_f32_s) } + | (ixx as t)".trunc_sat_f32_u" + { CONVERT (intop t i32_trunc_sat_f32_u i64_trunc_sat_f32_u) } + | (ixx as t)".trunc_sat_f64_s" + { CONVERT (intop t i32_trunc_sat_f64_s i64_trunc_sat_f64_s) } + | (ixx as t)".trunc_sat_f64_u" + { CONVERT (intop t i32_trunc_sat_f64_u i64_trunc_sat_f64_u) } | (fxx as t)".convert_i32_s" { CONVERT (floatop t f32_convert_i32_s f64_convert_i32_s) } | (fxx as t)".convert_i32_u" diff --git a/interpreter/text/parser.mly b/interpreter/text/parser.mly index 445c6db3b1..04a3993e08 100644 --- a/interpreter/text/parser.mly +++ b/interpreter/text/parser.mly @@ -474,22 +474,43 @@ call_instr_results_instr : block_instr : | BLOCK labeling_opt block END labeling_end_opt - { fun c -> let c' = $2 c $5 in let ts, es = $3 c' in block ts es } + { fun c -> let c' = $2 c $5 in let bt, es = $3 c' in block bt es } | LOOP labeling_opt block END labeling_end_opt - { fun c -> let c' = $2 c $5 in let ts, es = $3 c' in loop ts es } + { fun c -> let c' = $2 c $5 in let bt, es = $3 c' in loop bt es } | IF labeling_opt block END labeling_end_opt - { fun c -> let c' = $2 c $5 in let ts, es = $3 c' in if_ ts es [] } + { fun c -> let c' = $2 c $5 in let bt, es = $3 c' in if_ bt es [] } | IF labeling_opt block ELSE labeling_end_opt instr_list END labeling_end_opt { fun c -> let c' = $2 c ($5 @ $8) in let ts, es1 = $3 c' in if_ ts es1 ($6 c') } -block_type : - | LPAR RESULT value_type RPAR { [$3] } - block : - | block_type instr_list - { fun c -> $1, $2 c } - | instr_list { fun c -> [], $1 c } + | type_use block_param_body + { let at1 = ati 1 in + fun c -> + VarBlockType (inline_type_explicit c ($1 c type_) (fst $2) at1), + snd $2 c } + | block_param_body /* Sugar */ + { let at = at () in + fun c -> + let bt = + match fst $1 with + | FuncType ([], []) -> ValBlockType None + | FuncType ([], [t]) -> ValBlockType (Some t) + | ft -> VarBlockType (inline_type c ft at) + in bt, snd $1 c } + +block_param_body : + | block_result_body { $1 } + | LPAR PARAM value_type_list RPAR block_param_body + { let FuncType (ins, out) = fst $5 in + FuncType ($3 @ ins, out), snd $5 } + +block_result_body : + | instr_list { FuncType ([], []), $1 } + | LPAR RESULT value_type_list RPAR block_result_body + { let FuncType (ins, out) = fst $5 in + FuncType (ins, $3 @ out), snd $5 } + expr : /* Sugar */ | LPAR expr1 RPAR @@ -505,12 +526,12 @@ expr1 : /* Sugar */ { let at1 = ati 1 in fun c -> let x, es = $2 c in es, call_indirect (0l @@ at1) x } | BLOCK labeling_opt block - { fun c -> let c' = $2 c [] in let ts, es = $3 c' in [], block ts es } + { fun c -> let c' = $2 c [] in let bt, es = $3 c' in [], block bt es } | LOOP labeling_opt block - { fun c -> let c' = $2 c [] in let ts, es = $3 c' in [], loop ts es } + { fun c -> let c' = $2 c [] in let bt, es = $3 c' in [], loop bt es } | IF labeling_opt if_block { fun c -> let c' = $2 c [] in - let ts, (es, es1, es2) = $3 c c' in es, if_ ts es1 es2 } + let bt, (es, es1, es2) = $3 c c' in es, if_ bt es1 es2 } select_expr_results : | LPAR RESULT value_type_list RPAR select_expr_results @@ -544,8 +565,32 @@ call_expr_results : if_block : - | block_type if_block { fun c c' -> let ts, ess = $2 c c' in $1 @ ts, ess } - | if_ { fun c c' -> [], $1 c c' } + | type_use if_block_param_body + { let at = at () in + fun c c' -> + VarBlockType (inline_type_explicit c ($1 c type_) (fst $2) at), + snd $2 c c' } + | if_block_param_body /* Sugar */ + { let at = at () in + fun c c' -> + let bt = + match fst $1 with + | FuncType ([], []) -> ValBlockType None + | FuncType ([], [t]) -> ValBlockType (Some t) + | ft -> VarBlockType (inline_type c ft at) + in bt, snd $1 c c' } + +if_block_param_body : + | if_block_result_body { $1 } + | LPAR PARAM value_type_list RPAR if_block_param_body + { let FuncType (ins, out) = fst $5 in + FuncType ($3 @ ins, out), snd $5 } + +if_block_result_body : + | if_ { FuncType ([], []), $1 } + | LPAR RESULT value_type_list RPAR if_block_result_body + { let FuncType (ins, out) = fst $5 in + FuncType (ins, $3 @ out), snd $5 } if_ : | expr if_ @@ -580,24 +625,24 @@ func : func_fields : | type_use func_fields_body { fun c x at -> - let t = inline_type_explicit c ($1 c type_) (fst $2) at in - [{(snd $2 (enter_func c)) with ftype = t} @@ at], [], [] } + let y = inline_type_explicit c ($1 c type_) (fst $2) at in + [{(snd $2 (enter_func c)) with ftype = y} @@ at], [], [] } | func_fields_body /* Sugar */ { fun c x at -> - let t = inline_type c (fst $1) at in - [{(snd $1 (enter_func c)) with ftype = t} @@ at], [], [] } + let y = inline_type c (fst $1) at in + [{(snd $1 (enter_func c)) with ftype = y} @@ at], [], [] } | inline_import type_use func_fields_import /* Sugar */ { fun c x at -> - let t = inline_type_explicit c ($2 c type_) $3 at in + let y = inline_type_explicit c ($2 c type_) $3 at in [], [{ module_name = fst $1; item_name = snd $1; - idesc = FuncImport t @@ at } @@ at ], [] } + idesc = FuncImport y @@ at } @@ at ], [] } | inline_import func_fields_import /* Sugar */ { fun c x at -> - let t = inline_type c $2 at in + let y = inline_type c $2 at in [], [{ module_name = fst $1; item_name = snd $1; - idesc = FuncImport t @@ at } @@ at ], [] } + idesc = FuncImport y @@ at } @@ at ], [] } | inline_export func_fields /* Sugar */ { fun c x at -> let fns, ims, exs = $2 c x at in fns, ims, $1 (FuncExport x) c :: exs } diff --git a/interpreter/util/lib.ml b/interpreter/util/lib.ml index c4e0c361e1..adf101eb7d 100644 --- a/interpreter/util/lib.ml +++ b/interpreter/util/lib.ml @@ -1,3 +1,5 @@ +type void + module Fun = struct let id x = x @@ -102,6 +104,10 @@ struct match f x with | None -> map_filter f xs | Some y -> y :: map_filter f xs + + let rec concat_map f = function + | [] -> [] + | x::xs -> f x @ concat_map f xs end module List32 = diff --git a/interpreter/util/lib.mli b/interpreter/util/lib.mli index 1cadd9c9c8..415a855e0d 100644 --- a/interpreter/util/lib.mli +++ b/interpreter/util/lib.mli @@ -1,5 +1,7 @@ (* Things that should be in the OCaml library... *) +type void + module Fun : sig val id : 'a -> 'a @@ -22,6 +24,7 @@ sig val index_of : 'a -> 'a list -> int option val index_where : ('a -> bool) -> 'a list -> int option val map_filter : ('a -> 'b option) -> 'a list -> 'b list + val concat_map : ('a -> 'b list) -> 'a list -> 'b list end module List32 : diff --git a/interpreter/valid/valid.ml b/interpreter/valid/valid.ml index 1eb6bcf1b4..8099837194 100644 --- a/interpreter/valid/valid.ml +++ b/interpreter/valid/valid.ml @@ -121,16 +121,18 @@ let type_cvtop at = function (match cvtop with | ExtendSI32 | ExtendUI32 -> error at "invalid conversion" | WrapI64 -> I64Type - | TruncSF32 | TruncUF32 | ReinterpretFloat -> F32Type - | TruncSF64 | TruncUF64 -> F64Type + | TruncSF32 | TruncUF32 | TruncSatSF32 | TruncSatUF32 + | ReinterpretFloat -> F32Type + | TruncSF64 | TruncUF64 | TruncSatSF64 | TruncSatUF64 -> F64Type ), I32Type | Values.I64 cvtop -> let open I64Op in (match cvtop with | ExtendSI32 | ExtendUI32 -> I32Type | WrapI64 -> error at "invalid conversion" - | TruncSF32 | TruncUF32 -> F32Type - | TruncSF64 | TruncUF64 | ReinterpretFloat -> F64Type + | TruncSF32 | TruncUF32 | TruncSatSF32 | TruncSatUF32 -> F32Type + | TruncSF64 | TruncUF64 | TruncSatSF64 | TruncSatUF64 + | ReinterpretFloat -> F64Type ), I64Type | Values.F32 cvtop -> let open F32Op in @@ -152,22 +154,27 @@ let type_cvtop at = function (* Expressions *) +let check_pack sz t at = + require (packed_size sz < size t) at "invalid sign extension" + +let check_unop unop at = + match unop with + | Values.I32 (IntOp.ExtendS sz) | Values.I64 (IntOp.ExtendS sz) -> + check_pack sz (Values.type_of_num unop) at + | _ -> () + let check_memop (c : context) (memop : 'a memop) get_sz at = let _mt = memory c (0l @@ at) in let size = match get_sz memop.sz with | None -> size memop.ty | Some sz -> - require (memop.ty = I64Type || sz <> Memory.Pack32) at - "memory size too big"; - Memory.packed_size sz + check_pack sz memop.ty at; + packed_size sz in require (1 lsl memop.align <= size) at "alignment must not be larger than natural" -let check_arity n at = - require (n <= 1) at "invalid result arity, larger than 1 is not (yet) allowed" - (* * Conventions: @@ -189,6 +196,12 @@ let check_arity n at = * declarative typing rules. *) +let check_block_type (c : context) (bt : block_type) : func_type = + match bt with + | VarBlockType x -> type_ c x + | ValBlockType None -> FuncType ([], []) + | ValBlockType (Some t) -> FuncType ([], [t]) + let rec check_instr (c : context) (e : instr) (s : infer_stack_type) : op_type = match e.it with | Unreachable -> @@ -208,25 +221,24 @@ let rec check_instr (c : context) (e : instr) (s : infer_stack_type) : op_type = [t; t; Some (NumType I32Type)] -~> [t] | Select (Some ts) -> - check_arity (List.length ts) e.at; - require (List.length ts <> 0) e.at "invalid result arity, 0 is not (yet) allowed"; + require (List.length ts = 1) e.at "invalid result arity other than 1 is not (yet) allowed"; (ts @ ts @ [NumType I32Type]) --> ts - | Block (ts, es) -> - check_arity (List.length ts) e.at; - check_block {c with labels = ts :: c.labels} es ts e.at; - [] --> ts + | Block (bt, es) -> + let FuncType (ts1, ts2) as ft = check_block_type c bt in + check_block {c with labels = ts2 :: c.labels} es ft e.at; + ts1 --> ts2 - | Loop (ts, es) -> - check_arity (List.length ts) e.at; - check_block {c with labels = [] :: c.labels} es ts e.at; - [] --> ts + | Loop (bt, es) -> + let FuncType (ts1, ts2) as ft = check_block_type c bt in + check_block {c with labels = ts1 :: c.labels} es ft e.at; + ts1 --> ts2 - | If (ts, es1, es2) -> - check_arity (List.length ts) e.at; - check_block {c with labels = ts :: c.labels} es1 ts e.at; - check_block {c with labels = ts :: c.labels} es2 ts e.at; - [NumType I32Type] --> ts + | If (bt, es1, es2) -> + let FuncType (ts1, ts2) as ft = check_block_type c bt in + check_block {c with labels = ts2 :: c.labels} es1 ft e.at; + check_block {c with labels = ts2 :: c.labels} es2 ft e.at; + (ts1 @ [NumType I32Type]) --> ts2 | Br x -> label c x -->... [] @@ -243,16 +255,16 @@ let rec check_instr (c : context) (e : instr) (s : infer_stack_type) : op_type = c.results -->... [] | Call x -> - let FuncType (ins, out) = func c x in - ins --> out + let FuncType (ts1, ts2) = func c x in + ts1 --> ts2 | CallIndirect (x, y) -> let TableType (lim, t) = table c x in - let FuncType (ins, out) = type_ c y in + let FuncType (ts1, ts2) = type_ c y in require (t = FuncRefType) x.at ("type mismatch: instruction requires table of functions" ^ " but table has " ^ string_of_ref_type t); - (ins @ [NumType I32Type]) --> out + (ts1 @ [NumType I32Type]) --> ts2 | LocalGet x -> [] --> [local c x] @@ -371,6 +383,7 @@ let rec check_instr (c : context) (e : instr) (s : infer_stack_type) : op_type = [t; t] --> [NumType I32Type] | Unary unop -> + check_unop unop e.at; let t = NumType (type_unop unop) in [t] --> [t] @@ -382,22 +395,24 @@ let rec check_instr (c : context) (e : instr) (s : infer_stack_type) : op_type = let t1, t2 = type_cvtop e.at cvtop in [NumType t1] --> [NumType t2] -and check_seq (c : context) (es : instr list) : infer_stack_type = +and check_seq (c : context) (s : infer_stack_type) (es : instr list) + : infer_stack_type = match es with | [] -> - stack [] + s | _ -> let es', e = Lib.List.split_last es in - let s = check_seq c es' in - let {ins; outs} = check_instr c e s in - push outs (pop ins s e.at) - -and check_block (c : context) (es : instr list) (ts : stack_type) at = - let s = check_seq c es in - let s' = pop (stack ts) s at in + let s' = check_seq c s es' in + let {ins; outs} = check_instr c e s' in + push outs (pop ins s' e.at) + +and check_block (c : context) (es : instr list) (ft : func_type) at = + let FuncType (ts1, ts2) = ft in + let s = check_seq c (stack ts1) es in + let s' = pop (stack ts2) s at in require (snd s' = []) at - ("type mismatch: operator requires " ^ string_of_stack_type ts ^ + ("type mismatch: block requires " ^ string_of_stack_type ts2 ^ " but stack has " ^ string_of_infer_types (snd s)) @@ -424,10 +439,9 @@ let check_value_type (t : value_type) at = | RefType t' -> check_ref_type t' at let check_func_type (ft : func_type) at = - let FuncType (ins, out) = ft in - List.iter (fun t -> check_value_type t at) ins; - List.iter (fun t -> check_value_type t at) out; - check_arity (List.length out) at + let FuncType (ts1, ts2) = ft in + List.iter (fun t -> check_value_type t at) ts1; + List.iter (fun t -> check_value_type t at) ts2 let check_table_type (tt : table_type) at = let TableType (lim, t) = tt in @@ -444,6 +458,10 @@ let check_global_type (gt : global_type) at = check_value_type t at +let check_type (t : type_) = + check_func_type t.it t.at + + (* Functions & Constants *) (* @@ -458,14 +476,11 @@ let check_global_type (gt : global_type) at = * x : variable *) -let check_type (t : type_) = - check_func_type t.it t.at - let check_func (c : context) (f : func) = let {ftype; locals; body} = f.it in - let FuncType (ins, out) = type_ c ftype in - let c' = {c with locals = ins @ locals; results = out; labels = [out]} in - check_block c' body out f.at + let FuncType (ts1, ts2) = type_ c ftype in + let c' = {c with locals = ts1 @ locals; results = ts2; labels = [ts2]} in + check_block c' body (FuncType ([], ts2)) f.at let is_const (c : context) (e : instr) = @@ -479,7 +494,7 @@ let is_const (c : context) (e : instr) = let check_const (c : context) (const : const) (t : value_type) = require (List.for_all (is_const c) const.it) const.at "constant expression required"; - check_block c const.it [t] const.at + check_block c const.it (FuncType ([], [t])) const.at (* Tables, Memories, & Globals *) diff --git a/proposals/README.md b/proposals/README.md new file mode 100644 index 0000000000..364b7ab4dc --- /dev/null +++ b/proposals/README.md @@ -0,0 +1,3 @@ +# Proposals + +This directory contains overviews for post-MVP proposals that are included in this repository. diff --git a/proposals/multi-value/Overview.md b/proposals/multi-value/Overview.md new file mode 100644 index 0000000000..a6aeb61b69 --- /dev/null +++ b/proposals/multi-value/Overview.md @@ -0,0 +1,196 @@ +# Multi-value Extension + +## Introduction + +### Background + +* Currently, functions and instructions consume multiple operands but can produce at most one result + - functions: `value* -> value?` + - instructions: `value* -> value?` + - blocks: `[] -> value?` + +* In a stack machine, these asymmetries are artifical restrictions + - were imposed to simplify the initial WebAssembly release (multiple results deferred to post-MVP) + - can easily be lifted by generalising to value* -> value* + +* Generalised semantics is well-understood + - https://github.com/WebAssembly/spec/tree/master/papers/pldi2017.pdf + +* Semi-complete implementation of multiple results in V8 + + +### Motivation + +* Multiple return values for functions: + - enable unboxing of tuples or structs returned by value + - efficient compilation of multiple return values + +* Multiple results for instructions: + - enable instructions producing several results (divmod, arithmetics with carry) + +* Inputs to blocks: + - loop labels can have arguments + - can represent phis on backward edges + - enable future `pick` operator to cross block boundary + - macro definability of instructons with inputs + * `i32.select3` = `dup if ... else ... end` + + +## Examples + +### Functions with multiple return Values + +A simple swap function. +```wasm +(func $swap (param i32 i32) (result i32 i32) + (get_local 1) (get_local 0) +) +``` + +An addition function returning an additional carry bit. +```wasm +(func $add64_u_with_carry (param $i i64) (param $j i64) (param $c i32) (result i64 i32) + (local $k i64) + (set_local $k + (i64.add (i64.add (get_local $i) (get_local $j)) (i64.extend_u/i32 (get_local $c))) + ) + (return (get_local $k) (i64.lt_u (get_local $k) (get_local $i))) +) +``` + +### Instructions with multiple results + +* `iNN.divrem` : \[iNN iNN\] -> \[iNN iNN\] +* `iNN.add_carry` : \[iNN iNN i32\] -> \[iNN i32\] +* `iNN.sub_carry` : \[iNN iNN i32\] -> \[iNN i32\] +* etc. + + +### Blocks with inputs + +Conditionally manipulating a stack operand without using a local. +```wasm +(func $add64_u_saturated (param i64 i64) (result i64) + ($i64.add_u_carry (get_local 0) (get_local 1) (i32.const 0)) + (if (param i64) (result i64) + (then (drop) (i64.const 0xffff_ffff_ffff_ffff)) + ) +) +``` + +An iterative factorial function whose loop doesn't use locals, but uses arguments like phis. +```wasm +(func $fac (param i64) (result i64) + (i64.const 1) (get_local 0) + (loop $l (param i64 i64) (result i64) + (pick 1) (pick 1) (i64.mul) + (pick 1) (i64.const 1) (i64.sub) + (pick 0) (i64.const 0) (i64.gt_u) + (br_if $l) + (pick 1) (return) + ) +) +``` + +Macro definition of an instruction expanding into an `if`. +``` +i64.select3 = + dup if (param i64 i64 i64 i32) (result i64) … select ... else … end +``` + +Macro expansion of `if` itself. +``` +if (param t*) (result u*) A else B end = + block (param t* i32) (result u*) + block (param t* i32) (result t*) (br_if 0) B (br 1) end A + end +``` + + +## Spec Changes + +### Structure + +The structure of the language is mostly unaffected. The only changes are to the type syntax: + +* *resulttype* is generalised from \[*valtype*?\] to \[*valtype*\*\] +* block types (in `block`, `loop`, `if` instructions) are generalised from *resulttype* to *functype* + + +### Validation + +Arity restrictions are removed: + +* no arity check is imposed for valid *functype* +* all occurrences of superscript "?" are replaced with superscript "\*" (e.g. blocks, calls, return) + +Validation for block instructions is generalised: + +* The type of `block`, `loop`, and `if` is the *functype* \[t1\*\] -> \[t2\*\] given as the block type +* The type of the label of `block` and `if` is \[t2\*\] +* The type of the label of `loop` is \[t1\*\] + + +### Execution + +Nothing much needs to be done for multiple results: + +* replace all occurrences of superscript "?" with superscript "\*". + +The only non-mechanical change involves entering blocks with operands: + +* The operand values are popped of the stack, and pushed right back after the label. +* See paper for formulation of formal reduction rules + + +### Binary Format + +The binary requires a change to allow function types as block types. That requires extending the current ad-hoc encoding to allow references to function types. + +* `blocktype` is extended to the following format: + ``` + blocktype ::= 0x40 => [] -> [] + | t:valtype => [] -> [t] + | ft:typeidx => ft + ``` + +### Text Format + +The text format is mostly unaffected, except that the syntax for block types is generalised: + +* `resulttype` is replaced with `blocktype`, whose syntax is + ``` + blocktype ::= vec(param) vec(result) + ``` + +* `block`, `loop`, and `if` instructions contain a `blocktype` instead of `resulttype`. + +* The existing abbreviations for functions apply to block types. + + +### Soundness Proof + +The typing of administrative instructions need to be generalised, see the paper. + + +## Possible Alternatives and Extensions + +### More Flexible Block and Function Types + +* Instead of inline function types, could use references to the type section + - more bureaucracy in the semantics, but otherwise no problem + +* Could also allow both + - inline function types are slightly more compact for one-off uses + +* Could even unify the encoding of block types with function types everywhere + - allow inline types even for functions, for the same benefits + + +## Open Questions + +* Destructuring or reshuffling multiple values requires locals, is that enough? + - could add `pick` instruction (generalised `dup`) + - could add `let` instruction (if you squint, a generalised `swap`) + - different use cases? + diff --git a/proposals/nontrapping-float-to-int-conversion/Overview.md b/proposals/nontrapping-float-to-int-conversion/Overview.md new file mode 100644 index 0000000000..574fcde70a --- /dev/null +++ b/proposals/nontrapping-float-to-int-conversion/Overview.md @@ -0,0 +1,93 @@ +# Non-trapping Float-to-int Conversions + +## Introduction + +### Motivation + +The primary motivations are: + + - LLVM’s float-to-int conversion has an undefined result, rather than undefined behavior, and it seems LLVM does speculate it under certain conditions. + - For the SIMD proposal, it’s more SIMD-hardware-like if no SIMD operations trap. This proposal would establish a convention for saturating operations which SIMD could share, to avoid introducing trapping. + +This proposal is not motivated by performance data. + +It's plausible that LLVM could be changed, to have something like an "nsw" flag for the "fptosi" instruction, especially with some of the recent proposals to modify the poison concept in LLVM. However, no one is currently working on this. + +### Background + +This issue has been discussed in several areas including here: + +https://github.com/WebAssembly/design/issues/986 + +While performance concerns initially motivated the discussion, the performance +effects were due to a particular implementation detail which has since been +fixed. + +Since then, no real-world performance problems related to this issue have +been reported. + +This topic was discussed at the CG-05 meeting: + +https://github.com/WebAssembly/meetings/pull/3 + +and + +https://github.com/WebAssembly/meetings/blob/master/2017/CG-05.md#non-trapping-float-to-int + +which made decisions about which semantics to choose, and which encoding strategy. + +These decisions were captured in a design repo PR: + +https://github.com/WebAssembly/design/pull/1089 + +At the CG-07-06 meeting it was decided that a full spec repo fork should be +created to follow the new process for new features: + +https://github.com/WebAssembly/meetings/blob/master/2017/CG-07-06.md#float-to-int-conversion + +This led to the creation of the present repo: + +https://github.com/WebAssembly/nontrapping-float-to-int-conversions + +### Design + +This proposal introduces 8 new instructions: + + - `i32.trunc_sat_f32_s` + - `i32.trunc_sat_f32_u` + - `i32.trunc_sat_f64_s` + - `i32.trunc_sat_f64_u` + - `i64.trunc_sat_f32_s` + - `i64.trunc_sat_f32_u` + - `i64.trunc_sat_f64_s` + - `i64.trunc_sat_f64_u` + +The semantics are the same as the corresponding non-`_sat` instructions, except: + - Instead of trapping on positive or negative overflow, they return the maximum + or minimum integer value, respectively, and do not trap. (This behavior is + also referred to as "saturating".) + - Instead of trapping on NaN, they return 0 and do not trap. + +### Encoding + +This proposal introduces a new prefix byte: + +| Prefix | Name | Description | +| ------ | ------- | ----------- | +| `0xfc` | misc | Miscellaneous operations :bowling: | + +which is intended to be used as a prefix for other future miscellaneous operations +as well. + +The encodings for the new instructions use this new prefix and are as follows: + +| Name | Opcode | Immediate | Description | +| ---- | ---- | ---- | ---- | +| `i32.trunc_sat_f32_s` | `0xfc` `0x00` | | :bowling: saturating form of `i32.trunc_f32_s` | +| `i32.trunc_sat_f32_u` | `0xfc` `0x01` | | :bowling: saturating form of `i32.trunc_f32_u` | +| `i32.trunc_sat_f64_s` | `0xfc` `0x02` | | :bowling: saturating form of `i32.trunc_f64_s` | +| `i32.trunc_sat_f64_u` | `0xfc` `0x03` | | :bowling: saturating form of `i32.trunc_f64_u` | +| `i64.trunc_sat_f32_s` | `0xfc` `0x04` | | :bowling: saturating form of `i64.trunc_f32_s` | +| `i64.trunc_sat_f32_u` | `0xfc` `0x05` | | :bowling: saturating form of `i64.trunc_f32_u` | +| `i64.trunc_sat_f64_s` | `0xfc` `0x06` | | :bowling: saturating form of `i64.trunc_f64_s` | +| `i64.trunc_sat_f64_u` | `0xfc` `0x07` | | :bowling: saturating form of `i64.trunc_f64_u` | diff --git a/proposals/sign-extension-ops/Overview.md b/proposals/sign-extension-ops/Overview.md new file mode 100644 index 0000000000..55df64b4cf --- /dev/null +++ b/proposals/sign-extension-ops/Overview.md @@ -0,0 +1,51 @@ +# Sign-extension operators proposal for WebAssembly + +This page describes a proposal for the post-MVP +[sign-extension operator feature][future sext]. + +This proposal adds five new integer instructions for sign-extending 8-bit, +16-bit, and 32-bit values. + +## New Sign-extending Operators + +To support sign-extending, five new sign-extension operators are added: + + * `i32.extend8_s`: extend a signed 8-bit integer to a 32-bit integer + * `i32.extend16_s`: extend a signed 16-bit integer to a 32-bit integer + * `i64.extend8_s`: extend a signed 8-bit integer to a 64-bit integer + * `i64.extend16_s`: extend a signed 16-bit integer to a 64-bit integer + * `i64.extend32_s`: extend a signed 32-bit integer to a 64-bit integer + +Note that `i64.extend32_s` was not originally included when this proposal was +discussed in the May 2017 CG meeting. The reason given was that +the behavior matches `i64.extend_s/i32`. It was later discovered that this is +not correct, as `i64.extend_s/i32` sign-extends an `i32` value to `i64`, +whereas `i64.extend32_s` sign-extends an `i64` value to `i64`. The behavior +of `i64.extend32_s` can be emulated with `i32.wrap/i64` followed by +`i64.extend_s/i32`, but the same can be said of the sign-extending load +operations. Therefore, `i64.extend32_s` has been added for consistency. + +## [Spec Changes][spec] + +The [instruction syntax][] is modified as follows: + +``` +instr ::= ... | + inn.extend8_s | inn.extend16_s | i64.extend32_s +``` + +The [instruction binary format][] is modified as follows: + +``` +instr ::= ... + | 0xC0 => i32.extend8_s + | 0xC1 => i32.extend16_s + | 0xC2 => i64.extend8_s + | 0xC3 => i64.extend16_s + | 0xC4 => i64.extend32_s +``` + +[future sext]: https://github.com/WebAssembly/design/blob/master/FutureFeatures.md#additional-integer-operators +[instruction syntax]: https://webassembly.github.io/spec/syntax/instructions.html +[instruction binary format]: https://webassembly.github.io/spec/binary/instructions.html +[spec]: https://webassembly.github.io/sign-extension-ops/ diff --git a/test/core/address.wast b/test/core/address.wast index e071cca503..320ea36bc0 100644 --- a/test/core/address.wast +++ b/test/core/address.wast @@ -191,6 +191,13 @@ (assert_return (invoke "32_good4" (i32.const 65508)) (i32.const 0)) (assert_trap (invoke "32_good5" (i32.const 65508)) "out of bounds memory access") +(assert_trap (invoke "8u_good3" (i32.const -1)) "out of bounds memory access") +(assert_trap (invoke "8s_good3" (i32.const -1)) "out of bounds memory access") +(assert_trap (invoke "16u_good3" (i32.const -1)) "out of bounds memory access") +(assert_trap (invoke "16s_good3" (i32.const -1)) "out of bounds memory access") +(assert_trap (invoke "32_good3" (i32.const -1)) "out of bounds memory access") +(assert_trap (invoke "32_good3" (i32.const -1)) "out of bounds memory access") + (assert_trap (invoke "8u_bad" (i32.const 0)) "out of bounds memory access") (assert_trap (invoke "8s_bad" (i32.const 0)) "out of bounds memory access") (assert_trap (invoke "16u_bad" (i32.const 0)) "out of bounds memory access") @@ -478,6 +485,14 @@ (assert_return (invoke "64_good4" (i32.const 65504)) (i64.const 0)) (assert_trap (invoke "64_good5" (i32.const 65504)) "out of bounds memory access") +(assert_trap (invoke "8u_good3" (i32.const -1)) "out of bounds memory access") +(assert_trap (invoke "8s_good3" (i32.const -1)) "out of bounds memory access") +(assert_trap (invoke "16u_good3" (i32.const -1)) "out of bounds memory access") +(assert_trap (invoke "16s_good3" (i32.const -1)) "out of bounds memory access") +(assert_trap (invoke "32u_good3" (i32.const -1)) "out of bounds memory access") +(assert_trap (invoke "32s_good3" (i32.const -1)) "out of bounds memory access") +(assert_trap (invoke "64_good3" (i32.const -1)) "out of bounds memory access") + (assert_trap (invoke "8u_bad" (i32.const 0)) "out of bounds memory access") (assert_trap (invoke "8s_bad" (i32.const 0)) "out of bounds memory access") (assert_trap (invoke "16u_bad" (i32.const 0)) "out of bounds memory access") @@ -538,6 +553,9 @@ (assert_return (invoke "32_good4" (i32.const 65525)) (f32.const 0.0)) (assert_trap (invoke "32_good5" (i32.const 65525)) "out of bounds memory access") +(assert_trap (invoke "32_good3" (i32.const -1)) "out of bounds memory access") +(assert_trap (invoke "32_good3" (i32.const -1)) "out of bounds memory access") + (assert_trap (invoke "32_bad" (i32.const 0)) "out of bounds memory access") (assert_trap (invoke "32_bad" (i32.const 1)) "out of bounds memory access") @@ -585,5 +603,8 @@ (assert_return (invoke "64_good4" (i32.const 65511)) (f64.const 0.0)) (assert_trap (invoke "64_good5" (i32.const 65511)) "out of bounds memory access") +(assert_trap (invoke "64_good3" (i32.const -1)) "out of bounds memory access") +(assert_trap (invoke "64_good3" (i32.const -1)) "out of bounds memory access") + (assert_trap (invoke "64_bad" (i32.const 0)) "out of bounds memory access") (assert_trap (invoke "64_bad" (i32.const 1)) "out of bounds memory access") diff --git a/test/core/binary.wast b/test/core/binary.wast index 4b00271df6..c97d377c4e 100644 --- a/test/core/binary.wast +++ b/test/core/binary.wast @@ -1491,7 +1491,7 @@ "\02" ;; break depth for default "\0b\0b\0b" ;; end ) - "malformed reference type" + "unexpected end" ) ;; Start section diff --git a/test/core/block.wast b/test/core/block.wast index 625dd98fbf..44915b991b 100644 --- a/test/core/block.wast +++ b/test/core/block.wast @@ -18,7 +18,16 @@ (func (export "multi") (result i32) (block (call $dummy) (call $dummy) (call $dummy) (call $dummy)) - (block (result i32) (call $dummy) (call $dummy) (call $dummy) (i32.const 8)) + (block (result i32) + (call $dummy) (call $dummy) (call $dummy) (i32.const 7) (call $dummy) + ) + (drop) + (block (result i32 i64 i32) + (call $dummy) (call $dummy) (call $dummy) (i32.const 8) (call $dummy) + (call $dummy) (call $dummy) (call $dummy) (i64.const 7) (call $dummy) + (call $dummy) (call $dummy) (call $dummy) (i32.const 9) (call $dummy) + ) + (drop) (drop) ) (func (export "nested") (result i32) @@ -198,6 +207,28 @@ (block (result f32) (call $dummy) (f32.const 3)) ) ) + (func (export "as-binary-operands") (result i32) + (i32.mul + (block (result i32 i32) + (call $dummy) (i32.const 3) (call $dummy) (i32.const 4) + ) + ) + ) + (func (export "as-compare-operands") (result i32) + (f32.gt + (block (result f32 f32) + (call $dummy) (f32.const 3) (call $dummy) (f32.const 3) + ) + ) + ) + (func (export "as-mixed-operands") (result i32) + (block (result i32 i32) + (call $dummy) (i32.const 3) (call $dummy) (i32.const 4) + ) + (i32.const 5) + (i32.add) + (i32.mul) + ) (func (export "break-bare") (result i32) (block (br 0) (unreachable)) @@ -209,6 +240,12 @@ (func (export "break-value") (result i32) (block (result i32) (br 0 (i32.const 18)) (i32.const 19)) ) + (func (export "break-multi-value") (result i32 i32 i64) + (block (result i32 i32 i64) + (br 0 (i32.const 18) (i32.const -18) (i64.const 18)) + (i32.const 19) (i32.const -19) (i64.const 19) + ) + ) (func (export "break-repeated") (result i32) (block (result i32) (br 0 (i32.const 18)) @@ -235,6 +272,49 @@ (local.get 0) ) + (func (export "param") (result i32) + (i32.const 1) + (block (param i32) (result i32) + (i32.const 2) + (i32.add) + ) + ) + (func (export "params") (result i32) + (i32.const 1) + (i32.const 2) + (block (param i32 i32) (result i32) + (i32.add) + ) + ) + (func (export "params-id") (result i32) + (i32.const 1) + (i32.const 2) + (block (param i32 i32) (result i32 i32)) + (i32.add) + ) + (func (export "param-break") (result i32) + (i32.const 1) + (block (param i32) (result i32) + (i32.const 2) + (i32.add) + (br 0) + ) + ) + (func (export "params-break") (result i32) + (i32.const 1) + (i32.const 2) + (block (param i32 i32) (result i32) + (i32.add) + (br 0) + ) + ) + (func (export "params-id-break") (result i32) + (i32.const 1) + (i32.const 2) + (block (param i32 i32) (result i32 i32) (br 0)) + (i32.add) + ) + (func (export "effects") (result i32) (local i32) (block @@ -247,6 +327,27 @@ ) (i32.eq (local.get 0) (i32.const -14)) ) + + (type $block-sig-1 (func)) + (type $block-sig-2 (func (result i32))) + (type $block-sig-3 (func (param $x i32))) + (type $block-sig-4 (func (param i32 f64 i32) (result i32 f64 i32))) + + (func (export "type-use") + (block (type $block-sig-1)) + (block (type $block-sig-2) (i32.const 0)) + (block (type $block-sig-3) (drop)) + (i32.const 0) (f64.const 0) (i32.const 0) + (block (type $block-sig-4)) + (drop) (drop) (drop) + (block (type $block-sig-2) (result i32) (i32.const 0)) + (block (type $block-sig-3) (param i32) (drop)) + (i32.const 0) (f64.const 0) (i32.const 0) + (block (type $block-sig-4) + (param i32) (param f64 i32) (result i32 f64) (result i32) + ) + (drop) (drop) (drop) + ) ) (assert_return (invoke "empty")) @@ -294,14 +395,112 @@ (assert_return (invoke "as-binary-operand") (i32.const 12)) (assert_return (invoke "as-test-operand") (i32.const 0)) (assert_return (invoke "as-compare-operand") (i32.const 0)) +(assert_return (invoke "as-binary-operands") (i32.const 12)) +(assert_return (invoke "as-compare-operands") (i32.const 0)) +(assert_return (invoke "as-mixed-operands") (i32.const 27)) (assert_return (invoke "break-bare") (i32.const 19)) (assert_return (invoke "break-value") (i32.const 18)) +(assert_return (invoke "break-multi-value") + (i32.const 18) (i32.const -18) (i64.const 18) +) (assert_return (invoke "break-repeated") (i32.const 18)) (assert_return (invoke "break-inner") (i32.const 0xf)) +(assert_return (invoke "param") (i32.const 3)) +(assert_return (invoke "params") (i32.const 3)) +(assert_return (invoke "params-id") (i32.const 3)) +(assert_return (invoke "param-break") (i32.const 3)) +(assert_return (invoke "params-break") (i32.const 3)) +(assert_return (invoke "params-id-break") (i32.const 3)) + (assert_return (invoke "effects") (i32.const 1)) +(assert_return (invoke "type-use")) + +(assert_malformed + (module quote + "(type $sig (func (param i32) (result i32)))" + "(func (i32.const 0) (block (type $sig) (result i32) (param i32)))" + ) + "unexpected token" +) +(assert_malformed + (module quote + "(type $sig (func (param i32) (result i32)))" + "(func (i32.const 0) (block (param i32) (type $sig) (result i32)))" + ) + "unexpected token" +) +(assert_malformed + (module quote + "(type $sig (func (param i32) (result i32)))" + "(func (i32.const 0) (block (param i32) (result i32) (type $sig)))" + ) + "unexpected token" +) +(assert_malformed + (module quote + "(type $sig (func (param i32) (result i32)))" + "(func (i32.const 0) (block (result i32) (type $sig) (param i32)))" + ) + "unexpected token" +) +(assert_malformed + (module quote + "(type $sig (func (param i32) (result i32)))" + "(func (i32.const 0) (block (result i32) (param i32) (type $sig)))" + ) + "unexpected token" +) +(assert_malformed + (module quote + "(func (i32.const 0) (block (result i32) (param i32)))" + ) + "unexpected token" +) + +(assert_malformed + (module quote "(func (i32.const 0) (block (param $x i32) (drop)))") + "unexpected token" +) +(assert_malformed + (module quote + "(type $sig (func))" + "(func (block (type $sig) (result i32) (i32.const 0)) (unreachable))" + ) + "inline function type" +) +(assert_malformed + (module quote + "(type $sig (func (param i32) (result i32)))" + "(func (block (type $sig) (result i32) (i32.const 0)) (unreachable))" + ) + "inline function type" +) +(assert_malformed + (module quote + "(type $sig (func (param i32) (result i32)))" + "(func (i32.const 0) (block (type $sig) (param i32) (drop)) (unreachable))" + ) + "inline function type" +) +(assert_malformed + (module quote + "(type $sig (func (param i32 i32) (result i32)))" + "(func (i32.const 0) (block (type $sig) (param i32) (result i32)) (unreachable))" + ) + "inline function type" +) + +(assert_invalid + (module + (type $sig (func)) + (func (block (type $sig) (i32.const 0))) + ) + "type mismatch" +) + (assert_invalid (module (func $type-empty-i32 (result i32) (block))) "type mismatch" @@ -343,7 +542,12 @@ )) "type mismatch" ) - +(assert_invalid + (module (func $type-value-nums-vs-void + (block (i32.const 1) (i32.const 2)) + )) + "type mismatch" +) (assert_invalid (module (func $type-value-empty-vs-i32 (result i32) (block (result i32)) @@ -368,6 +572,12 @@ )) "type mismatch" ) +(assert_invalid + (module (func $type-value-empty-vs-nums (result i32 i32) + (block (result i32 i32)) + )) + "type mismatch" +) (assert_invalid (module @@ -421,7 +631,12 @@ )) "type mismatch" ) - +(assert_invalid + (module (func $type-value-void-vs-nums (result i32 i32) + (block (result i32 i32) (nop)) + )) + "type mismatch" +) (assert_invalid (module (func $type-value-i32-vs-i64 (result i32) (block (result i32) (i64.const 0)) @@ -494,6 +709,24 @@ )) "type mismatch" ) +(assert_invalid + (module (func $type-value-num-vs-nums (result i32 i32) + (block (result i32 i32) (i32.const 0)) + )) + "type mismatch" +) +(assert_invalid + (module (func $type-value-partial-vs-nums (result i32 i32) + (i32.const 1) (block (result i32 i32) (i32.const 2)) + )) + "type mismatch" +) +(assert_invalid + (module (func $type-value-nums-vs-num (result i32) + (block (result i32) (i32.const 1) (i32.const 2)) + )) + "type mismatch" +) (assert_invalid (module (func $type-value-unreached-select-i32-i64 (result i32) @@ -592,6 +825,12 @@ )) "type mismatch" ) +(assert_invalid + (module (func $type-break-last-void-vs-nums (result i32 i32) + (block (result i32 i32) (br 0)) + )) + "type mismatch" +) (assert_invalid (module (func $type-break-empty-vs-i32 (result i32) @@ -617,6 +856,12 @@ )) "type mismatch" ) +(assert_invalid + (module (func $type-break-empty-vs-nums (result i32 i32) + (block (result i32 i32) (br 0) (i32.const 1) (i32.const 2)) + )) + "type mismatch" +) (assert_invalid (module (func $type-break-void-vs-i32 (result i32) @@ -715,6 +960,18 @@ )) "type mismatch" ) +(assert_invalid + (module (func $type-break-num-vs-nums (result i32 i32) + (block (result i32 i32) (br 0 (i32.const 0)) (i32.const 1) (i32.const 2)) + )) + "type mismatch" +) +(assert_invalid + (module (func $type-break-partial-vs-nums (result i32 i32) + (i32.const 1) (block (result i32 i32) (br 0 (i32.const 0)) (i32.const 2)) + )) + "type mismatch" +) (assert_invalid (module (func $type-break-first-void-vs-i32 (result i32) @@ -740,6 +997,12 @@ )) "type mismatch" ) +(assert_invalid + (module (func $type-break-first-void-vs-nums (result i32 i32) + (block (result i32 i32) (br 0 (nop)) (br 0 (i32.const 1) (i32.const 2))) + )) + "type mismatch" +) (assert_invalid (module (func $type-break-first-i32-vs-i64 (result i32) @@ -813,6 +1076,12 @@ )) "type mismatch" ) +(assert_invalid + (module (func $type-break-first-num-vs-nums (result i32 i32) + (block (result i32 i32) (br 0 (i32.const 0)) (br 0 (i32.const 1) (i32.const 2))) + )) + "type mismatch" +) (assert_invalid (module (func $type-break-nested-i32-vs-void @@ -838,6 +1107,12 @@ )) "type mismatch" ) +(assert_invalid + (module (func $type-break-nested-nums-vs-void + (block (result i32 i32) (block (result i32 i32) (br 1 (i32.const 1) (i32.const 2))) (br 0)) + )) + "type mismatch" +) (assert_invalid (module (func $type-break-nested-empty-vs-i32 (result i32) @@ -863,6 +1138,12 @@ )) "type mismatch" ) +(assert_invalid + (module (func $type-break-nested-empty-vs-nums (result i32 i32) + (block (result i32 i32) (block (br 1)) (br 0 (i32.const 1) (i32.const 2))) + )) + "type mismatch" +) (assert_invalid (module (func $type-break-nested-void-vs-i32 (result i32) @@ -888,6 +1169,12 @@ )) "type mismatch" ) +(assert_invalid + (module (func $type-break-nested-void-vs-nums (result i32 i32) + (block (result i32 i32) (block (result i32 i32) (br 1 (nop))) (br 0 (i32.const 1) (i32.const 2))) + )) + "type mismatch" +) (assert_invalid (module (func $type-break-nested-i32-vs-i64 (result i32) @@ -985,6 +1272,14 @@ )) "type mismatch" ) +(assert_invalid + (module (func $type-break-nested-num-vs-nums (result i32 i32) + (block (result i32 i32) + (block (result i32 i32) (br 1 (i32.const 0))) (br 0 (i32.const 1) (i32.const 2)) + ) + )) + "type mismatch" +) (assert_invalid (module (func $type-break-operand-empty-vs-i32 (result i32) @@ -1010,6 +1305,12 @@ )) "type mismatch" ) +(assert_invalid + (module (func $type-break-operand-empty-vs-nums (result i32) + (i32.add (block (br 0))) + )) + "type mismatch" +) (assert_invalid (module (func $type-break-operand-void-vs-i32 (result i32) @@ -1035,6 +1336,12 @@ )) "type mismatch" ) +(assert_invalid + (module (func $type-break-operand-void-vs-nums (result i32) + (i32.add (block (br 0 (nop)))) + )) + "type mismatch" +) (assert_invalid (module (func $type-break-operand-i32-vs-i64 (result i32) @@ -1108,6 +1415,70 @@ )) "type mismatch" ) +(assert_invalid + (module (func $type-break-operand-num-vs-nums (result i32) + (i32.add (block (br 0 (i64.const 9) (i32.const 10)))) + )) + "type mismatch" +) + +(assert_invalid + (module (func $type-param-void-vs-num + (block (param i32) (drop)) + )) + "type mismatch" +) +(assert_invalid + (module (func $type-param-void-vs-nums + (block (param i32 f64) (drop) (drop)) + )) + "type mismatch" +) +(assert_invalid + (module (func $type-param-num-vs-num + (f32.const 0) (block (param i32) (drop)) + )) + "type mismatch" +) +(assert_invalid + (module (func $type-param-num-vs-nums + (f32.const 0) (block (param f32 i32) (drop) (drop)) + )) + "type mismatch" +) +(assert_invalid + (module (func $type-param-nested-void-vs-num + (block (block (param i32) (drop))) + )) + "type mismatch" +) +(assert_invalid + (module (func $type-param-void-vs-nums + (block (block (param i32 f64) (drop) (drop))) + )) + "type mismatch" +) +(assert_invalid + (module (func $type-param-num-vs-num + (block (f32.const 0) (block (param i32) (drop))) + )) + "type mismatch" +) +(assert_invalid + (module (func $type-param-num-vs-nums + (block (f32.const 0) (block (param f32 i32) (drop) (drop))) + )) + "type mismatch" +) + +(assert_malformed + (module quote "(func (param i32) (result i32) block (param $x i32) end)") + "unexpected token" +) +(assert_malformed + (module quote "(func (param i32) (result i32) (block (param $x i32)))") + "unexpected token" +) (assert_malformed diff --git a/test/core/br.wast b/test/core/br.wast index 98a3a34bdc..35f707c922 100644 --- a/test/core/br.wast +++ b/test/core/br.wast @@ -8,6 +8,10 @@ (func (export "type-i64") (block (drop (i64.ctz (br 0))))) (func (export "type-f32") (block (drop (f32.neg (br 0))))) (func (export "type-f64") (block (drop (f64.neg (br 0))))) + (func (export "type-i32-i32") (block (drop (i32.add (br 0))))) + (func (export "type-i64-i64") (block (drop (i64.add (br 0))))) + (func (export "type-f32-f32") (block (drop (f32.add (br 0))))) + (func (export "type-f64-f64") (block (drop (f64.add (br 0))))) (func (export "type-i32-value") (result i32) (block (result i32) (i32.ctz (br 0 (i32.const 1)))) @@ -21,6 +25,11 @@ (func (export "type-f64-value") (result f64) (block (result f64) (f64.neg (br 0 (f64.const 4)))) ) + (func (export "type-f64-f64-value") (result f64 f64) + (block (result f64 f64) + (f64.add (br 0 (f64.const 4) (f64.const 5))) (f64.const 6) + ) + ) (func (export "as-block-first") (block (br 0) (call $dummy)) @@ -84,6 +93,10 @@ (func (export "as-return-value") (result i64) (block (result i64) (return (br 0 (i64.const 7)))) ) + (func (export "as-return-values") (result i32 i64) + (i32.const 2) + (block (result i64) (return (br 0 (i32.const 1) (i64.const 7)))) + ) (func (export "as-if-cond") (result i32) (block (result i32) @@ -125,6 +138,9 @@ (select (i32.const 0) (i32.const 1) (br 0 (i32.const 7))) ) ) + (func (export "as-select-all") (result i32) + (block (result i32) (select (br 0 (i32.const 8)))) + ) (func $f (param i32 i32 i32) (result i32) (i32.const -1)) (func (export "as-call-first") (result i32) @@ -142,6 +158,9 @@ (call $f (i32.const 1) (i32.const 2) (br 0 (i32.const 14))) ) ) + (func (export "as-call-all") (result i32) + (block (result i32) (call $f (br 0 (i32.const 15)))) + ) (type $sig (func (param i32 i32 i32) (result i32))) (table funcref (elem $f)) @@ -177,6 +196,9 @@ ) ) ) + (func (export "as-call_indirect-all") (result i32) + (block (result i32) (call_indirect (type $sig) (br 0 (i32.const 24)))) + ) (func (export "as-local.set-value") (result i32) (local f32) (block (result i32) (local.set 0 (br 0 (i32.const 17))) (i32.const -1)) @@ -207,6 +229,11 @@ (i64.store (i32.const 2) (br 0 (i32.const 31))) (i32.const -1) ) ) + (func (export "as-store-both") (result i32) + (block (result i32) + (i64.store (br 0 (i32.const 32))) (i32.const -1) + ) + ) (func (export "as-storeN-address") (result i32) (block (result i32) @@ -218,6 +245,11 @@ (i64.store16 (i32.const 2) (br 0 (i32.const 33))) (i32.const -1) ) ) + (func (export "as-storeN-both") (result i32) + (block (result i32) + (i64.store16 (br 0 (i32.const 34))) (i32.const -1) + ) + ) (func (export "as-unary-operand") (result f32) (block (result f32) (f32.neg (br 0 (f32.const 3.4)))) @@ -229,6 +261,9 @@ (func (export "as-binary-right") (result i64) (block (result i64) (i64.sub (i64.const 10) (br 0 (i64.const 45)))) ) + (func (export "as-binary-both") (result i32) + (block (result i32) (i32.add (br 0 (i32.const 46)))) + ) (func (export "as-test-operand") (result i32) (block (result i32) (i32.eqz (br 0 (i32.const 44)))) @@ -240,6 +275,9 @@ (func (export "as-compare-right") (result i32) (block (result i32) (f32.ne (f32.const 10) (br 0 (i32.const 42)))) ) + (func (export "as-compare-both") (result i32) + (block (result i32) (f64.le (br 0 (i32.const 44)))) + ) (func (export "as-convert-operand") (result i32) (block (result i32) (i32.wrap_i64 (br 0 (i32.const 41)))) @@ -335,11 +373,16 @@ (assert_return (invoke "type-i64")) (assert_return (invoke "type-f32")) (assert_return (invoke "type-f64")) +(assert_return (invoke "type-i32-i32")) +(assert_return (invoke "type-i64-i64")) +(assert_return (invoke "type-f32-f32")) +(assert_return (invoke "type-f64-f64")) (assert_return (invoke "type-i32-value") (i32.const 1)) (assert_return (invoke "type-i64-value") (i64.const 2)) (assert_return (invoke "type-f32-value") (f32.const 3)) (assert_return (invoke "type-f64-value") (f64.const 4)) +(assert_return (invoke "type-f64-f64-value") (f64.const 4) (f64.const 5)) (assert_return (invoke "as-block-first")) (assert_return (invoke "as-block-mid")) @@ -361,6 +404,7 @@ (assert_return (invoke "as-br_table-value-index") (i32.const 11)) (assert_return (invoke "as-return-value") (i64.const 7)) +(assert_return (invoke "as-return-values") (i32.const 2) (i64.const 7)) (assert_return (invoke "as-if-cond") (i32.const 2)) (assert_return (invoke "as-if-then" (i32.const 1) (i32.const 6)) (i32.const 3)) @@ -373,15 +417,18 @@ (assert_return (invoke "as-select-second" (i32.const 0) (i32.const 6)) (i32.const 6)) (assert_return (invoke "as-select-second" (i32.const 1) (i32.const 6)) (i32.const 6)) (assert_return (invoke "as-select-cond") (i32.const 7)) +(assert_return (invoke "as-select-all") (i32.const 8)) (assert_return (invoke "as-call-first") (i32.const 12)) (assert_return (invoke "as-call-mid") (i32.const 13)) (assert_return (invoke "as-call-last") (i32.const 14)) +(assert_return (invoke "as-call-all") (i32.const 15)) (assert_return (invoke "as-call_indirect-func") (i32.const 20)) (assert_return (invoke "as-call_indirect-first") (i32.const 21)) (assert_return (invoke "as-call_indirect-mid") (i32.const 22)) (assert_return (invoke "as-call_indirect-last") (i32.const 23)) +(assert_return (invoke "as-call_indirect-all") (i32.const 24)) (assert_return (invoke "as-local.set-value") (i32.const 17)) (assert_return (invoke "as-local.tee-value") (i32.const 1)) @@ -392,18 +439,22 @@ (assert_return (invoke "as-store-address") (i32.const 30)) (assert_return (invoke "as-store-value") (i32.const 31)) +(assert_return (invoke "as-store-both") (i32.const 32)) (assert_return (invoke "as-storeN-address") (i32.const 32)) (assert_return (invoke "as-storeN-value") (i32.const 33)) +(assert_return (invoke "as-storeN-both") (i32.const 34)) (assert_return (invoke "as-unary-operand") (f32.const 3.4)) (assert_return (invoke "as-binary-left") (i32.const 3)) (assert_return (invoke "as-binary-right") (i64.const 45)) +(assert_return (invoke "as-binary-both") (i32.const 46)) (assert_return (invoke "as-test-operand") (i32.const 44)) (assert_return (invoke "as-compare-left") (i32.const 43)) (assert_return (invoke "as-compare-right") (i32.const 42)) +(assert_return (invoke "as-compare-both") (i32.const 44)) (assert_return (invoke "as-convert-operand") (i32.const 41)) diff --git a/test/core/break-drop.wast b/test/core/break-drop.wast deleted file mode 100644 index e10df66715..0000000000 --- a/test/core/break-drop.wast +++ /dev/null @@ -1,9 +0,0 @@ -(module - (func (export "br") (block (br 0))) - (func (export "br_if") (block (br_if 0 (i32.const 1)))) - (func (export "br_table") (block (br_table 0 (i32.const 0)))) -) - -(assert_return (invoke "br")) -(assert_return (invoke "br_if")) -(assert_return (invoke "br_table")) diff --git a/test/core/call.wast b/test/core/call.wast index 4d0f1a7c25..e4f854f7a5 100644 --- a/test/core/call.wast +++ b/test/core/call.wast @@ -6,11 +6,25 @@ (func $const-i64 (result i64) (i64.const 0x164)) (func $const-f32 (result f32) (f32.const 0xf32)) (func $const-f64 (result f64) (f64.const 0xf64)) + (func $const-i32-i64 (result i32 i64) (i32.const 0x132) (i64.const 0x164)) (func $id-i32 (param i32) (result i32) (local.get 0)) (func $id-i64 (param i64) (result i64) (local.get 0)) (func $id-f32 (param f32) (result f32) (local.get 0)) (func $id-f64 (param f64) (result f64) (local.get 0)) + (func $id-i32-f64 (param i32 f64) (result i32 f64) + (local.get 0) (local.get 1) + ) + + (func $swap-i32-i32 (param i32 i32) (result i32 i32) + (local.get 1) (local.get 0) + ) + (func $swap-f32-f64 (param f32 f64) (result f64 f32) + (local.get 1) (local.get 0) + ) + (func $swap-f64-i32 (param f64 i32) (result i32 f64) + (local.get 1) (local.get 0) + ) (func $f32-i32 (param f32 i32) (result i32) (local.get 1)) (func $i32-i64 (param i32 i64) (result i64) (local.get 1)) @@ -23,6 +37,7 @@ (func (export "type-i64") (result i64) (call $const-i64)) (func (export "type-f32") (result f32) (call $const-f32)) (func (export "type-f64") (result f64) (call $const-f64)) + (func (export "type-i32-i64") (result i32 i64) (call $const-i32-i64)) (func (export "type-first-i32") (result i32) (call $id-i32 (i32.const 32))) (func (export "type-first-i64") (result i64) (call $id-i64 (i64.const 64))) @@ -42,6 +57,36 @@ (call $i64-f64 (i64.const 64) (f64.const 64.1)) ) + (func (export "type-all-i32-f64") (result i32 f64) + (call $id-i32-f64 (i32.const 32) (f64.const 1.64)) + ) + (func (export "type-all-i32-i32") (result i32 i32) + (call $swap-i32-i32 (i32.const 1) (i32.const 2)) + ) + (func (export "type-all-f32-f64") (result f64 f32) + (call $swap-f32-f64 (f32.const 1) (f64.const 2)) + ) + (func (export "type-all-f64-i32") (result i32 f64) + (call $swap-f64-i32 (f64.const 1) (i32.const 2)) + ) + + ;; Composition + + (func (export "as-binary-all-operands") (result i32) + (i32.add (call $swap-i32-i32 (i32.const 3) (i32.const 4))) + ) + + (func (export "as-mixed-operands") (result i32) + (call $swap-i32-i32 (i32.const 3) (i32.const 4)) + (i32.const 5) + (i32.add) + (i32.mul) + ) + + (func (export "as-call-all-operands") (result i32 i32) + (call $swap-i32-i32 (call $swap-i32-i32 (i32.const 3) (i32.const 4))) + ) + ;; Recursion (func $fac (export "fac") (param i64) (result i64) @@ -241,6 +286,7 @@ (assert_return (invoke "type-i64") (i64.const 0x164)) (assert_return (invoke "type-f32") (f32.const 0xf32)) (assert_return (invoke "type-f64") (f64.const 0xf64)) +(assert_return (invoke "type-i32-i64") (i32.const 0x132) (i64.const 0x164)) (assert_return (invoke "type-first-i32") (i32.const 32)) (assert_return (invoke "type-first-i64") (i64.const 64)) @@ -252,6 +298,15 @@ (assert_return (invoke "type-second-f32") (f32.const 32)) (assert_return (invoke "type-second-f64") (f64.const 64.1)) +(assert_return (invoke "type-all-i32-f64") (i32.const 32) (f64.const 1.64)) +(assert_return (invoke "type-all-i32-i32") (i32.const 2) (i32.const 1)) +(assert_return (invoke "type-all-f32-f64") (f64.const 2) (f32.const 1)) +(assert_return (invoke "type-all-f64-i32") (i32.const 2) (f64.const 1)) + +(assert_return (invoke "as-binary-all-operands") (i32.const 7)) +(assert_return (invoke "as-mixed-operands") (i32.const 32)) +(assert_return (invoke "as-call-all-operands") (i32.const 3) (i32.const 4)) + (assert_return (invoke "fac" (i64.const 0)) (i64.const 1)) (assert_return (invoke "fac" (i64.const 1)) (i64.const 1)) (assert_return (invoke "fac" (i64.const 5)) (i64.const 120)) diff --git a/test/core/call_indirect.wast b/test/core/call_indirect.wast index de7534b9c6..1ecd9b7baf 100644 --- a/test/core/call_indirect.wast +++ b/test/core/call_indirect.wast @@ -7,10 +7,13 @@ (type $out-i64 (func (result i64))) (type $out-f32 (func (result f32))) (type $out-f64 (func (result f64))) + (type $out-f64-i32 (func (result f64 i32))) (type $over-i32 (func (param i32) (result i32))) (type $over-i64 (func (param i64) (result i64))) (type $over-f32 (func (param f32) (result f32))) (type $over-f64 (func (param f64) (result f64))) + (type $over-i32-f64 (func (param i32 f64) (result i32 f64))) + (type $swap-i32-i64 (func (param i32 i64) (result i64 i32))) (type $f32-i32 (func (param f32 i32) (result i32))) (type $i32-i64 (func (param i32 i64) (result i64))) (type $f64-f32 (func (param f64 f32) (result f32))) @@ -24,11 +27,14 @@ (func $const-i64 (type $out-i64) (i64.const 0x164)) (func $const-f32 (type $out-f32) (f32.const 0xf32)) (func $const-f64 (type $out-f64) (f64.const 0xf64)) + (func $const-f64-i32 (type $out-f64-i32) (f64.const 0xf64) (i32.const 32)) (func $id-i32 (type $over-i32) (local.get 0)) (func $id-i64 (type $over-i64) (local.get 0)) (func $id-f32 (type $over-f32) (local.get 0)) (func $id-f64 (type $over-f64) (local.get 0)) + (func $id-i32-f64 (type $over-i32-f64) (local.get 0) (local.get 1)) + (func $swap-i32-i64 (type $swap-i32-i64) (local.get 1) (local.get 0)) (func $i32-i64 (type $i32-i64) (local.get 1)) (func $i64-f64 (type $i64-f64) (local.get 1)) @@ -42,15 +48,16 @@ (table funcref (elem - $const-i32 $const-i64 $const-f32 $const-f64 - $id-i32 $id-i64 $id-f32 $id-f64 - $f32-i32 $i32-i64 $f64-f32 $i64-f64 - $fac-i64 $fib-i64 $even $odd - $runaway $mutual-runaway1 $mutual-runaway2 - $over-i32-duplicate $over-i64-duplicate - $over-f32-duplicate $over-f64-duplicate - $fac-i32 $fac-f32 $fac-f64 - $fib-i32 $fib-f32 $fib-f64 + $const-i32 $const-i64 $const-f32 $const-f64 ;; 0..3 + $id-i32 $id-i64 $id-f32 $id-f64 ;; 4..7 + $f32-i32 $i32-i64 $f64-f32 $i64-f64 ;; 9..11 + $fac-i64 $fib-i64 $even $odd ;; 12..15 + $runaway $mutual-runaway1 $mutual-runaway2 ;; 16..18 + $over-i32-duplicate $over-i64-duplicate ;; 19..20 + $over-f32-duplicate $over-f64-duplicate ;; 21..22 + $fac-i32 $fac-f32 $fac-f64 ;; 23..25 + $fib-i32 $fib-f32 $fib-f64 ;; 26..28 + $const-f64-i32 $id-i32-f64 $swap-i32-i64 ;; 29..31 ) ) @@ -96,6 +103,9 @@ (func (export "type-f64") (result f64) (call_indirect (type $out-f64) (i32.const 3)) ) + (func (export "type-f64-i32") (result f64 i32) + (call_indirect (type $out-f64-i32) (i32.const 29)) + ) (func (export "type-index") (result i64) (call_indirect (type $over-i64) (i64.const 100) (i32.const 5)) @@ -127,6 +137,20 @@ (call_indirect (type $i64-f64) (i64.const 64) (f64.const 64.1) (i32.const 11)) ) + (func (export "type-all-f64-i32") (result f64 i32) + (call_indirect (type $out-f64-i32) (i32.const 29)) + ) + (func (export "type-all-i32-f64") (result i32 f64) + (call_indirect (type $over-i32-f64) + (i32.const 1) (f64.const 2) (i32.const 30) + ) + ) + (func (export "type-all-i32-i64") (result i64 i32) + (call_indirect (type $swap-i32-i64) + (i32.const 1) (i64.const 2) (i32.const 31) + ) + ) + ;; Dispatch (func (export "dispatch") (param i32 i64) (result i64) @@ -448,6 +472,7 @@ (assert_return (invoke "type-i64") (i64.const 0x164)) (assert_return (invoke "type-f32") (f32.const 0xf32)) (assert_return (invoke "type-f64") (f64.const 0xf64)) +(assert_return (invoke "type-f64-i32") (f64.const 0xf64) (i32.const 32)) (assert_return (invoke "type-index") (i64.const 100)) @@ -461,6 +486,10 @@ (assert_return (invoke "type-second-f32") (f32.const 32)) (assert_return (invoke "type-second-f64") (f64.const 64.1)) +(assert_return (invoke "type-all-f64-i32") (f64.const 0xf64) (i32.const 32)) +(assert_return (invoke "type-all-i32-f64") (i32.const 1) (f64.const 2)) +(assert_return (invoke "type-all-i32-i64") (i64.const 2) (i32.const 1)) + (assert_return (invoke "dispatch" (i32.const 5) (i64.const 2)) (i64.const 2)) (assert_return (invoke "dispatch" (i32.const 5) (i64.const 5)) (i64.const 5)) (assert_return (invoke "dispatch" (i32.const 12) (i64.const 5)) (i64.const 120)) @@ -468,7 +497,7 @@ (assert_return (invoke "dispatch" (i32.const 20) (i64.const 2)) (i64.const 2)) (assert_trap (invoke "dispatch" (i32.const 0) (i64.const 2)) "indirect call type mismatch") (assert_trap (invoke "dispatch" (i32.const 15) (i64.const 2)) "indirect call type mismatch") -(assert_trap (invoke "dispatch" (i32.const 29) (i64.const 2)) "undefined element") +(assert_trap (invoke "dispatch" (i32.const 32) (i64.const 2)) "undefined element") (assert_trap (invoke "dispatch" (i32.const -1) (i64.const 2)) "undefined element") (assert_trap (invoke "dispatch" (i32.const 1213432423) (i64.const 2)) "undefined element") diff --git a/test/core/const.wast b/test/core/const.wast index 6e8931a063..5656502987 100644 --- a/test/core/const.wast +++ b/test/core/const.wast @@ -154,6 +154,13 @@ (module (func (f64.const 0123456789.0123456789e019) drop)) (module (func (f64.const 0123456789.0123456789e+019) drop)) (module (func (f64.const 0123456789.0123456789e-019) drop)) +(module (func (f64.const 0_1_2_3_4_5_6_7_8_9) drop)) +(module (func (f64.const 0_1_2_3_4_5_6_7_8_9.) drop)) +(module (func (f64.const 0_1_2_3_4_5_6_7_8_9.0_1_2_3_4_5_6_7_8_9) drop)) +(module (func (f64.const 0_1_2_3_4_5_6_7_8_9e+0_1_9) drop)) +(module (func (f64.const 0_1_2_3_4_5_6_7_8_9.e+0_1_9) drop)) +(module (func (f64.const 0_1_2_3_4_5_6_7_8_9.0_1_2_3_4_5_6_7_8_9e0_1_9) drop)) + (module (func (f64.const 0x0123456789ABCDEFabcdef) drop)) (module (func (f64.const 0x0123456789ABCDEFabcdefp019) drop)) (module (func (f64.const 0x0123456789ABCDEFabcdefp+019) drop)) @@ -166,6 +173,14 @@ (module (func (f64.const 0x0123456789ABCDEFabcdef.0123456789ABCDEFabcdefp019) drop)) (module (func (f64.const 0x0123456789ABCDEFabcdef.0123456789ABCDEFabcdefp+019) drop)) (module (func (f64.const 0x0123456789ABCDEFabcdef.0123456789ABCDEFabcdefp-019) drop)) +(module (func (f64.const 0x0_1_2_3_4_5_6_7_8_9_A_B_C_D_E_F_a_b_c_d_e_f) drop)) +(module (func (f64.const 0x0_1_2_3_4_5_6_7_8_9_A_B_C_D_E_F_a_b_c_d_e_f.) drop)) +(module (func (f64.const 0x0_1_2_3_4_5_6_7_8_9_A_B_C_D_E_F_a_b_c_d_e_f.0_1_2_3_4_5_6_7_8_9_A_B_C_D_E_F_a_b_c_d_e_f) drop)) +(module (func (f64.const 0x0_1_2_3_4_5_6_7_8_9_A_B_C_D_E_F_a_b_c_d_e_fp0_1_9) drop)) +(module (func (f64.const 0x0_1_2_3_4_5_6_7_8_9_A_B_C_D_E_F_a_b_c_d_e_f.p0_1_9) drop)) +(module (func (f64.const 0x0_1_2_3_4_5_6_7_8_9_A_B_C_D_E_F_a_b_c_d_e_f.0_1_2_3_4_5_6_7_8_9_A_B_C_D_E_F_a_b_c_d_e_fp0_1_9) drop)) + + (assert_malformed (module quote "(func (f64.const) drop)") "unexpected token" diff --git a/test/core/conversions.wast b/test/core/conversions.wast index 308296d2e0..99355a0857 100644 --- a/test/core/conversions.wast +++ b/test/core/conversions.wast @@ -10,6 +10,14 @@ (func (export "i64.trunc_f32_u") (param $x f32) (result i64) (i64.trunc_f32_u (local.get $x))) (func (export "i64.trunc_f64_s") (param $x f64) (result i64) (i64.trunc_f64_s (local.get $x))) (func (export "i64.trunc_f64_u") (param $x f64) (result i64) (i64.trunc_f64_u (local.get $x))) + (func (export "i32.trunc_sat_f32_s") (param $x f32) (result i32) (i32.trunc_sat_f32_s (local.get $x))) + (func (export "i32.trunc_sat_f32_u") (param $x f32) (result i32) (i32.trunc_sat_f32_u (local.get $x))) + (func (export "i32.trunc_sat_f64_s") (param $x f64) (result i32) (i32.trunc_sat_f64_s (local.get $x))) + (func (export "i32.trunc_sat_f64_u") (param $x f64) (result i32) (i32.trunc_sat_f64_u (local.get $x))) + (func (export "i64.trunc_sat_f32_s") (param $x f32) (result i64) (i64.trunc_sat_f32_s (local.get $x))) + (func (export "i64.trunc_sat_f32_u") (param $x f32) (result i64) (i64.trunc_sat_f32_u (local.get $x))) + (func (export "i64.trunc_sat_f64_s") (param $x f64) (result i64) (i64.trunc_sat_f64_s (local.get $x))) + (func (export "i64.trunc_sat_f64_u") (param $x f64) (result i64) (i64.trunc_sat_f64_u (local.get $x))) (func (export "f32.convert_i32_s") (param $x i32) (result f32) (f32.convert_i32_s (local.get $x))) (func (export "f32.convert_i64_s") (param $x i64) (result f32) (f32.convert_i64_s (local.get $x))) (func (export "f64.convert_i32_s") (param $x i32) (result f64) (f64.convert_i32_s (local.get $x))) @@ -247,6 +255,197 @@ (assert_return (invoke "f32.convert_i32_s" (i32.const 2147483647)) (f32.const 2147483648)) (assert_return (invoke "f32.convert_i32_s" (i32.const -2147483648)) (f32.const -2147483648)) (assert_return (invoke "f32.convert_i32_s" (i32.const 1234567890)) (f32.const 0x1.26580cp+30)) + +;; Saturating conversions: test all the same values as the non-saturating conversions. + +(assert_return (invoke "i32.trunc_sat_f32_s" (f32.const 0.0)) (i32.const 0)) +(assert_return (invoke "i32.trunc_sat_f32_s" (f32.const -0.0)) (i32.const 0)) +(assert_return (invoke "i32.trunc_sat_f32_s" (f32.const 0x1p-149)) (i32.const 0)) +(assert_return (invoke "i32.trunc_sat_f32_s" (f32.const -0x1p-149)) (i32.const 0)) +(assert_return (invoke "i32.trunc_sat_f32_s" (f32.const 1.0)) (i32.const 1)) +(assert_return (invoke "i32.trunc_sat_f32_s" (f32.const 0x1.19999ap+0)) (i32.const 1)) +(assert_return (invoke "i32.trunc_sat_f32_s" (f32.const 1.5)) (i32.const 1)) +(assert_return (invoke "i32.trunc_sat_f32_s" (f32.const -1.0)) (i32.const -1)) +(assert_return (invoke "i32.trunc_sat_f32_s" (f32.const -0x1.19999ap+0)) (i32.const -1)) +(assert_return (invoke "i32.trunc_sat_f32_s" (f32.const -1.5)) (i32.const -1)) +(assert_return (invoke "i32.trunc_sat_f32_s" (f32.const -1.9)) (i32.const -1)) +(assert_return (invoke "i32.trunc_sat_f32_s" (f32.const -2.0)) (i32.const -2)) +(assert_return (invoke "i32.trunc_sat_f32_s" (f32.const 2147483520.0)) (i32.const 2147483520)) +(assert_return (invoke "i32.trunc_sat_f32_s" (f32.const -2147483648.0)) (i32.const -2147483648)) +(assert_return (invoke "i32.trunc_sat_f32_s" (f32.const 2147483648.0)) (i32.const 0x7fffffff)) +(assert_return (invoke "i32.trunc_sat_f32_s" (f32.const -2147483904.0)) (i32.const 0x80000000)) +(assert_return (invoke "i32.trunc_sat_f32_s" (f32.const inf)) (i32.const 0x7fffffff)) +(assert_return (invoke "i32.trunc_sat_f32_s" (f32.const -inf)) (i32.const 0x80000000)) +(assert_return (invoke "i32.trunc_sat_f32_s" (f32.const nan)) (i32.const 0)) +(assert_return (invoke "i32.trunc_sat_f32_s" (f32.const nan:0x200000)) (i32.const 0)) +(assert_return (invoke "i32.trunc_sat_f32_s" (f32.const -nan)) (i32.const 0)) +(assert_return (invoke "i32.trunc_sat_f32_s" (f32.const -nan:0x200000)) (i32.const 0)) + +(assert_return (invoke "i32.trunc_sat_f32_u" (f32.const 0.0)) (i32.const 0)) +(assert_return (invoke "i32.trunc_sat_f32_u" (f32.const -0.0)) (i32.const 0)) +(assert_return (invoke "i32.trunc_sat_f32_u" (f32.const 0x1p-149)) (i32.const 0)) +(assert_return (invoke "i32.trunc_sat_f32_u" (f32.const -0x1p-149)) (i32.const 0)) +(assert_return (invoke "i32.trunc_sat_f32_u" (f32.const 1.0)) (i32.const 1)) +(assert_return (invoke "i32.trunc_sat_f32_u" (f32.const 0x1.19999ap+0)) (i32.const 1)) +(assert_return (invoke "i32.trunc_sat_f32_u" (f32.const 1.5)) (i32.const 1)) +(assert_return (invoke "i32.trunc_sat_f32_u" (f32.const 1.9)) (i32.const 1)) +(assert_return (invoke "i32.trunc_sat_f32_u" (f32.const 2.0)) (i32.const 2)) +(assert_return (invoke "i32.trunc_sat_f32_u" (f32.const 2147483648)) (i32.const -2147483648)) ;; 0x1.00000p+31 -> 8000 0000 +(assert_return (invoke "i32.trunc_sat_f32_u" (f32.const 4294967040.0)) (i32.const -256)) +(assert_return (invoke "i32.trunc_sat_f32_u" (f32.const -0x1.ccccccp-1)) (i32.const 0)) +(assert_return (invoke "i32.trunc_sat_f32_u" (f32.const -0x1.fffffep-1)) (i32.const 0)) +(assert_return (invoke "i32.trunc_sat_f32_u" (f32.const 4294967296.0)) (i32.const 0xffffffff)) +(assert_return (invoke "i32.trunc_sat_f32_u" (f32.const -1.0)) (i32.const 0x00000000)) +(assert_return (invoke "i32.trunc_sat_f32_u" (f32.const inf)) (i32.const 0xffffffff)) +(assert_return (invoke "i32.trunc_sat_f32_u" (f32.const -inf)) (i32.const 0x00000000)) +(assert_return (invoke "i32.trunc_sat_f32_u" (f32.const nan)) (i32.const 0)) +(assert_return (invoke "i32.trunc_sat_f32_u" (f32.const nan:0x200000)) (i32.const 0)) +(assert_return (invoke "i32.trunc_sat_f32_u" (f32.const -nan)) (i32.const 0)) +(assert_return (invoke "i32.trunc_sat_f32_u" (f32.const -nan:0x200000)) (i32.const 0)) + +(assert_return (invoke "i32.trunc_sat_f64_s" (f64.const 0.0)) (i32.const 0)) +(assert_return (invoke "i32.trunc_sat_f64_s" (f64.const -0.0)) (i32.const 0)) +(assert_return (invoke "i32.trunc_sat_f64_s" (f64.const 0x0.0000000000001p-1022)) (i32.const 0)) +(assert_return (invoke "i32.trunc_sat_f64_s" (f64.const -0x0.0000000000001p-1022)) (i32.const 0)) +(assert_return (invoke "i32.trunc_sat_f64_s" (f64.const 1.0)) (i32.const 1)) +(assert_return (invoke "i32.trunc_sat_f64_s" (f64.const 0x1.199999999999ap+0)) (i32.const 1)) +(assert_return (invoke "i32.trunc_sat_f64_s" (f64.const 1.5)) (i32.const 1)) +(assert_return (invoke "i32.trunc_sat_f64_s" (f64.const -1.0)) (i32.const -1)) +(assert_return (invoke "i32.trunc_sat_f64_s" (f64.const -0x1.199999999999ap+0)) (i32.const -1)) +(assert_return (invoke "i32.trunc_sat_f64_s" (f64.const -1.5)) (i32.const -1)) +(assert_return (invoke "i32.trunc_sat_f64_s" (f64.const -1.9)) (i32.const -1)) +(assert_return (invoke "i32.trunc_sat_f64_s" (f64.const -2.0)) (i32.const -2)) +(assert_return (invoke "i32.trunc_sat_f64_s" (f64.const 2147483647.0)) (i32.const 2147483647)) +(assert_return (invoke "i32.trunc_sat_f64_s" (f64.const -2147483648.0)) (i32.const -2147483648)) +(assert_return (invoke "i32.trunc_sat_f64_s" (f64.const 2147483648.0)) (i32.const 0x7fffffff)) +(assert_return (invoke "i32.trunc_sat_f64_s" (f64.const -2147483649.0)) (i32.const 0x80000000)) +(assert_return (invoke "i32.trunc_sat_f64_s" (f64.const inf)) (i32.const 0x7fffffff)) +(assert_return (invoke "i32.trunc_sat_f64_s" (f64.const -inf)) (i32.const 0x80000000)) +(assert_return (invoke "i32.trunc_sat_f64_s" (f64.const nan)) (i32.const 0)) +(assert_return (invoke "i32.trunc_sat_f64_s" (f64.const nan:0x4000000000000)) (i32.const 0)) +(assert_return (invoke "i32.trunc_sat_f64_s" (f64.const -nan)) (i32.const 0)) +(assert_return (invoke "i32.trunc_sat_f64_s" (f64.const -nan:0x4000000000000)) (i32.const 0)) + +(assert_return (invoke "i32.trunc_sat_f64_u" (f64.const 0.0)) (i32.const 0)) +(assert_return (invoke "i32.trunc_sat_f64_u" (f64.const -0.0)) (i32.const 0)) +(assert_return (invoke "i32.trunc_sat_f64_u" (f64.const 0x0.0000000000001p-1022)) (i32.const 0)) +(assert_return (invoke "i32.trunc_sat_f64_u" (f64.const -0x0.0000000000001p-1022)) (i32.const 0)) +(assert_return (invoke "i32.trunc_sat_f64_u" (f64.const 1.0)) (i32.const 1)) +(assert_return (invoke "i32.trunc_sat_f64_u" (f64.const 0x1.199999999999ap+0)) (i32.const 1)) +(assert_return (invoke "i32.trunc_sat_f64_u" (f64.const 1.5)) (i32.const 1)) +(assert_return (invoke "i32.trunc_sat_f64_u" (f64.const 1.9)) (i32.const 1)) +(assert_return (invoke "i32.trunc_sat_f64_u" (f64.const 2.0)) (i32.const 2)) +(assert_return (invoke "i32.trunc_sat_f64_u" (f64.const 2147483648)) (i32.const -2147483648)) ;; 0x1.00000p+31 -> 8000 0000 +(assert_return (invoke "i32.trunc_sat_f64_u" (f64.const 4294967295.0)) (i32.const -1)) +(assert_return (invoke "i32.trunc_sat_f64_u" (f64.const -0x1.ccccccccccccdp-1)) (i32.const 0)) +(assert_return (invoke "i32.trunc_sat_f64_u" (f64.const -0x1.fffffffffffffp-1)) (i32.const 0)) +(assert_return (invoke "i32.trunc_sat_f64_u" (f64.const 1e8)) (i32.const 100000000)) +(assert_return (invoke "i32.trunc_sat_f64_u" (f64.const 4294967296.0)) (i32.const 0xffffffff)) +(assert_return (invoke "i32.trunc_sat_f64_u" (f64.const -1.0)) (i32.const 0x00000000)) +(assert_return (invoke "i32.trunc_sat_f64_u" (f64.const 1e16)) (i32.const 0xffffffff)) +(assert_return (invoke "i32.trunc_sat_f64_u" (f64.const 1e30)) (i32.const 0xffffffff)) +(assert_return (invoke "i32.trunc_sat_f64_u" (f64.const 9223372036854775808)) (i32.const 0xffffffff)) +(assert_return (invoke "i32.trunc_sat_f64_u" (f64.const inf)) (i32.const 0xffffffff)) +(assert_return (invoke "i32.trunc_sat_f64_u" (f64.const -inf)) (i32.const 0x00000000)) +(assert_return (invoke "i32.trunc_sat_f64_u" (f64.const nan)) (i32.const 0)) +(assert_return (invoke "i32.trunc_sat_f64_u" (f64.const nan:0x4000000000000)) (i32.const 0)) +(assert_return (invoke "i32.trunc_sat_f64_u" (f64.const -nan)) (i32.const 0)) +(assert_return (invoke "i32.trunc_sat_f64_u" (f64.const -nan:0x4000000000000)) (i32.const 0)) + +(assert_return (invoke "i64.trunc_sat_f32_s" (f32.const 0.0)) (i64.const 0)) +(assert_return (invoke "i64.trunc_sat_f32_s" (f32.const -0.0)) (i64.const 0)) +(assert_return (invoke "i64.trunc_sat_f32_s" (f32.const 0x1p-149)) (i64.const 0)) +(assert_return (invoke "i64.trunc_sat_f32_s" (f32.const -0x1p-149)) (i64.const 0)) +(assert_return (invoke "i64.trunc_sat_f32_s" (f32.const 1.0)) (i64.const 1)) +(assert_return (invoke "i64.trunc_sat_f32_s" (f32.const 0x1.19999ap+0)) (i64.const 1)) +(assert_return (invoke "i64.trunc_sat_f32_s" (f32.const 1.5)) (i64.const 1)) +(assert_return (invoke "i64.trunc_sat_f32_s" (f32.const -1.0)) (i64.const -1)) +(assert_return (invoke "i64.trunc_sat_f32_s" (f32.const -0x1.19999ap+0)) (i64.const -1)) +(assert_return (invoke "i64.trunc_sat_f32_s" (f32.const -1.5)) (i64.const -1)) +(assert_return (invoke "i64.trunc_sat_f32_s" (f32.const -1.9)) (i64.const -1)) +(assert_return (invoke "i64.trunc_sat_f32_s" (f32.const -2.0)) (i64.const -2)) +(assert_return (invoke "i64.trunc_sat_f32_s" (f32.const 4294967296)) (i64.const 4294967296)) ;; 0x1.00000p+32 -> 1 0000 0000 +(assert_return (invoke "i64.trunc_sat_f32_s" (f32.const -4294967296)) (i64.const -4294967296)) ;; -0x1.00000p+32 -> ffff ffff 0000 0000 +(assert_return (invoke "i64.trunc_sat_f32_s" (f32.const 9223371487098961920.0)) (i64.const 9223371487098961920)) +(assert_return (invoke "i64.trunc_sat_f32_s" (f32.const -9223372036854775808.0)) (i64.const -9223372036854775808)) +(assert_return (invoke "i64.trunc_sat_f32_s" (f32.const 9223372036854775808.0)) (i64.const 0x7fffffffffffffff)) +(assert_return (invoke "i64.trunc_sat_f32_s" (f32.const -9223373136366403584.0)) (i64.const 0x8000000000000000)) +(assert_return (invoke "i64.trunc_sat_f32_s" (f32.const inf)) (i64.const 0x7fffffffffffffff)) +(assert_return (invoke "i64.trunc_sat_f32_s" (f32.const -inf)) (i64.const 0x8000000000000000)) +(assert_return (invoke "i64.trunc_sat_f32_s" (f32.const nan)) (i64.const 0)) +(assert_return (invoke "i64.trunc_sat_f32_s" (f32.const nan:0x200000)) (i64.const 0)) +(assert_return (invoke "i64.trunc_sat_f32_s" (f32.const -nan)) (i64.const 0)) +(assert_return (invoke "i64.trunc_sat_f32_s" (f32.const -nan:0x200000)) (i64.const 0)) + +(assert_return (invoke "i64.trunc_sat_f32_u" (f32.const 0.0)) (i64.const 0)) +(assert_return (invoke "i64.trunc_sat_f32_u" (f32.const -0.0)) (i64.const 0)) +(assert_return (invoke "i64.trunc_sat_f32_u" (f32.const 0x1p-149)) (i64.const 0)) +(assert_return (invoke "i64.trunc_sat_f32_u" (f32.const -0x1p-149)) (i64.const 0)) +(assert_return (invoke "i64.trunc_sat_f32_u" (f32.const 1.0)) (i64.const 1)) +(assert_return (invoke "i64.trunc_sat_f32_u" (f32.const 0x1.19999ap+0)) (i64.const 1)) +(assert_return (invoke "i64.trunc_sat_f32_u" (f32.const 1.5)) (i64.const 1)) +(assert_return (invoke "i64.trunc_sat_f32_u" (f32.const 4294967296)) (i64.const 4294967296)) +(assert_return (invoke "i64.trunc_sat_f32_u" (f32.const 18446742974197923840.0)) (i64.const -1099511627776)) +(assert_return (invoke "i64.trunc_sat_f32_u" (f32.const -0x1.ccccccp-1)) (i64.const 0)) +(assert_return (invoke "i64.trunc_sat_f32_u" (f32.const -0x1.fffffep-1)) (i64.const 0)) +(assert_return (invoke "i64.trunc_sat_f32_u" (f32.const 18446744073709551616.0)) (i64.const 0xffffffffffffffff)) +(assert_return (invoke "i64.trunc_sat_f32_u" (f32.const -1.0)) (i64.const 0x0000000000000000)) +(assert_return (invoke "i64.trunc_sat_f32_u" (f32.const inf)) (i64.const 0xffffffffffffffff)) +(assert_return (invoke "i64.trunc_sat_f32_u" (f32.const -inf)) (i64.const 0x0000000000000000)) +(assert_return (invoke "i64.trunc_sat_f32_u" (f32.const nan)) (i64.const 0)) +(assert_return (invoke "i64.trunc_sat_f32_u" (f32.const nan:0x200000)) (i64.const 0)) +(assert_return (invoke "i64.trunc_sat_f32_u" (f32.const -nan)) (i64.const 0)) +(assert_return (invoke "i64.trunc_sat_f32_u" (f32.const -nan:0x200000)) (i64.const 0)) + +(assert_return (invoke "i64.trunc_sat_f64_s" (f64.const 0.0)) (i64.const 0)) +(assert_return (invoke "i64.trunc_sat_f64_s" (f64.const -0.0)) (i64.const 0)) +(assert_return (invoke "i64.trunc_sat_f64_s" (f64.const 0x0.0000000000001p-1022)) (i64.const 0)) +(assert_return (invoke "i64.trunc_sat_f64_s" (f64.const -0x0.0000000000001p-1022)) (i64.const 0)) +(assert_return (invoke "i64.trunc_sat_f64_s" (f64.const 1.0)) (i64.const 1)) +(assert_return (invoke "i64.trunc_sat_f64_s" (f64.const 0x1.199999999999ap+0)) (i64.const 1)) +(assert_return (invoke "i64.trunc_sat_f64_s" (f64.const 1.5)) (i64.const 1)) +(assert_return (invoke "i64.trunc_sat_f64_s" (f64.const -1.0)) (i64.const -1)) +(assert_return (invoke "i64.trunc_sat_f64_s" (f64.const -0x1.199999999999ap+0)) (i64.const -1)) +(assert_return (invoke "i64.trunc_sat_f64_s" (f64.const -1.5)) (i64.const -1)) +(assert_return (invoke "i64.trunc_sat_f64_s" (f64.const -1.9)) (i64.const -1)) +(assert_return (invoke "i64.trunc_sat_f64_s" (f64.const -2.0)) (i64.const -2)) +(assert_return (invoke "i64.trunc_sat_f64_s" (f64.const 4294967296)) (i64.const 4294967296)) ;; 0x1.00000p+32 -> 1 0000 0000 +(assert_return (invoke "i64.trunc_sat_f64_s" (f64.const -4294967296)) (i64.const -4294967296)) ;; -0x1.00000p+32 -> ffff ffff 0000 0000 +(assert_return (invoke "i64.trunc_sat_f64_s" (f64.const 9223372036854774784.0)) (i64.const 9223372036854774784)) +(assert_return (invoke "i64.trunc_sat_f64_s" (f64.const -9223372036854775808.0)) (i64.const -9223372036854775808)) +(assert_return (invoke "i64.trunc_sat_f64_s" (f64.const 9223372036854775808.0)) (i64.const 0x7fffffffffffffff)) +(assert_return (invoke "i64.trunc_sat_f64_s" (f64.const -9223372036854777856.0)) (i64.const 0x8000000000000000)) +(assert_return (invoke "i64.trunc_sat_f64_s" (f64.const inf)) (i64.const 0x7fffffffffffffff)) +(assert_return (invoke "i64.trunc_sat_f64_s" (f64.const -inf)) (i64.const 0x8000000000000000)) +(assert_return (invoke "i64.trunc_sat_f64_s" (f64.const nan)) (i64.const 0)) +(assert_return (invoke "i64.trunc_sat_f64_s" (f64.const nan:0x4000000000000)) (i64.const 0)) +(assert_return (invoke "i64.trunc_sat_f64_s" (f64.const -nan)) (i64.const 0)) +(assert_return (invoke "i64.trunc_sat_f64_s" (f64.const -nan:0x4000000000000)) (i64.const 0)) + +(assert_return (invoke "i64.trunc_sat_f64_u" (f64.const 0.0)) (i64.const 0)) +(assert_return (invoke "i64.trunc_sat_f64_u" (f64.const -0.0)) (i64.const 0)) +(assert_return (invoke "i64.trunc_sat_f64_u" (f64.const 0x0.0000000000001p-1022)) (i64.const 0)) +(assert_return (invoke "i64.trunc_sat_f64_u" (f64.const -0x0.0000000000001p-1022)) (i64.const 0)) +(assert_return (invoke "i64.trunc_sat_f64_u" (f64.const 1.0)) (i64.const 1)) +(assert_return (invoke "i64.trunc_sat_f64_u" (f64.const 0x1.199999999999ap+0)) (i64.const 1)) +(assert_return (invoke "i64.trunc_sat_f64_u" (f64.const 1.5)) (i64.const 1)) +(assert_return (invoke "i64.trunc_sat_f64_u" (f64.const 4294967295)) (i64.const 0xffffffff)) +(assert_return (invoke "i64.trunc_sat_f64_u" (f64.const 4294967296)) (i64.const 0x100000000)) +(assert_return (invoke "i64.trunc_sat_f64_u" (f64.const 18446744073709549568.0)) (i64.const -2048)) +(assert_return (invoke "i64.trunc_sat_f64_u" (f64.const -0x1.ccccccccccccdp-1)) (i64.const 0)) +(assert_return (invoke "i64.trunc_sat_f64_u" (f64.const -0x1.fffffffffffffp-1)) (i64.const 0)) +(assert_return (invoke "i64.trunc_sat_f64_u" (f64.const 1e8)) (i64.const 100000000)) +(assert_return (invoke "i64.trunc_sat_f64_u" (f64.const 1e16)) (i64.const 10000000000000000)) +(assert_return (invoke "i64.trunc_sat_f64_u" (f64.const 9223372036854775808)) (i64.const -9223372036854775808)) +(assert_return (invoke "i64.trunc_sat_f64_u" (f64.const 18446744073709551616.0)) (i64.const 0xffffffffffffffff)) +(assert_return (invoke "i64.trunc_sat_f64_u" (f64.const -1.0)) (i64.const 0x0000000000000000)) +(assert_return (invoke "i64.trunc_sat_f64_u" (f64.const inf)) (i64.const 0xffffffffffffffff)) +(assert_return (invoke "i64.trunc_sat_f64_u" (f64.const -inf)) (i64.const 0x0000000000000000)) +(assert_return (invoke "i64.trunc_sat_f64_u" (f64.const nan)) (i64.const 0)) +(assert_return (invoke "i64.trunc_sat_f64_u" (f64.const nan:0x4000000000000)) (i64.const 0)) +(assert_return (invoke "i64.trunc_sat_f64_u" (f64.const -nan)) (i64.const 0)) +(assert_return (invoke "i64.trunc_sat_f64_u" (f64.const -nan:0x4000000000000)) (i64.const 0)) + ;; Test rounding directions. (assert_return (invoke "f32.convert_i32_s" (i32.const 16777217)) (f32.const 16777216.0)) (assert_return (invoke "f32.convert_i32_s" (i32.const -16777217)) (f32.const -16777216.0)) diff --git a/test/core/fac.wast b/test/core/fac.wast index ef10991a82..0e61c1f9ee 100644 --- a/test/core/fac.wast +++ b/test/core/fac.wast @@ -79,6 +79,24 @@ ) (local.get 1) ) + + ;; Iterative factorial without locals. + (func $pick0 (param i64) (result i64 i64) + (local.get 0) (local.get 0) + ) + (func $pick1 (param i64 i64) (result i64 i64 i64) + (local.get 0) (local.get 1) (local.get 0) + ) + (func (export "fac-ssa") (param i64) (result i64) + (i64.const 1) (local.get 0) + (loop $l (param i64 i64) (result i64) + (call $pick1) (call $pick1) (i64.mul) + (call $pick1) (i64.const 1) (i64.sub) + (call $pick0) (i64.const 0) (i64.gt_u) + (br_if $l) + (drop) (return) + ) + ) ) (assert_return (invoke "fac-rec" (i64.const 25)) (i64.const 7034535277573963776)) @@ -86,4 +104,6 @@ (assert_return (invoke "fac-rec-named" (i64.const 25)) (i64.const 7034535277573963776)) (assert_return (invoke "fac-iter-named" (i64.const 25)) (i64.const 7034535277573963776)) (assert_return (invoke "fac-opt" (i64.const 25)) (i64.const 7034535277573963776)) +(assert_return (invoke "fac-ssa" (i64.const 25)) (i64.const 7034535277573963776)) + (assert_exhaustion (invoke "fac-rec" (i64.const 1073741824)) "call stack exhausted") diff --git a/test/core/func.wast b/test/core/func.wast index 263440a271..af81d982c7 100644 --- a/test/core/func.wast +++ b/test/core/func.wast @@ -28,7 +28,12 @@ (func (param i32) (param f64)) (func (param i32 f32) (param $x i64) (param) (param i32 f64)) + (func (result)) + (func (result) (result)) (func (result i32) (unreachable)) + (func (result i32 f64 f32) (unreachable)) + (func (result i32) (result f64) (unreachable)) + (func (result i32 f32) (result i64) (result) (result i32 f64) (unreachable)) (type $sig-1 (func)) (type $sig-2 (func (result i32))) @@ -50,7 +55,7 @@ (func $complex (param i32 f32) (param $x i64) (param) (param i32) - (result) (result i32) (result) + (result) (result i32) (result) (result i64 i32) (local f32) (local $y i32) (local i64 i32) (local) (local f64 i32) (unreachable) (unreachable) ) @@ -104,7 +109,7 @@ (local.get 4) ) - ;; Typing of result + ;; Typing of results (func (export "empty")) (func (export "value-void") (call $dummy)) @@ -112,28 +117,53 @@ (func (export "value-i64") (result i64) (i64.const 7777)) (func (export "value-f32") (result f32) (f32.const 77.7)) (func (export "value-f64") (result f64) (f64.const 77.77)) + (func (export "value-i32-f64") (result i32 f64) (i32.const 77) (f64.const 7)) + (func (export "value-i32-i32-i32") (result i32 i32 i32) + (i32.const 1) (i32.const 2) (i32.const 3) + ) (func (export "value-block-void") (block (call $dummy) (call $dummy))) (func (export "value-block-i32") (result i32) (block (result i32) (call $dummy) (i32.const 77)) ) + (func (export "value-block-i32-i64") (result i32 i64) + (block (result i32 i64) (call $dummy) (i32.const 1) (i64.const 2)) + ) (func (export "return-empty") (return)) (func (export "return-i32") (result i32) (return (i32.const 78))) (func (export "return-i64") (result i64) (return (i64.const 7878))) (func (export "return-f32") (result f32) (return (f32.const 78.7))) (func (export "return-f64") (result f64) (return (f64.const 78.78))) + (func (export "return-i32-f64") (result i32 f64) + (return (i32.const 78) (f64.const 78.78)) + ) + (func (export "return-i32-i32-i32") (result i32 i32 i32) + (return (i32.const 1) (i32.const 2) (i32.const 3)) + ) (func (export "return-block-i32") (result i32) (return (block (result i32) (call $dummy) (i32.const 77))) ) + (func (export "return-block-i32-i64") (result i32 i64) + (return (block (result i32 i64) (call $dummy) (i32.const 1) (i64.const 2))) + ) (func (export "break-empty") (br 0)) (func (export "break-i32") (result i32) (br 0 (i32.const 79))) (func (export "break-i64") (result i64) (br 0 (i64.const 7979))) (func (export "break-f32") (result f32) (br 0 (f32.const 79.9))) (func (export "break-f64") (result f64) (br 0 (f64.const 79.79))) + (func (export "break-i32-f64") (result i32 f64) + (br 0 (i32.const 79) (f64.const 79.79)) + ) + (func (export "break-i32-i32-i32") (result i32 i32 i32) + (br 0 (i32.const 1) (i32.const 2) (i32.const 3)) + ) (func (export "break-block-i32") (result i32) (br 0 (block (result i32) (call $dummy) (i32.const 77))) ) + (func (export "break-block-i32-i64") (result i32 i64) + (br 0 (block (result i32 i64) (call $dummy) (i32.const 1) (i64.const 2))) + ) (func (export "break-br_if-empty") (param i32) (br_if 0 (local.get 0)) @@ -141,6 +171,10 @@ (func (export "break-br_if-num") (param i32) (result i32) (drop (br_if 0 (i32.const 50) (local.get 0))) (i32.const 51) ) + (func (export "break-br_if-num-num") (param i32) (result i32 i64) + (drop (drop (br_if 0 (i32.const 50) (i64.const 51) (local.get 0)))) + (i32.const 51) (i64.const 52) + ) (func (export "break-br_table-empty") (param i32) (br_table 0 0 0 (local.get 0)) @@ -148,6 +182,10 @@ (func (export "break-br_table-num") (param i32) (result i32) (br_table 0 0 (i32.const 50) (local.get 0)) (i32.const 51) ) + (func (export "break-br_table-num-num") (param i32) (result i32 i64) + (br_table 0 0 (i32.const 50) (i64.const 51) (local.get 0)) + (i32.const 51) (i64.const 52) + ) (func (export "break-br_table-nested-empty") (param i32) (block (br_table 0 1 0 (local.get 0))) ) @@ -159,6 +197,38 @@ (i32.const 2) ) ) + (func (export "break-br_table-nested-num-num") (param i32) (result i32 i32) + (i32.add + (block (result i32 i32) + (br_table 0 1 0 (i32.const 50) (i32.const 51) (local.get 0)) + (i32.const 51) (i32.const -3) + ) + ) + (i32.const 52) + ) + + ;; Large signatures + + (func (export "large-sig") + (param i32 i64 f32 f32 i32 f64 f32 i32 i32 i32 f32 f64 f64 f64 i32 i32 f32) + (result f64 f32 i32 i32 i32 i64 f32 i32 i32 f32 f64 f64 i32 f32 i32 f64) + (local.get 5) + (local.get 2) + (local.get 0) + (local.get 8) + (local.get 7) + (local.get 1) + (local.get 3) + (local.get 9) + (local.get 4) + (local.get 6) + (local.get 13) + (local.get 11) + (local.get 15) + (local.get 16) + (local.get 14) + (local.get 12) + ) ;; Default initialization of locals @@ -231,27 +301,48 @@ (assert_return (invoke "value-i64") (i64.const 7777)) (assert_return (invoke "value-f32") (f32.const 77.7)) (assert_return (invoke "value-f64") (f64.const 77.77)) +(assert_return (invoke "value-i32-f64") (i32.const 77) (f64.const 7)) +(assert_return (invoke "value-i32-i32-i32") + (i32.const 1) (i32.const 2) (i32.const 3) +) (assert_return (invoke "value-block-void")) (assert_return (invoke "value-block-i32") (i32.const 77)) +(assert_return (invoke "value-block-i32-i64") (i32.const 1) (i64.const 2)) (assert_return (invoke "return-empty")) (assert_return (invoke "return-i32") (i32.const 78)) (assert_return (invoke "return-i64") (i64.const 7878)) (assert_return (invoke "return-f32") (f32.const 78.7)) (assert_return (invoke "return-f64") (f64.const 78.78)) +(assert_return (invoke "return-i32-f64") (i32.const 78) (f64.const 78.78)) +(assert_return (invoke "return-i32-i32-i32") + (i32.const 1) (i32.const 2) (i32.const 3) +) (assert_return (invoke "return-block-i32") (i32.const 77)) +(assert_return (invoke "return-block-i32-i64") (i32.const 1) (i64.const 2)) (assert_return (invoke "break-empty")) (assert_return (invoke "break-i32") (i32.const 79)) (assert_return (invoke "break-i64") (i64.const 7979)) (assert_return (invoke "break-f32") (f32.const 79.9)) (assert_return (invoke "break-f64") (f64.const 79.79)) +(assert_return (invoke "break-i32-f64") (i32.const 79) (f64.const 79.79)) +(assert_return (invoke "break-i32-i32-i32") + (i32.const 1) (i32.const 2) (i32.const 3) +) (assert_return (invoke "break-block-i32") (i32.const 77)) +(assert_return (invoke "break-block-i32-i64") (i32.const 1) (i64.const 2)) (assert_return (invoke "break-br_if-empty" (i32.const 0))) (assert_return (invoke "break-br_if-empty" (i32.const 2))) (assert_return (invoke "break-br_if-num" (i32.const 0)) (i32.const 51)) (assert_return (invoke "break-br_if-num" (i32.const 1)) (i32.const 50)) +(assert_return (invoke "break-br_if-num-num" (i32.const 0)) + (i32.const 51) (i64.const 52) +) +(assert_return (invoke "break-br_if-num-num" (i32.const 1)) + (i32.const 50) (i64.const 51) +) (assert_return (invoke "break-br_table-empty" (i32.const 0))) (assert_return (invoke "break-br_table-empty" (i32.const 1))) @@ -261,6 +352,18 @@ (assert_return (invoke "break-br_table-num" (i32.const 1)) (i32.const 50)) (assert_return (invoke "break-br_table-num" (i32.const 10)) (i32.const 50)) (assert_return (invoke "break-br_table-num" (i32.const -100)) (i32.const 50)) +(assert_return (invoke "break-br_table-num-num" (i32.const 0)) + (i32.const 50) (i64.const 51) +) +(assert_return (invoke "break-br_table-num-num" (i32.const 1)) + (i32.const 50) (i64.const 51) +) +(assert_return (invoke "break-br_table-num-num" (i32.const 10)) + (i32.const 50) (i64.const 51) +) +(assert_return (invoke "break-br_table-num-num" (i32.const -100)) + (i32.const 50) (i64.const 51) +) (assert_return (invoke "break-br_table-nested-empty" (i32.const 0))) (assert_return (invoke "break-br_table-nested-empty" (i32.const 1))) (assert_return (invoke "break-br_table-nested-empty" (i32.const 3))) @@ -277,6 +380,36 @@ (assert_return (invoke "break-br_table-nested-num" (i32.const -3)) (i32.const 52) ) +(assert_return + (invoke "break-br_table-nested-num-num" (i32.const 0)) + (i32.const 101) (i32.const 52) +) +(assert_return + (invoke "break-br_table-nested-num-num" (i32.const 1)) + (i32.const 50) (i32.const 51) +) +(assert_return + (invoke "break-br_table-nested-num-num" (i32.const 2)) + (i32.const 101) (i32.const 52) +) +(assert_return + (invoke "break-br_table-nested-num-num" (i32.const -3)) + (i32.const 101) (i32.const 52) +) + +(assert_return + (invoke "large-sig" + (i32.const 0) (i64.const 1) (f32.const 2) (f32.const 3) + (i32.const 4) (f64.const 5) (f32.const 6) (i32.const 7) + (i32.const 8) (i32.const 9) (f32.const 10) (f64.const 11) + (f64.const 12) (f64.const 13) (i32.const 14) (i32.const 15) + (f32.const 16) + ) + (f64.const 5) (f32.const 2) (i32.const 0) (i32.const 8) + (i32.const 7) (i64.const 1) (f32.const 3) (i32.const 9) + (i32.const 4) (f32.const 6) (f64.const 13) (f64.const 11) + (i32.const 15) (f32.const 16) (i32.const 14) (f64.const 12) +) (assert_return (invoke "init-local-i32") (i32.const 0)) (assert_return (invoke "init-local-i64") (i64.const 0)) @@ -489,19 +622,6 @@ ;; Invalid typing of result -(assert_invalid - (module (func $type-multiple-result (result i32 i32) (unreachable))) - "invalid result arity" -) -(assert_invalid - (module - (type (func (result i32 i32))) - (func $type-multiple-result (type 0) (unreachable)) - ) - "invalid result arity" -) - - (assert_invalid (module (func $type-empty-i32 (result i32))) "type mismatch" @@ -518,6 +638,10 @@ (module (func $type-empty-f64 (result f64))) "type mismatch" ) +(assert_invalid + (module (func $type-empty-f64-i32 (result f64 i32))) + "type mismatch" +) (assert_invalid (module (func $type-value-void-vs-num (result i32) @@ -525,18 +649,42 @@ )) "type mismatch" ) +(assert_invalid + (module (func $type-value-void-vs-nums (result i32 i32) + (nop) + )) + "type mismatch" +) (assert_invalid (module (func $type-value-num-vs-void (i32.const 0) )) "type mismatch" ) +(assert_invalid + (module (func $type-value-nums-vs-void + (i32.const 0) (i64.const 0) + )) + "type mismatch" +) (assert_invalid (module (func $type-value-num-vs-num (result i32) (f32.const 0) )) "type mismatch" ) +(assert_invalid + (module (func $type-value-num-vs-nums (result f32 f32) + (f32.const 0) + )) + "type mismatch" +) +(assert_invalid + (module (func $type-value-nums-vs-num (result f32) + (f32.const 0) (f32.const 0) + )) + "type mismatch" +) (assert_invalid (module (func $type-return-last-empty-vs-num (result i32) @@ -544,18 +692,36 @@ )) "type mismatch" ) +(assert_invalid + (module (func $type-return-last-empty-vs-nums (result i32 i32) + (return) + )) + "type mismatch" +) (assert_invalid (module (func $type-return-last-void-vs-num (result i32) (return (nop)) )) "type mismatch" ) +(assert_invalid + (module (func $type-return-last-void-vs-nums (result i32 i64) + (return (nop)) + )) + "type mismatch" +) (assert_invalid (module (func $type-return-last-num-vs-num (result i32) (return (i64.const 0)) )) "type mismatch" ) +(assert_invalid + (module (func $type-return-last-num-vs-nums (result i64 i64) + (return (i64.const 0)) + )) + "type mismatch" +) (assert_invalid (module (func $type-return-empty-vs-num (result i32) @@ -563,24 +729,54 @@ )) "type mismatch" ) +(assert_invalid + (module (func $type-return-empty-vs-nums (result i32 i32) + (return) (i32.const 1) (i32.const 2) + )) + "type mismatch" +) +(assert_invalid + (module (func $type-return-partial-vs-nums (result i32 i32) + (i32.const 1) (return) (i32.const 2) + )) + "type mismatch" +) (assert_invalid (module (func $type-return-void-vs-num (result i32) (return (nop)) (i32.const 1) )) "type mismatch" ) +(assert_invalid + (module (func $type-return-void-vs-nums (result i32 i32) + (return (nop)) (i32.const 1) + )) + "type mismatch" +) (assert_invalid (module (func $type-return-num-vs-num (result i32) (return (i64.const 1)) (i32.const 1) )) "type mismatch" ) +(assert_invalid + (module (func $type-return-num-vs-nums (result i32 i32) + (return (i64.const 1)) (i32.const 1) (i32.const 2) + )) + "type mismatch" +) (assert_invalid (module (func $type-return-first-num-vs-num (result i32) (return (i64.const 1)) (return (i32.const 1)) )) "type mismatch" ) +(assert_invalid + (module (func $type-return-first-num-vs-nums (result i32 i32) + (return (i32.const 1)) (return (i32.const 1) (i32.const 2)) + )) + "type mismatch" +) (assert_invalid (module (func $type-break-last-void-vs-num (result i32) @@ -588,24 +784,48 @@ )) "type mismatch" ) +(assert_invalid + (module (func $type-break-last-void-vs-nums (result i32 i32) + (br 0) + )) + "type mismatch" +) (assert_invalid (module (func $type-break-last-num-vs-num (result i32) (br 0 (f32.const 0)) )) "type mismatch" ) +(assert_invalid + (module (func $type-break-last-num-vs-nums (result i32 i32) + (br 0 (i32.const 0)) + )) + "type mismatch" +) (assert_invalid (module (func $type-break-void-vs-num (result i32) (br 0) (i32.const 1) )) "type mismatch" ) +(assert_invalid + (module (func $type-break-void-vs-nums (result i32 i32) + (br 0) (i32.const 1) (i32.const 2) + )) + "type mismatch" +) (assert_invalid (module (func $type-break-num-vs-num (result i32) (br 0 (i64.const 1)) (i32.const 1) )) "type mismatch" ) +(assert_invalid + (module (func $type-break-num-vs-nums (result i32 i32) + (br 0 (i32.const 1)) (i32.const 1) (i32.const 2) + )) + "type mismatch" +) (assert_invalid (module (func $type-break-first-num-vs-num (result i32) (br 0 (i64.const 1)) (br 0 (i32.const 1)) @@ -619,18 +839,36 @@ )) "type mismatch" ) +(assert_invalid + (module (func $type-break-nested-empty-vs-nums (result i32 i32) + (block (br 1)) (br 0 (i32.const 1) (i32.const 2)) + )) + "type mismatch" +) (assert_invalid (module (func $type-break-nested-void-vs-num (result i32) (block (br 1 (nop))) (br 0 (i32.const 1)) )) "type mismatch" ) +(assert_invalid + (module (func $type-break-nested-void-vs-nums (result i32 i32) + (block (br 1 (nop))) (br 0 (i32.const 1) (i32.const 2)) + )) + "type mismatch" +) (assert_invalid (module (func $type-break-nested-num-vs-num (result i32) (block (br 1 (i64.const 1))) (br 0 (i32.const 1)) )) "type mismatch" ) +(assert_invalid + (module (func $type-break-nested-num-vs-nums (result i32 i32) + (block (result i32) (br 1 (i32.const 1))) (br 0 (i32.const 1) (i32.const 2)) + )) + "type mismatch" +) ;; Syntax errors diff --git a/test/core/i32.wast b/test/core/i32.wast index 58c853a6ba..32862c3475 100644 --- a/test/core/i32.wast +++ b/test/core/i32.wast @@ -19,6 +19,8 @@ (func (export "clz") (param $x i32) (result i32) (i32.clz (local.get $x))) (func (export "ctz") (param $x i32) (result i32) (i32.ctz (local.get $x))) (func (export "popcnt") (param $x i32) (result i32) (i32.popcnt (local.get $x))) + (func (export "extend8_s") (param $x i32) (result i32) (i32.extend8_s (local.get $x))) + (func (export "extend16_s") (param $x i32) (result i32) (i32.extend16_s (local.get $x))) (func (export "eqz") (param $x i32) (result i32) (i32.eqz (local.get $x))) (func (export "eq") (param $x i32) (param $y i32) (result i32) (i32.eq (local.get $x) (local.get $y))) (func (export "ne") (param $x i32) (param $y i32) (result i32) (i32.ne (local.get $x) (local.get $y))) @@ -265,6 +267,22 @@ (assert_return (invoke "popcnt" (i32.const 0x55555555)) (i32.const 16)) (assert_return (invoke "popcnt" (i32.const 0xDEADBEEF)) (i32.const 24)) +(assert_return (invoke "extend8_s" (i32.const 0)) (i32.const 0)) +(assert_return (invoke "extend8_s" (i32.const 0x7f)) (i32.const 127)) +(assert_return (invoke "extend8_s" (i32.const 0x80)) (i32.const -128)) +(assert_return (invoke "extend8_s" (i32.const 0xff)) (i32.const -1)) +(assert_return (invoke "extend8_s" (i32.const 0x012345_00)) (i32.const 0)) +(assert_return (invoke "extend8_s" (i32.const 0xfedcba_80)) (i32.const -0x80)) +(assert_return (invoke "extend8_s" (i32.const -1)) (i32.const -1)) + +(assert_return (invoke "extend16_s" (i32.const 0)) (i32.const 0)) +(assert_return (invoke "extend16_s" (i32.const 0x7fff)) (i32.const 32767)) +(assert_return (invoke "extend16_s" (i32.const 0x8000)) (i32.const -32768)) +(assert_return (invoke "extend16_s" (i32.const 0xffff)) (i32.const -1)) +(assert_return (invoke "extend16_s" (i32.const 0x0123_0000)) (i32.const 0)) +(assert_return (invoke "extend16_s" (i32.const 0xfedc_8000)) (i32.const -0x8000)) +(assert_return (invoke "extend16_s" (i32.const -1)) (i32.const -1)) + (assert_return (invoke "eqz" (i32.const 0)) (i32.const 1)) (assert_return (invoke "eqz" (i32.const 1)) (i32.const 0)) (assert_return (invoke "eqz" (i32.const 0x80000000)) (i32.const 0)) diff --git a/test/core/i64.wast b/test/core/i64.wast index 5a8c1d6625..baeed0ce1b 100644 --- a/test/core/i64.wast +++ b/test/core/i64.wast @@ -19,6 +19,9 @@ (func (export "clz") (param $x i64) (result i64) (i64.clz (local.get $x))) (func (export "ctz") (param $x i64) (result i64) (i64.ctz (local.get $x))) (func (export "popcnt") (param $x i64) (result i64) (i64.popcnt (local.get $x))) + (func (export "extend8_s") (param $x i64) (result i64) (i64.extend8_s (local.get $x))) + (func (export "extend16_s") (param $x i64) (result i64) (i64.extend16_s (local.get $x))) + (func (export "extend32_s") (param $x i64) (result i64) (i64.extend32_s (local.get $x))) (func (export "eqz") (param $x i64) (result i32) (i64.eqz (local.get $x))) (func (export "eq") (param $x i64) (param $y i64) (result i32) (i64.eq (local.get $x) (local.get $y))) (func (export "ne") (param $x i64) (param $y i64) (result i32) (i64.ne (local.get $x) (local.get $y))) @@ -265,6 +268,33 @@ (assert_return (invoke "popcnt" (i64.const 0x99999999AAAAAAAA)) (i64.const 32)) (assert_return (invoke "popcnt" (i64.const 0xDEADBEEFDEADBEEF)) (i64.const 48)) +(assert_return (invoke "extend8_s" (i64.const 0)) (i64.const 0)) +(assert_return (invoke "extend8_s" (i64.const 0x7f)) (i64.const 127)) +(assert_return (invoke "extend8_s" (i64.const 0x80)) (i64.const -128)) +(assert_return (invoke "extend8_s" (i64.const 0xff)) (i64.const -1)) +(assert_return (invoke "extend8_s" (i64.const 0x01234567_89abcd_00)) (i64.const 0)) +(assert_return (invoke "extend8_s" (i64.const 0xfedcba98_765432_80)) (i64.const -0x80)) +(assert_return (invoke "extend8_s" (i64.const -1)) (i64.const -1)) + +(assert_return (invoke "extend16_s" (i64.const 0)) (i64.const 0)) +(assert_return (invoke "extend16_s" (i64.const 0x7fff)) (i64.const 32767)) +(assert_return (invoke "extend16_s" (i64.const 0x8000)) (i64.const -32768)) +(assert_return (invoke "extend16_s" (i64.const 0xffff)) (i64.const -1)) +(assert_return (invoke "extend16_s" (i64.const 0x12345678_9abc_0000)) (i64.const 0)) +(assert_return (invoke "extend16_s" (i64.const 0xfedcba98_7654_8000)) (i64.const -0x8000)) +(assert_return (invoke "extend16_s" (i64.const -1)) (i64.const -1)) + +(assert_return (invoke "extend32_s" (i64.const 0)) (i64.const 0)) +(assert_return (invoke "extend32_s" (i64.const 0x7fff)) (i64.const 32767)) +(assert_return (invoke "extend32_s" (i64.const 0x8000)) (i64.const 32768)) +(assert_return (invoke "extend32_s" (i64.const 0xffff)) (i64.const 65535)) +(assert_return (invoke "extend32_s" (i64.const 0x7fffffff)) (i64.const 0x7fffffff)) +(assert_return (invoke "extend32_s" (i64.const 0x80000000)) (i64.const -0x80000000)) +(assert_return (invoke "extend32_s" (i64.const 0xffffffff)) (i64.const -1)) +(assert_return (invoke "extend32_s" (i64.const 0x01234567_00000000)) (i64.const 0)) +(assert_return (invoke "extend32_s" (i64.const 0xfedcba98_80000000)) (i64.const -0x80000000)) +(assert_return (invoke "extend32_s" (i64.const -1)) (i64.const -1)) + (assert_return (invoke "eqz" (i64.const 0)) (i32.const 1)) (assert_return (invoke "eqz" (i64.const 1)) (i32.const 0)) (assert_return (invoke "eqz" (i64.const 0x8000000000000000)) (i32.const 0)) diff --git a/test/core/if.wast b/test/core/if.wast index ae7f7b3859..1cbb617a7f 100644 --- a/test/core/if.wast +++ b/test/core/if.wast @@ -19,13 +19,26 @@ (if (result i32) (local.get 0) (then (i32.const 7)) (else (i32.const 8))) ) - (func (export "multi") (param i32) (result i32) + (func (export "multi") (param i32) (result i32 i32) (if (local.get 0) (then (call $dummy) (call $dummy) (call $dummy))) (if (local.get 0) (then) (else (call $dummy) (call $dummy) (call $dummy))) (if (result i32) (local.get 0) - (then (call $dummy) (call $dummy) (i32.const 8)) - (else (call $dummy) (call $dummy) (i32.const 9)) + (then (call $dummy) (call $dummy) (i32.const 8) (call $dummy)) + (else (call $dummy) (call $dummy) (i32.const 9) (call $dummy)) ) + (if (result i32 i64 i32) (local.get 0) + (then + (call $dummy) (call $dummy) (i32.const 1) (call $dummy) + (call $dummy) (call $dummy) (i64.const 2) (call $dummy) + (call $dummy) (call $dummy) (i32.const 3) (call $dummy) + ) + (else + (call $dummy) (call $dummy) (i32.const -1) (call $dummy) + (call $dummy) (call $dummy) (i64.const -2) (call $dummy) + (call $dummy) (call $dummy) (i32.const -3) (call $dummy) + ) + ) + (drop) (drop) ) (func (export "nested") (param i32 i32) (result i32) @@ -337,6 +350,31 @@ ) ) ) + (func (export "as-binary-operands") (param i32) (result i32) + (i32.mul + (if (result i32 i32) (local.get 0) + (then (call $dummy) (i32.const 3) (call $dummy) (i32.const 4)) + (else (call $dummy) (i32.const 3) (call $dummy) (i32.const -4)) + ) + ) + ) + (func (export "as-compare-operands") (param i32) (result i32) + (f32.gt + (if (result f32 f32) (local.get 0) + (then (call $dummy) (f32.const 3) (call $dummy) (f32.const 3)) + (else (call $dummy) (f32.const -2) (call $dummy) (f32.const -3)) + ) + ) + ) + (func (export "as-mixed-operands") (param i32) (result i32) + (if (result i32 i32) (local.get 0) + (then (call $dummy) (i32.const 3) (call $dummy) (i32.const 4)) + (else (call $dummy) (i32.const -3) (call $dummy) (i32.const -4)) + ) + (i32.const 5) + (i32.add) + (i32.mul) + ) (func (export "break-bare") (result i32) (if (i32.const 1) (then (br 0) (unreachable))) @@ -357,6 +395,61 @@ (else (br 0 (i32.const 21)) (i32.const 20)) ) ) + (func (export "break-multi-value") (param i32) (result i32 i32 i64) + (if (result i32 i32 i64) (local.get 0) + (then + (br 0 (i32.const 18) (i32.const -18) (i64.const 18)) + (i32.const 19) (i32.const -19) (i64.const 19) + ) + (else + (br 0 (i32.const -18) (i32.const 18) (i64.const -18)) + (i32.const -19) (i32.const 19) (i64.const -19) + ) + ) + ) + + (func (export "param") (param i32) (result i32) + (i32.const 1) + (if (param i32) (result i32) (local.get 0) + (then (i32.const 2) (i32.add)) + (else (i32.const -2) (i32.add)) + ) + ) + (func (export "params") (param i32) (result i32) + (i32.const 1) + (i32.const 2) + (if (param i32 i32) (result i32) (local.get 0) + (then (i32.add)) + (else (i32.sub)) + ) + ) + (func (export "params-id") (param i32) (result i32) + (i32.const 1) + (i32.const 2) + (if (param i32 i32) (result i32 i32) (local.get 0) (then)) + (i32.add) + ) + (func (export "param-break") (param i32) (result i32) + (i32.const 1) + (if (param i32) (result i32) (local.get 0) + (then (i32.const 2) (i32.add) (br 0)) + (else (i32.const -2) (i32.add) (br 0)) + ) + ) + (func (export "params-break") (param i32) (result i32) + (i32.const 1) + (i32.const 2) + (if (param i32 i32) (result i32) (local.get 0) + (then (i32.add) (br 0)) + (else (i32.sub) (br 0)) + ) + ) + (func (export "params-id-break") (param i32) (result i32) + (i32.const 1) + (i32.const 2) + (if (param i32 i32) (result i32 i32) (local.get 0) (then (br 0))) + (i32.add) + ) (func (export "effects") (param i32) (result i32) (local i32) @@ -379,6 +472,58 @@ ) (local.get 1) ) + + ;; Examples + + (func $add64_u_with_carry (export "add64_u_with_carry") + (param $i i64) (param $j i64) (param $c i32) (result i64 i32) + (local $k i64) + (local.set $k + (i64.add + (i64.add (local.get $i) (local.get $j)) + (i64.extend_i32_u (local.get $c)) + ) + ) + (return (local.get $k) (i64.lt_u (local.get $k) (local.get $i))) + ) + + (func $add64_u_saturated (export "add64_u_saturated") + (param i64 i64) (result i64) + (call $add64_u_with_carry (local.get 0) (local.get 1) (i32.const 0)) + (if (param i64) (result i64) + (then (drop) (i64.const -1)) + ) + ) + + ;; Block signature syntax + + (type $block-sig-1 (func)) + (type $block-sig-2 (func (result i32))) + (type $block-sig-3 (func (param $x i32))) + (type $block-sig-4 (func (param i32 f64 i32) (result i32 f64 i32))) + + (func (export "type-use") + (if (type $block-sig-1) (i32.const 1) (then)) + (if (type $block-sig-2) (i32.const 1) + (then (i32.const 0)) (else (i32.const 2)) + ) + (if (type $block-sig-3) (i32.const 1) (then (drop)) (else (drop))) + (i32.const 0) (f64.const 0) (i32.const 0) + (if (type $block-sig-4) (i32.const 1) (then)) + (drop) (drop) (drop) + (if (type $block-sig-2) (result i32) (i32.const 1) + (then (i32.const 0)) (else (i32.const 2)) + ) + (if (type $block-sig-3) (param i32) (i32.const 1) + (then (drop)) (else (drop)) + ) + (i32.const 0) (f64.const 0) (i32.const 0) + (if (type $block-sig-4) + (param i32) (param f64 i32) (result i32 f64) (result i32) + (i32.const 1) (then) + ) + (drop) (drop) (drop) + ) ) (assert_return (invoke "empty" (i32.const 0))) @@ -391,10 +536,10 @@ (assert_return (invoke "singular" (i32.const 10)) (i32.const 7)) (assert_return (invoke "singular" (i32.const -10)) (i32.const 7)) -(assert_return (invoke "multi" (i32.const 0)) (i32.const 9)) -(assert_return (invoke "multi" (i32.const 1)) (i32.const 8)) -(assert_return (invoke "multi" (i32.const 13)) (i32.const 8)) -(assert_return (invoke "multi" (i32.const -5)) (i32.const 8)) +(assert_return (invoke "multi" (i32.const 0)) (i32.const 9) (i32.const -1)) +(assert_return (invoke "multi" (i32.const 1)) (i32.const 8) (i32.const 1)) +(assert_return (invoke "multi" (i32.const 13)) (i32.const 8) (i32.const 1)) +(assert_return (invoke "multi" (i32.const -5)) (i32.const 8) (i32.const 1)) (assert_return (invoke "nested" (i32.const 0) (i32.const 0)) (i32.const 11)) (assert_return (invoke "nested" (i32.const 1) (i32.const 0)) (i32.const 10)) @@ -488,13 +633,203 @@ (assert_return (invoke "as-compare-operand" (i32.const 1) (i32.const 0)) (i32.const 1)) (assert_return (invoke "as-compare-operand" (i32.const 1) (i32.const 1)) (i32.const 0)) +(assert_return (invoke "as-binary-operands" (i32.const 0)) (i32.const -12)) +(assert_return (invoke "as-binary-operands" (i32.const 1)) (i32.const 12)) + +(assert_return (invoke "as-compare-operands" (i32.const 0)) (i32.const 1)) +(assert_return (invoke "as-compare-operands" (i32.const 1)) (i32.const 0)) + +(assert_return (invoke "as-mixed-operands" (i32.const 0)) (i32.const -3)) +(assert_return (invoke "as-mixed-operands" (i32.const 1)) (i32.const 27)) + (assert_return (invoke "break-bare") (i32.const 19)) (assert_return (invoke "break-value" (i32.const 1)) (i32.const 18)) (assert_return (invoke "break-value" (i32.const 0)) (i32.const 21)) +(assert_return (invoke "break-multi-value" (i32.const 0)) + (i32.const -18) (i32.const 18) (i64.const -18) +) +(assert_return (invoke "break-multi-value" (i32.const 1)) + (i32.const 18) (i32.const -18) (i64.const 18) +) + +(assert_return (invoke "param" (i32.const 0)) (i32.const -1)) +(assert_return (invoke "param" (i32.const 1)) (i32.const 3)) +(assert_return (invoke "params" (i32.const 0)) (i32.const -1)) +(assert_return (invoke "params" (i32.const 1)) (i32.const 3)) +(assert_return (invoke "params-id" (i32.const 0)) (i32.const 3)) +(assert_return (invoke "params-id" (i32.const 1)) (i32.const 3)) +(assert_return (invoke "param-break" (i32.const 0)) (i32.const -1)) +(assert_return (invoke "param-break" (i32.const 1)) (i32.const 3)) +(assert_return (invoke "params-break" (i32.const 0)) (i32.const -1)) +(assert_return (invoke "params-break" (i32.const 1)) (i32.const 3)) +(assert_return (invoke "params-id-break" (i32.const 0)) (i32.const 3)) +(assert_return (invoke "params-id-break" (i32.const 1)) (i32.const 3)) (assert_return (invoke "effects" (i32.const 1)) (i32.const -14)) (assert_return (invoke "effects" (i32.const 0)) (i32.const -6)) +(assert_return + (invoke "add64_u_with_carry" (i64.const 0) (i64.const 0) (i32.const 0)) + (i64.const 0) (i32.const 0) +) +(assert_return + (invoke "add64_u_with_carry" (i64.const 100) (i64.const 124) (i32.const 0)) + (i64.const 224) (i32.const 0) +) +(assert_return + (invoke "add64_u_with_carry" (i64.const -1) (i64.const 0) (i32.const 0)) + (i64.const -1) (i32.const 0) +) +(assert_return + (invoke "add64_u_with_carry" (i64.const -1) (i64.const 1) (i32.const 0)) + (i64.const 0) (i32.const 1) +) +(assert_return + (invoke "add64_u_with_carry" (i64.const -1) (i64.const -1) (i32.const 0)) + (i64.const -2) (i32.const 1) +) +(assert_return + (invoke "add64_u_with_carry" (i64.const -1) (i64.const 0) (i32.const 1)) + (i64.const 0) (i32.const 1) +) +(assert_return + (invoke "add64_u_with_carry" (i64.const -1) (i64.const 1) (i32.const 1)) + (i64.const 1) (i32.const 1) +) +(assert_return + (invoke "add64_u_with_carry" (i64.const 0x8000000000000000) (i64.const 0x8000000000000000) (i32.const 0)) + (i64.const 0) (i32.const 1) +) + +(assert_return + (invoke "add64_u_saturated" (i64.const 0) (i64.const 0)) (i64.const 0) +) +(assert_return + (invoke "add64_u_saturated" (i64.const 1230) (i64.const 23)) (i64.const 1253) +) +(assert_return + (invoke "add64_u_saturated" (i64.const -1) (i64.const 0)) (i64.const -1) +) +(assert_return + (invoke "add64_u_saturated" (i64.const -1) (i64.const 1)) (i64.const -1) +) +(assert_return + (invoke "add64_u_saturated" (i64.const -1) (i64.const -1)) (i64.const -1) +) +(assert_return + (invoke "add64_u_saturated" (i64.const 0x8000000000000000) (i64.const 0x8000000000000000)) (i64.const -1) +) + +(assert_return (invoke "type-use")) + +(assert_malformed + (module quote + "(type $sig (func (param i32) (result i32)))" + "(func (i32.const 0)" + " (if (type $sig) (result i32) (param i32) (i32.const 1) (then))" + ")" + ) + "unexpected token" +) +(assert_malformed + (module quote + "(type $sig (func (param i32) (result i32)))" + "(func (i32.const 0)" + " (if (param i32) (type $sig) (result i32) (i32.const 1) (then))" + ")" + ) + "unexpected token" +) +(assert_malformed + (module quote + "(type $sig (func (param i32) (result i32)))" + "(func (i32.const 0)" + " (if (param i32) (result i32) (type $sig) (i32.const 1) (then))" + ")" + ) + "unexpected token" +) +(assert_malformed + (module quote + "(type $sig (func (param i32) (result i32)))" + "(func (i32.const 0)" + " (if (result i32) (type $sig) (param i32) (i32.const 1) (then))" + ")" + ) + "unexpected token" +) +(assert_malformed + (module quote + "(type $sig (func (param i32) (result i32)))" + "(func (i32.const 0)" + " (if (result i32) (param i32) (type $sig) (i32.const 1) (then))" + ")" + ) + "unexpected token" +) +(assert_malformed + (module quote + "(func (i32.const 0) (if (result i32) (param i32) (i32.const 1) (then)))" + ) + "unexpected token" +) + +(assert_malformed + (module quote + "(func (i32.const 0) (i32.const 1)" + " (if (param $x i32) (then (drop)) (else (drop)))" + ")" + ) + "unexpected token" +) +(assert_malformed + (module quote + "(type $sig (func))" + "(func (i32.const 1)" + " (if (type $sig) (result i32) (then (i32.const 0)) (else (i32.const 2)))" + " (unreachable)" + ")" + ) + "inline function type" +) +(assert_malformed + (module quote + "(type $sig (func (param i32) (result i32)))" + "(func (i32.const 1)" + " (if (type $sig) (result i32) (then (i32.const 0)) (else (i32.const 2)))" + " (unreachable)" + ")" + ) + "inline function type" +) +(assert_malformed + (module quote + "(type $sig (func (param i32) (result i32)))" + "(func (i32.const 0) (i32.const 1)" + " (if (type $sig) (param i32) (then (drop)) (else (drop)))" + " (unreachable)" + ")" + ) + "inline function type" +) +(assert_malformed + (module quote + "(type $sig (func (param i32 i32) (result i32)))" + "(func (i32.const 0) (i32.const 1)" + " (if (type $sig) (param i32) (result i32) (then)) (unreachable)" + ")" + ) + "inline function type" +) + +(assert_invalid + (module + (type $sig (func)) + (func (i32.const 1) (if (type $sig) (i32.const 0) (then))) + ) + "type mismatch" +) + (assert_invalid (module (func $type-empty-i32 (result i32) (if (i32.const 0) (then)))) "type mismatch" @@ -536,7 +871,7 @@ "type mismatch" ) (assert_invalid - (module (func $type-then-value-num-vs-void + (module (func $type-then-value-num-vs-void-else (if (i32.const 1) (then (i32.const 1)) (else)) )) "type mismatch" @@ -554,6 +889,31 @@ "type mismatch" ) +(assert_invalid + (module (func $type-then-value-nums-vs-void + (if (i32.const 1) (then (i32.const 1) (i32.const 2))) + )) + "type mismatch" +) +(assert_invalid + (module (func $type-then-value-nums-vs-void-else + (if (i32.const 1) (then (i32.const 1) (i32.const 2)) (else)) + )) + "type mismatch" +) +(assert_invalid + (module (func $type-else-value-nums-vs-void + (if (i32.const 1) (then) (else (i32.const 1) (i32.const 2))) + )) + "type mismatch" +) +(assert_invalid + (module (func $type-both-value-nums-vs-void + (if (i32.const 1) (then (i32.const 1) (i32.const 2)) (else (i32.const 2) (i32.const 1))) + )) + "type mismatch" +) + (assert_invalid (module (func $type-then-value-empty-vs-num (result i32) (if (result i32) (i32.const 1) (then) (else (i32.const 0))) @@ -561,7 +921,7 @@ "type mismatch" ) (assert_invalid - (module (func $type-then-value-empty-vs-num (result i32) + (module (func $type-else-value-empty-vs-num (result i32) (if (result i32) (i32.const 1) (then (i32.const 0)) (else)) )) "type mismatch" @@ -572,12 +932,38 @@ )) "type mismatch" ) + +(assert_invalid + (module (func $type-then-value-empty-vs-nums (result i32 i32) + (if (result i32 i32) (i32.const 1) (then) (else (i32.const 0) (i32.const 2))) + )) + "type mismatch" +) +(assert_invalid + (module (func $type-else-value-empty-vs-nums (result i32 i32) + (if (result i32 i32) (i32.const 1) (then (i32.const 0) (i32.const 1)) (else)) + )) + "type mismatch" +) +(assert_invalid + (module (func $type-both-value-empty-vs-nums (result i32 i32) + (if (result i32 i32) (i32.const 1) (then) (else)) + )) + "type mismatch" +) + (assert_invalid (module (func $type-no-else-vs-num (result i32) (if (result i32) (i32.const 1) (then (i32.const 1))) )) "type mismatch" ) +(assert_invalid + (module (func $type-no-else-vs-nums (result i32 i32) + (if (result i32 i32) (i32.const 1) (then (i32.const 1) (i32.const 1))) + )) + "type mismatch" +) (assert_invalid (module (func $type-then-value-void-vs-num (result i32) @@ -586,7 +972,7 @@ "type mismatch" ) (assert_invalid - (module (func $type-then-value-void-vs-num (result i32) + (module (func $type-else-value-void-vs-num (result i32) (if (result i32) (i32.const 1) (then (i32.const 0)) (else (nop))) )) "type mismatch" @@ -598,6 +984,25 @@ "type mismatch" ) +(assert_invalid + (module (func $type-then-value-void-vs-nums (result i32 i32) + (if (result i32 i32) (i32.const 1) (then (nop)) (else (i32.const 0) (i32.const 0))) + )) + "type mismatch" +) +(assert_invalid + (module (func $type-else-value-void-vs-nums (result i32 i32) + (if (result i32 i32) (i32.const 1) (then (i32.const 0) (i32.const 0)) (else (nop))) + )) + "type mismatch" +) +(assert_invalid + (module (func $type-both-value-void-vs-nums (result i32 i32) + (if (result i32 i32) (i32.const 1) (then (nop)) (else (nop))) + )) + "type mismatch" +) + (assert_invalid (module (func $type-then-value-num-vs-num (result i32) (if (result i32) (i32.const 1) (then (i64.const 1)) (else (i32.const 1))) @@ -605,7 +1010,7 @@ "type mismatch" ) (assert_invalid - (module (func $type-then-value-num-vs-num (result i32) + (module (func $type-else-value-num-vs-num (result i32) (if (result i32) (i32.const 1) (then (i32.const 1)) (else (i64.const 1))) )) "type mismatch" @@ -616,12 +1021,79 @@ )) "type mismatch" ) + +(assert_invalid + (module (func $type-then-value-num-vs-nums (result i32 i32) + (if (result i32 i32) (i32.const 1) (then (i32.const 1)) (else (i32.const 1) (i32.const 1))) + )) + "type mismatch" +) +(assert_invalid + (module (func $type-else-value-num-vs-nums (result i32 i32) + (if (result i32 i32) (i32.const 1) (then (i32.const 1) (i32.const 1)) (else (i32.const 1))) + )) + "type mismatch" +) +(assert_invalid + (module (func $type-both-value-num-vs-nums (result i32 i32) + (if (result i32 i32) (i32.const 1) (then (i32.const 1)) (else (i32.const 1))) + )) + "type mismatch" +) + +(assert_invalid + (module (func $type-then-value-partial-vs-nums (result i32 i32) + (i32.const 0) + (if (result i32 i32) (i32.const 1) (then (i32.const 1)) (else (i32.const 1) (i32.const 1))) + )) + "type mismatch" +) +(assert_invalid + (module (func $type-else-value-partial-vs-nums (result i32 i32) + (i32.const 0) + (if (result i32 i32) (i32.const 1) (then (i32.const 1) (i32.const 1)) (else (i32.const 1))) + )) + "type mismatch" +) +(assert_invalid + (module (func $type-both-value-partial-vs-nums (result i32 i32) + (i32.const 0) + (if (result i32 i32) (i32.const 1) (then (i32.const 1)) (else (i32.const 1))) + )) + "type mismatch" +) + +(assert_invalid + (module (func $type-then-value-nums-vs-num (result i32) + (if (result i32) (i32.const 1) (then (i32.const 1) (i32.const 1)) (else (i32.const 1))) + )) + "type mismatch" +) +(assert_invalid + (module (func $type-else-value-nums-vs-num (result i32) + (if (result i32) (i32.const 1) (then (i32.const 1)) (else (i32.const 1) (i32.const 1))) + )) + "type mismatch" +) +(assert_invalid + (module (func $type-both-value-nums-vs-num (result i32) + (if (result i32) (i32.const 1) (then (i32.const 1) (i32.const 1)) (else (i32.const 1) (i32.const 1))) + )) + "type mismatch" +) + (assert_invalid (module (func $type-both-different-value-num-vs-num (result i32) (if (result i32) (i32.const 1) (then (i64.const 1)) (else (f64.const 1))) )) "type mismatch" ) +(assert_invalid + (module (func $type-both-different-value-nums-vs-nums (result i32 i32) + (if (result i32 i32) (i32.const 1) (then (i32.const 1) (i32.const 1) (i32.const 1)) (else (i32.const 1))) + )) + "type mismatch" +) (assert_invalid (module (func $type-then-value-unreached-select (result i32) @@ -666,6 +1138,19 @@ )) "type mismatch" ) +(assert_invalid + (module (func $type-then-break-last-void-vs-nums (result i32 i32) + (if (result i32 i32) (i32.const 1) (then (br 0)) (else (i32.const 1) (i32.const 1))) + )) + "type mismatch" +) +(assert_invalid + (module (func $type-else-break-last-void-vs-nums (result i32 i32) + (if (result i32 i32) (i32.const 1) (then (i32.const 1) (i32.const 1)) (else (br 0))) + )) + "type mismatch" +) + (assert_invalid (module (func $type-then-break-empty-vs-num (result i32) (if (result i32) (i32.const 1) @@ -684,6 +1169,25 @@ )) "type mismatch" ) +(assert_invalid + (module (func $type-then-break-empty-vs-nums (result i32 i32) + (if (result i32 i32) (i32.const 1) + (then (br 0) (i32.const 1) (i32.const 1)) + (else (i32.const 1) (i32.const 1)) + ) + )) + "type mismatch" +) +(assert_invalid + (module (func $type-else-break-empty-vs-nums (result i32 i32) + (if (result i32 i32) (i32.const 1) + (then (i32.const 1) (i32.const 1)) + (else (br 0) (i32.const 1) (i32.const 1)) + ) + )) + "type mismatch" +) + (assert_invalid (module (func $type-then-break-void-vs-num (result i32) (if (result i32) (i32.const 1) @@ -702,6 +1206,24 @@ )) "type mismatch" ) +(assert_invalid + (module (func $type-then-break-void-vs-nums (result i32 i32) + (if (result i32 i32) (i32.const 1) + (then (br 0 (nop)) (i32.const 1) (i32.const 1)) + (else (i32.const 1) (i32.const 1)) + ) + )) + "type mismatch" +) +(assert_invalid + (module (func $type-else-break-void-vs-nums (result i32 i32) + (if (result i32 i32) (i32.const 1) + (then (i32.const 1) (i32.const 1)) + (else (br 0 (nop)) (i32.const 1) (i32.const 1)) + ) + )) + "type mismatch" +) (assert_invalid (module (func $type-then-break-num-vs-num (result i32) @@ -721,6 +1243,44 @@ )) "type mismatch" ) +(assert_invalid + (module (func $type-then-break-num-vs-nums (result i32 i32) + (if (result i32 i32) (i32.const 1) + (then (br 0 (i64.const 1)) (i32.const 1) (i32.const 1)) + (else (i32.const 1) (i32.const 1)) + ) + )) + "type mismatch" +) +(assert_invalid + (module (func $type-else-break-num-vs-nums (result i32 i32) + (if (result i32 i32) (i32.const 1) + (then (i32.const 1) (i32.const 1)) + (else (br 0 (i64.const 1)) (i32.const 1) (i32.const 1)) + ) + )) + "type mismatch" +) +(assert_invalid + (module (func $type-then-break-partial-vs-nums (result i32 i32) + (i32.const 1) + (if (result i32 i32) (i32.const 1) + (then (br 0 (i64.const 1)) (i32.const 1)) + (else (i32.const 1)) + ) + )) + "type mismatch" +) +(assert_invalid + (module (func $type-else-break-partial-vs-nums (result i32 i32) + (i32.const 1) + (if (result i32 i32) (i32.const 1) + (then (i32.const 1)) + (else (br 0 (i64.const 1)) (i32.const 1)) + ) + )) + "type mismatch" +) (assert_invalid (module @@ -890,6 +1450,63 @@ "type mismatch" ) +(assert_invalid + (module (func $type-param-void-vs-num + (if (param i32) (i32.const 1) (then (drop))) + )) + "type mismatch" +) +(assert_invalid + (module (func $type-param-void-vs-nums + (if (param i32 f64) (i32.const 1) (then (drop) (drop))) + )) + "type mismatch" +) +(assert_invalid + (module (func $type-param-num-vs-num + (f32.const 0) (if (param i32) (i32.const 1) (then (drop))) + )) + "type mismatch" +) +(assert_invalid + (module (func $type-param-num-vs-nums + (f32.const 0) (if (param f32 i32) (i32.const 1) (then (drop) (drop))) + )) + "type mismatch" +) +(assert_invalid + (module (func $type-param-nested-void-vs-num + (block (if (param i32) (i32.const 1) (then (drop)))) + )) + "type mismatch" +) +(assert_invalid + (module (func $type-param-void-vs-nums + (block (if (param i32 f64) (i32.const 1) (then (drop) (drop)))) + )) + "type mismatch" +) +(assert_invalid + (module (func $type-param-num-vs-num + (block (f32.const 0) (if (param i32) (i32.const 1) (then (drop)))) + )) + "type mismatch" +) +(assert_invalid + (module (func $type-param-num-vs-nums + (block (f32.const 0) (if (param f32 i32) (i32.const 1) (then (drop) (drop)))) + )) + "type mismatch" +) + +(assert_malformed + (module quote "(func (param i32) (result i32) if (param $x i32) end)") + "unexpected token" +) +(assert_malformed + (module quote "(func (param i32) (result i32) (if (param $x i32) (then)))") + "unexpected token" +) (assert_malformed (module quote "(func i32.const 0 if end $l)") diff --git a/test/core/loop.wast b/test/core/loop.wast index 9141d00ed0..4557869b39 100644 --- a/test/core/loop.wast +++ b/test/core/loop.wast @@ -17,7 +17,14 @@ (func (export "multi") (result i32) (loop (call $dummy) (call $dummy) (call $dummy) (call $dummy)) - (loop (result i32) (call $dummy) (call $dummy) (call $dummy) (i32.const 8)) + (loop (result i32) (call $dummy) (call $dummy) (i32.const 8) (call $dummy)) + (drop) + (loop (result i32 i64 i32) + (call $dummy) (call $dummy) (call $dummy) (i32.const 8) (call $dummy) + (call $dummy) (call $dummy) (call $dummy) (i64.const 7) (call $dummy) + (call $dummy) (call $dummy) (call $dummy) (i32.const 9) (call $dummy) + ) + (drop) (drop) ) (func (export "nested") (result i32) @@ -188,6 +195,28 @@ (loop (result f32) (call $dummy) (f32.const 3)) ) ) + (func (export "as-binary-operands") (result i32) + (i32.mul + (loop (result i32 i32) + (call $dummy) (i32.const 3) (call $dummy) (i32.const 4) + ) + ) + ) + (func (export "as-compare-operands") (result i32) + (f32.gt + (loop (result f32 f32) + (call $dummy) (f32.const 3) (call $dummy) (f32.const 3) + ) + ) + ) + (func (export "as-mixed-operands") (result i32) + (loop (result i32 i32) + (call $dummy) (i32.const 3) (call $dummy) (i32.const 4) + ) + (i32.const 5) + (i32.add) + (i32.mul) + ) (func (export "break-bare") (result i32) (block (loop (br 1) (br 0) (unreachable))) @@ -198,7 +227,22 @@ ) (func (export "break-value") (result i32) (block (result i32) - (loop (result i32) (br 1 (i32.const 18)) (br 0) (i32.const 19)) + (i32.const 0) + (loop (param i32) + (block (br 2 (i32.const 18))) + (br 0 (i32.const 20)) + ) + (i32.const 19) + ) + ) + (func (export "break-multi-value") (result i32 i32 i64) + (block (result i32 i32 i64) + (i32.const 0) (i32.const 0) (i64.const 0) + (loop (param i32 i32 i64) + (block (br 2 (i32.const 18) (i32.const -18) (i64.const 18))) + (br 0 (i32.const 20) (i32.const -20) (i64.const 20)) + ) + (i32.const 19) (i32.const -19) (i64.const 19) ) ) (func (export "break-repeated") (result i32) @@ -234,6 +278,66 @@ (local.get 0) ) + (func (export "param") (result i32) + (i32.const 1) + (loop (param i32) (result i32) + (i32.const 2) + (i32.add) + ) + ) + (func (export "params") (result i32) + (i32.const 1) + (i32.const 2) + (loop (param i32 i32) (result i32) + (i32.add) + ) + ) + (func (export "params-id") (result i32) + (i32.const 1) + (i32.const 2) + (loop (param i32 i32) (result i32 i32)) + (i32.add) + ) + (func (export "param-break") (result i32) + (local $x i32) + (i32.const 1) + (loop (param i32) (result i32) + (i32.const 4) + (i32.add) + (local.tee $x) + (local.get $x) + (i32.const 10) + (i32.lt_u) + (br_if 0) + ) + ) + (func (export "params-break") (result i32) + (local $x i32) + (i32.const 1) + (i32.const 2) + (loop (param i32 i32) (result i32) + (i32.add) + (local.tee $x) + (i32.const 3) + (local.get $x) + (i32.const 10) + (i32.lt_u) + (br_if 0) + (drop) + ) + ) + (func (export "params-id-break") (result i32) + (local $x i32) + (local.set $x (i32.const 0)) + (i32.const 1) + (i32.const 2) + (loop (param i32 i32) (result i32 i32) + (local.set $x (i32.add (local.get $x) (i32.const 1))) + (br_if 0 (i32.lt_u (local.get $x) (i32.const 10))) + ) + (i32.add) + ) + (func $fx (export "effects") (result i32) (local i32) (block @@ -300,6 +404,27 @@ ) (local.get 3) ) + + (type $block-sig-1 (func)) + (type $block-sig-2 (func (result i32))) + (type $block-sig-3 (func (param $x i32))) + (type $block-sig-4 (func (param i32 f64 i32) (result i32 f64 i32))) + + (func (export "type-use") + (loop (type $block-sig-1)) + (loop (type $block-sig-2) (i32.const 0)) + (loop (type $block-sig-3) (drop)) + (i32.const 0) (f64.const 0) (i32.const 0) + (loop (type $block-sig-4)) + (drop) (drop) (drop) + (loop (type $block-sig-2) (result i32) (i32.const 0)) + (loop (type $block-sig-3) (param i32) (drop)) + (i32.const 0) (f64.const 0) (i32.const 0) + (loop (type $block-sig-4) + (param i32) (param f64 i32) (result i32 f64) (result i32) + ) + (drop) (drop) (drop) + ) ) (assert_return (invoke "empty")) @@ -343,12 +468,25 @@ (assert_return (invoke "as-binary-operand") (i32.const 12)) (assert_return (invoke "as-test-operand") (i32.const 0)) (assert_return (invoke "as-compare-operand") (i32.const 0)) +(assert_return (invoke "as-binary-operands") (i32.const 12)) +(assert_return (invoke "as-compare-operands") (i32.const 0)) +(assert_return (invoke "as-mixed-operands") (i32.const 27)) (assert_return (invoke "break-bare") (i32.const 19)) (assert_return (invoke "break-value") (i32.const 18)) +(assert_return (invoke "break-multi-value") + (i32.const 18) (i32.const -18) (i64.const 18) +) (assert_return (invoke "break-repeated") (i32.const 18)) (assert_return (invoke "break-inner") (i32.const 0x1f)) +(assert_return (invoke "param") (i32.const 3)) +(assert_return (invoke "params") (i32.const 3)) +(assert_return (invoke "params-id") (i32.const 3)) +(assert_return (invoke "param-break") (i32.const 13)) +(assert_return (invoke "params-break") (i32.const 12)) +(assert_return (invoke "params-id-break") (i32.const 3)) + (assert_return (invoke "effects") (i32.const 1)) (assert_return (invoke "while" (i64.const 0)) (i64.const 1)) @@ -382,6 +520,91 @@ (assert_return (invoke "nesting" (f32.const 7) (f32.const 100)) (f32.const 4381.54785156)) (assert_return (invoke "nesting" (f32.const 7) (f32.const 101)) (f32.const 2601)) +(assert_return (invoke "type-use")) + +(assert_malformed + (module quote + "(type $sig (func (param i32) (result i32)))" + "(func (i32.const 0) (loop (type $sig) (result i32) (param i32)))" + ) + "unexpected token" +) +(assert_malformed + (module quote + "(type $sig (func (param i32) (result i32)))" + "(func (i32.const 0) (loop (param i32) (type $sig) (result i32)))" + ) + "unexpected token" +) +(assert_malformed + (module quote + "(type $sig (func (param i32) (result i32)))" + "(func (i32.const 0) (loop (param i32) (result i32) (type $sig)))" + ) + "unexpected token" +) +(assert_malformed + (module quote + "(type $sig (func (param i32) (result i32)))" + "(func (i32.const 0) (loop (result i32) (type $sig) (param i32)))" + ) + "unexpected token" +) +(assert_malformed + (module quote + "(type $sig (func (param i32) (result i32)))" + "(func (i32.const 0) (loop (result i32) (param i32) (type $sig)))" + ) + "unexpected token" +) +(assert_malformed + (module quote + "(func (i32.const 0) (loop (result i32) (param i32)))" + ) + "unexpected token" +) + +(assert_malformed + (module quote "(func (i32.const 0) (loop (param $x i32) (drop)))") + "unexpected token" +) +(assert_malformed + (module quote + "(type $sig (func))" + "(func (loop (type $sig) (result i32) (i32.const 0)) (unreachable))" + ) + "inline function type" +) +(assert_malformed + (module quote + "(type $sig (func (param i32) (result i32)))" + "(func (loop (type $sig) (result i32) (i32.const 0)) (unreachable))" + ) + "inline function type" +) +(assert_malformed + (module quote + "(type $sig (func (param i32) (result i32)))" + "(func (i32.const 0) (loop (type $sig) (param i32) (drop)) (unreachable))" + ) + "inline function type" +) +(assert_malformed + (module quote + "(type $sig (func (param i32 i32) (result i32)))" + "(func (i32.const 0) (loop (type $sig) (param i32) (result i32)) (unreachable))" + ) + "inline function type" +) + +(assert_invalid + (module + (type $sig (func)) + (func (loop (type $sig) (i32.const 0))) + ) + "type mismatch" +) + (assert_invalid (module (func $type-empty-i32 (result i32) (loop))) "type mismatch" @@ -405,24 +628,60 @@ )) "type mismatch" ) +(assert_invalid + (module (func $type-value-nums-vs-void + (loop (i32.const 1) (i32.const 2)) + )) + "type mismatch" +) (assert_invalid (module (func $type-value-empty-vs-num (result i32) (loop (result i32)) )) "type mismatch" ) +(assert_invalid + (module (func $type-value-empty-vs-nums (result i32 i32) + (loop (result i32 i32)) + )) + "type mismatch" +) (assert_invalid (module (func $type-value-void-vs-num (result i32) (loop (result i32) (nop)) )) "type mismatch" ) +(assert_invalid + (module (func $type-value-void-vs-nums (result i32 i32) + (loop (result i32 i32) (nop)) + )) + "type mismatch" +) (assert_invalid (module (func $type-value-num-vs-num (result i32) (loop (result i32) (f32.const 0)) )) "type mismatch" ) +(assert_invalid + (module (func $type-value-num-vs-nums (result i32 i32) + (loop (result i32 i32) (i32.const 0)) + )) + "type mismatch" +) +(assert_invalid + (module (func $type-value-partial-vs-nums (result i32 i32) + (i32.const 1) (loop (result i32 i32) (i32.const 2)) + )) + "type mismatch" +) +(assert_invalid + (module (func $type-value-nums-vs-num (result i32) + (loop (result i32) (i32.const 1) (i32.const 2)) + )) + "type mismatch" +) (assert_invalid (module (func $type-value-unreached-select (result i32) (loop (result i64) (select (unreachable) (unreachable) (unreachable))) @@ -458,6 +717,63 @@ "type mismatch" ) +(assert_invalid + (module (func $type-param-void-vs-num + (loop (param i32) (drop)) + )) + "type mismatch" +) +(assert_invalid + (module (func $type-param-void-vs-nums + (loop (param i32 f64) (drop) (drop)) + )) + "type mismatch" +) +(assert_invalid + (module (func $type-param-num-vs-num + (f32.const 0) (loop (param i32) (drop)) + )) + "type mismatch" +) +(assert_invalid + (module (func $type-param-num-vs-nums + (f32.const 0) (loop (param f32 i32) (drop) (drop)) + )) + "type mismatch" +) +(assert_invalid + (module (func $type-param-nested-void-vs-num + (block (loop (param i32) (drop))) + )) + "type mismatch" +) +(assert_invalid + (module (func $type-param-void-vs-nums + (block (loop (param i32 f64) (drop) (drop))) + )) + "type mismatch" +) +(assert_invalid + (module (func $type-param-num-vs-num + (block (f32.const 0) (loop (param i32) (drop))) + )) + "type mismatch" +) +(assert_invalid + (module (func $type-param-num-vs-nums + (block (f32.const 0) (loop (param f32 i32) (drop) (drop))) + )) + "type mismatch" +) + +(assert_malformed + (module quote "(func (param i32) (result i32) loop (param $x i32) end)") + "unexpected token" +) +(assert_malformed + (module quote "(func (param i32) (result i32) (loop (param $x i32)))") + "unexpected token" +) (assert_malformed (module quote "(func loop end $l)") diff --git a/test/core/stack.wast b/test/core/stack.wast index d0c46955d3..5da5043c8e 100644 --- a/test/core/stack.wast +++ b/test/core/stack.wast @@ -125,12 +125,31 @@ end local.get $res ) + + (global $temp (mut i32) (i32.const 0)) + (func $add_one_to_global (result i32) + (local i32) + (global.set $temp (i32.add (i32.const 1) (global.get $temp))) + (global.get $temp) + ) + (func $add_one_to_global_and_drop + (drop (call $add_one_to_global)) + ) + (func (export "not-quite-a-tree") (result i32) + call $add_one_to_global + call $add_one_to_global + call $add_one_to_global_and_drop + i32.add + ) ) (assert_return (invoke "fac-expr" (i64.const 25)) (i64.const 7034535277573963776)) (assert_return (invoke "fac-stack" (i64.const 25)) (i64.const 7034535277573963776)) (assert_return (invoke "fac-mixed" (i64.const 25)) (i64.const 7034535277573963776)) +(assert_return (invoke "not-quite-a-tree") (i32.const 3)) +(assert_return (invoke "not-quite-a-tree") (i32.const 9)) + ;; Syntax of flat call_indirect diff --git a/test/core/type.wast b/test/core/type.wast index 5ceeeb2697..b94063e6a0 100644 --- a/test/core/type.wast +++ b/test/core/type.wast @@ -11,33 +11,33 @@ (type (func (param $x i32) (result i32))) (type (func (param f32 f64))) - ;; (type (func (result i64 f32))) - ;; (type (func (param i32 i64) (result f32 f64))) + (type (func (result i64 f32))) + (type (func (param i32 i64) (result f32 f64))) (type (func (param f32) (param f64))) (type (func (param $x f32) (param f64))) (type (func (param f32) (param $y f64))) (type (func (param $x f32) (param $y f64))) - ;; (type (func (result i64) (result f32))) - ;; (type (func (param i32) (param i64) (result f32) (result f64))) - ;; (type (func (param $x i32) (param $y i64) (result f32) (result f64))) + (type (func (result i64) (result f32))) + (type (func (param i32) (param i64) (result f32) (result f64))) + (type (func (param $x i32) (param $y i64) (result f32) (result f64))) (type (func (param f32 f64) (param $x i32) (param f64 i32 i32))) - ;; (type (func (result i64 i64 f32) (result f32 i32))) - ;; (type - ;; (func (param i32 i32) (param i64 i32) (result f32 f64) (result f64 i32)) - ;; ) + (type (func (result i64 i64 f32) (result f32 i32))) + (type + (func (param i32 i32) (param i64 i32) (result f32 f64) (result f64 i32)) + ) (type (func (param) (param $x f32) (param) (param) (param f64 i32) (param))) - ;; (type - ;; (func (result) (result) (result i64 i64) (result) (result f32) (result)) - ;; ) - ;; (type - ;; (func - ;; (param i32 i32) (param i64 i32) (param) (param $x i32) (param) - ;; (result) (result f32 f64) (result f64 i32) (result) - ;; ) - ;; ) + (type + (func (result) (result) (result i64 i64) (result) (result f32) (result)) + ) + (type + (func + (param i32 i32) (param i64 i32) (param) (param $x i32) (param) + (result) (result f32 f64) (result f64 i32) (result) + ) + ) ) (assert_malformed @@ -48,12 +48,3 @@ (module quote "(type (func (result $x i32)))") "unexpected token" ) - -(assert_invalid - (module (type (func (result i32 i32)))) - "invalid result arity" -) -(assert_invalid - (module (type (func (result i32) (result i32)))) - "invalid result arity" -) diff --git a/test/js-api/assertions.js b/test/js-api/assertions.js index bda3ae7bc3..f00303f6aa 100644 --- a/test/js-api/assertions.js +++ b/test/js-api/assertions.js @@ -34,6 +34,7 @@ function assert_Instance(instance, expected_exports) { assert_equals(Object.getPrototypeOf(exports), null, "exports prototype"); assert_false(Object.isExtensible(exports), "extensible exports"); + assert_array_equals(Object.keys(exports), Object.keys(expected_exports), "matching export keys"); for (const [key, expected] of Object.entries(expected_exports)) { const property = Object.getOwnPropertyDescriptor(exports, key); assert_equals(typeof property, "object", `${key} should be present`); @@ -71,3 +72,24 @@ function assert_Instance(instance, expected_exports) { } } } + +function assert_WebAssemblyInstantiatedSource(actual, expected_exports={}) { + assert_equals(Object.getPrototypeOf(actual), Object.prototype, + "Prototype"); + assert_true(Object.isExtensible(actual), "Extensibility"); + + const module = Object.getOwnPropertyDescriptor(actual, "module"); + assert_equals(typeof module, "object", "module: type of descriptor"); + assert_true(module.writable, "module: writable"); + assert_true(module.enumerable, "module: enumerable"); + assert_true(module.configurable, "module: configurable"); + assert_equals(Object.getPrototypeOf(module.value), WebAssembly.Module.prototype, + "module: prototype"); + + const instance = Object.getOwnPropertyDescriptor(actual, "instance"); + assert_equals(typeof instance, "object", "instance: type of descriptor"); + assert_true(instance.writable, "instance: writable"); + assert_true(instance.enumerable, "instance: enumerable"); + assert_true(instance.configurable, "instance: configurable"); + assert_Instance(instance.value, expected_exports); +} diff --git a/test/js-api/bad-imports.js b/test/js-api/bad-imports.js index 6c7d8056c7..afd41936d3 100644 --- a/test/js-api/bad-imports.js +++ b/test/js-api/bad-imports.js @@ -2,7 +2,7 @@ * `t` should be a function that takes at least three arguments: * * - the name of the test; - * - the expected error (to be passed to `assert_throws` or similar); + * - the expected error (to be passed to `assert_throws_js`); * - a function that takes a `WasmModuleBuilder` and initializes it; * - (optionally) an options object. * @@ -13,7 +13,7 @@ function test_bad_imports(t) { for (const value of [null, true, "", Symbol(), 1, 0.1, NaN]) { t(`Non-object imports argument: ${format_value(value)}`, - new TypeError(), + TypeError, builder => {}, value); } @@ -23,7 +23,7 @@ function test_bad_imports(t) { "module": value, }; t(`Non-object module: ${format_value(value)}`, - new TypeError(), + TypeError, builder => { builder.addImport("module", "fn", kSig_v_v); }, @@ -31,14 +31,14 @@ function test_bad_imports(t) { } t(`Missing imports argument`, - new TypeError(), + TypeError, builder => { builder.addImport("module", "fn", kSig_v_v); }); for (const [value, name] of [[undefined, "undefined"], [{}, "empty object"], [{ "module\0": null }, "wrong property"]]) { t(`Imports argument with missing property: ${name}`, - new TypeError(), + TypeError, builder => { builder.addImport("module", "fn", kSig_v_v); }, @@ -46,7 +46,7 @@ function test_bad_imports(t) { } t(`Importing an i64 global`, - new WebAssembly.LinkError(), + WebAssembly.LinkError, builder => { builder.addImportedGlobal("module", "global", kWasmI64); }, @@ -58,7 +58,7 @@ function test_bad_imports(t) { for (const value of [undefined, null, true, "", Symbol(), 1, 0.1, NaN, {}]) { t(`Importing a function with an incorrectly-typed value: ${format_value(value)}`, - new WebAssembly.LinkError(), + WebAssembly.LinkError, builder => { builder.addImport("module", "fn", kSig_v_v); }, @@ -79,11 +79,12 @@ function test_bad_imports(t) { [WebAssembly.Global, "WebAssembly.Global"], [WebAssembly.Global.prototype, "WebAssembly.Global.prototype"], [Object.create(WebAssembly.Global.prototype), "Object.create(WebAssembly.Global.prototype)"], + [new WebAssembly.Global({value: "f32"}), "WebAssembly.Global object (wrong value type)"], ]; for (const [value, name = format_value(value)] of nonGlobals) { t(`Importing a global with an incorrectly-typed value: ${name}`, - new WebAssembly.LinkError(), + WebAssembly.LinkError, builder => { builder.addImportedGlobal("module", "global", kWasmI32); }, @@ -107,11 +108,12 @@ function test_bad_imports(t) { [WebAssembly.Memory, "WebAssembly.Memory"], [WebAssembly.Memory.prototype, "WebAssembly.Memory.prototype"], [Object.create(WebAssembly.Memory.prototype), "Object.create(WebAssembly.Memory.prototype)"], + [new WebAssembly.Memory({"initial": 256}), "WebAssembly.Memory object (too large)"], ]; for (const [value, name = format_value(value)] of nonMemories) { t(`Importing memory with an incorrectly-typed value: ${name}`, - new WebAssembly.LinkError(), + WebAssembly.LinkError, builder => { builder.addImportedMemory("module", "memory", 0, 128); }, @@ -135,11 +137,12 @@ function test_bad_imports(t) { [WebAssembly.Table, "WebAssembly.Table"], [WebAssembly.Table.prototype, "WebAssembly.Table.prototype"], [Object.create(WebAssembly.Table.prototype), "Object.create(WebAssembly.Table.prototype)"], + [new WebAssembly.Table({"element": "anyfunc", "initial": 256}), "WebAssembly.Table object (too large)"], ]; for (const [value, name = format_value(value)] of nonTables) { t(`Importing table with an incorrectly-typed value: ${name}`, - new WebAssembly.LinkError(), + WebAssembly.LinkError, builder => { builder.addImportedTable("module", "table", 0, 128); }, diff --git a/test/js-api/constructor/compile.any.js b/test/js-api/constructor/compile.any.js index 5288d97119..e94ce11717 100644 --- a/test/js-api/constructor/compile.any.js +++ b/test/js-api/constructor/compile.any.js @@ -1,4 +1,4 @@ -// META: global=jsshell +// META: global=window,dedicatedworker,jsshell // META: script=/wasm/jsapi/wasm-module-builder.js function assert_Module(module) { @@ -13,7 +13,7 @@ setup(() => { }); promise_test(t => { - return promise_rejects(t, new TypeError(), WebAssembly.compile()); + return promise_rejects_js(t, TypeError, WebAssembly.compile()); }, "Missing argument"); promise_test(t => { @@ -30,7 +30,7 @@ promise_test(t => { Array.from(emptyModuleBinary), ]; return Promise.all(invalidArguments.map(argument => { - return promise_rejects(t, new TypeError(), WebAssembly.compile(argument), + return promise_rejects_js(t, TypeError, WebAssembly.compile(argument), `compile(${format_value(argument)})`); })); }, "Invalid arguments"); @@ -60,7 +60,12 @@ test(() => { promise_test(t => { const buffer = new Uint8Array(); - return promise_rejects(t, new WebAssembly.CompileError(), WebAssembly.compile(buffer)); + return promise_rejects_js(t, WebAssembly.CompileError, WebAssembly.compile(buffer)); +}, "Empty buffer"); + +promise_test(t => { + const buffer = new Uint8Array(Array.from(emptyModuleBinary).concat([0, 0])); + return promise_rejects_js(t, WebAssembly.CompileError, WebAssembly.compile(buffer)); }, "Invalid code"); promise_test(() => { diff --git a/test/js-api/constructor/instantiate-bad-imports.any.js b/test/js-api/constructor/instantiate-bad-imports.any.js index 1eaefdfba2..30252bd6ee 100644 --- a/test/js-api/constructor/instantiate-bad-imports.any.js +++ b/test/js-api/constructor/instantiate-bad-imports.any.js @@ -1,4 +1,4 @@ -// META: global=jsshell +// META: global=window,dedicatedworker,jsshell // META: script=/wasm/jsapi/wasm-module-builder.js // META: script=/wasm/jsapi/bad-imports.js @@ -8,7 +8,7 @@ test_bad_imports((name, error, build, ...arguments) => { build(builder); const buffer = builder.toBuffer(); const module = new WebAssembly.Module(buffer); - return promise_rejects(t, error, WebAssembly.instantiate(module, ...arguments)); + return promise_rejects_js(t, error, WebAssembly.instantiate(module, ...arguments)); }, `WebAssembly.instantiate(module): ${name}`); }); @@ -17,6 +17,6 @@ test_bad_imports((name, error, build, ...arguments) => { const builder = new WasmModuleBuilder(); build(builder); const buffer = builder.toBuffer(); - return promise_rejects(t, error, WebAssembly.instantiate(buffer, ...arguments)); + return promise_rejects_js(t, error, WebAssembly.instantiate(buffer, ...arguments)); }, `WebAssembly.instantiate(buffer): ${name}`); }); diff --git a/test/js-api/constructor/instantiate.any.js b/test/js-api/constructor/instantiate.any.js index 49499127ce..8152f3a56f 100644 --- a/test/js-api/constructor/instantiate.any.js +++ b/test/js-api/constructor/instantiate.any.js @@ -1,36 +1,15 @@ -// META: global=jsshell +// META: global=window,dedicatedworker,jsshell // META: script=/wasm/jsapi/wasm-module-builder.js // META: script=/wasm/jsapi/assertions.js // META: script=/wasm/jsapi/instanceTestFactory.js -function assert_WebAssemblyInstantiatedSource(actual, expected_exports={}) { - assert_equals(Object.getPrototypeOf(actual), Object.prototype, - "Prototype"); - assert_true(Object.isExtensible(actual), "Extensibility"); - - const module = Object.getOwnPropertyDescriptor(actual, "module"); - assert_equals(typeof module, "object", "module: type of descriptor"); - assert_true(module.writable, "module: writable"); - assert_true(module.enumerable, "module: enumerable"); - assert_true(module.configurable, "module: configurable"); - assert_equals(Object.getPrototypeOf(module.value), WebAssembly.Module.prototype, - "module: prototype"); - - const instance = Object.getOwnPropertyDescriptor(actual, "instance"); - assert_equals(typeof instance, "object", "instance: type of descriptor"); - assert_true(instance.writable, "instance: writable"); - assert_true(instance.enumerable, "instance: enumerable"); - assert_true(instance.configurable, "instance: configurable"); - assert_Instance(instance.value, expected_exports); -} - let emptyModuleBinary; setup(() => { emptyModuleBinary = new WasmModuleBuilder().toBuffer(); }); promise_test(t => { - return promise_rejects(t, new TypeError(), WebAssembly.instantiate()); + return promise_rejects_js(t, TypeError, WebAssembly.instantiate()); }, "Missing arguments"); promise_test(() => { @@ -66,7 +45,7 @@ promise_test(t => { Array.from(emptyModuleBinary), ]; return Promise.all(invalidArguments.map(argument => { - return promise_rejects(t, new TypeError(), WebAssembly.instantiate(argument), + return promise_rejects_js(t, TypeError, WebAssembly.instantiate(argument), `instantiate(${format_value(argument)})`); })); }, "Invalid arguments"); @@ -156,7 +135,12 @@ promise_test(() => { promise_test(t => { const buffer = new Uint8Array(); - return promise_rejects(t, new WebAssembly.CompileError(), WebAssembly.instantiate(buffer)); + return promise_rejects_js(t, WebAssembly.CompileError, WebAssembly.instantiate(buffer)); +}, "Empty buffer"); + +promise_test(t => { + const buffer = new Uint8Array(Array.from(emptyModuleBinary).concat([0, 0])); + return promise_rejects_js(t, WebAssembly.CompileError, WebAssembly.instantiate(buffer)); }, "Invalid code"); promise_test(() => { diff --git a/test/js-api/constructor/multi-value.any.js b/test/js-api/constructor/multi-value.any.js new file mode 100644 index 0000000000..4b06d1da3c --- /dev/null +++ b/test/js-api/constructor/multi-value.any.js @@ -0,0 +1,149 @@ +// META: global=window,dedicatedworker,jsshell +// META: script=/wasm/jsapi/wasm-module-builder.js +// META: script=/wasm/jsapi/assertions.js + +const type_if_fi = makeSig([kWasmF64, kWasmI32], [kWasmI32, kWasmF64]); + +promise_test(async () => { + const builder = new WasmModuleBuilder(); + + builder + .addFunction("swap", type_if_fi) + .addBody([ + kExprLocalGet, 1, + kExprLocalGet, 0, + kExprReturn, + ]) + .exportFunc(); + + const buffer = builder.toBuffer(); + + const result = await WebAssembly.instantiate(buffer); + const swapped = result.instance.exports.swap(4.2, 7); + assert_true(Array.isArray(swapped)); + assert_equals(Object.getPrototypeOf(swapped), Array.prototype); + assert_array_equals(swapped, [7, 4.2]); +}, "multiple return values from wasm to js"); + +promise_test(async () => { + const builder = new WasmModuleBuilder(); + + const swap = builder + .addFunction("swap", type_if_fi) + .addBody([ + kExprLocalGet, 1, + kExprLocalGet, 0, + kExprReturn, + ]); + builder + .addFunction("callswap", kSig_i_v) + .addBody([ + ...wasmF64Const(4.2), + ...wasmI32Const(7), + kExprCallFunction, swap.index, + kExprDrop, + kExprReturn, + ]) + .exportFunc(); + + const buffer = builder.toBuffer(); + + const result = await WebAssembly.instantiate(buffer); + const swapped = result.instance.exports.callswap(); + assert_equals(swapped, 7); +}, "multiple return values inside wasm"); + +promise_test(async () => { + const builder = new WasmModuleBuilder(); + + const fnIndex = builder.addImport("module", "fn", type_if_fi); + builder + .addFunction("callfn", kSig_i_v) + .addBody([ + ...wasmF64Const(4.2), + ...wasmI32Const(7), + kExprCallFunction, fnIndex, + kExprDrop, + kExprReturn, + ]) + .exportFunc(); + + const buffer = builder.toBuffer(); + + const actual = []; + const imports = { + "module": { + fn(f32, i32) { + assert_equals(f32, 4.2); + assert_equals(i32, 7); + const result = [2, 7.3]; + let i = 0; + return { + get [Symbol.iterator]() { + actual.push("@@iterator getter"); + return function iterator() { + actual.push("@@iterator call"); + return { + get next() { + actual.push("next getter"); + return function next(...args) { + assert_array_equals(args, []); + let j = ++i; + actual.push(`next call ${j}`); + if (j > result.length) { + return { + get done() { + actual.push(`done call ${j}`); + return true; + } + }; + } + return { + get done() { + actual.push(`done call ${j}`); + return false; + }, + get value() { + actual.push(`value call ${j}`); + return { + get valueOf() { + actual.push(`valueOf get ${j}`); + return function() { + actual.push(`valueOf call ${j}`); + return result[j - 1]; + }; + } + }; + } + }; + }; + } + }; + } + }, + }; + }, + } + }; + + const { instance } = await WebAssembly.instantiate(buffer, imports); + const result = instance.exports.callfn(); + assert_equals(result, 2); + assert_array_equals(actual, [ + "@@iterator getter", + "@@iterator call", + "next getter", + "next call 1", + "done call 1", + "value call 1", + "next call 2", + "done call 2", + "value call 2", + "next call 3", + "done call 3", + "valueOf get 1", + "valueOf call 1", + "valueOf get 2", + "valueOf call 2", + ]); +}, "multiple return values from js to wasm"); diff --git a/test/js-api/constructor/validate.any.js b/test/js-api/constructor/validate.any.js index 57fa335977..8b4f4582ab 100644 --- a/test/js-api/constructor/validate.any.js +++ b/test/js-api/constructor/validate.any.js @@ -1,4 +1,4 @@ -// META: global=jsshell +// META: global=window,dedicatedworker,jsshell // META: script=/wasm/jsapi/wasm-module-builder.js let emptyModuleBinary; @@ -7,7 +7,7 @@ setup(() => { }); test(() => { - assert_throws(new TypeError(), () => WebAssembly.validate()); + assert_throws_js(TypeError, () => WebAssembly.validate()); }, "Missing argument"); test(() => { @@ -24,8 +24,8 @@ test(() => { Array.from(emptyModuleBinary), ]; for (const argument of invalidArguments) { - assert_throws(new TypeError(), () => WebAssembly.validate(argument), - `validate(${format_value(argument)})`); + assert_throws_js(TypeError, () => WebAssembly.validate(argument), + `validate(${format_value(argument)})`); } }, "Invalid arguments"); diff --git a/test/js-api/error-interfaces-no-symbol-tostringtag.js b/test/js-api/error-interfaces-no-symbol-tostringtag.js new file mode 100644 index 0000000000..572db0c01b --- /dev/null +++ b/test/js-api/error-interfaces-no-symbol-tostringtag.js @@ -0,0 +1,13 @@ +// META: global=jsshell + +test(() => { + assert_not_own_property(WebAssembly.CompileError.prototype, Symbol.toStringTag); +}, "WebAssembly.CompileError"); + +test(() => { + assert_not_own_property(WebAssembly.LinkError.prototype, Symbol.toStringTag); +}, "WebAssembly.LinkError"); + +test(() => { + assert_not_own_property(WebAssembly.RuntimeError.prototype, Symbol.toStringTag); +}, "WebAssembly.RuntimeError"); diff --git a/test/js-api/global/constructor.any.js b/test/js-api/global/constructor.any.js index 237f99c8b2..b008ef3016 100644 --- a/test/js-api/global/constructor.any.js +++ b/test/js-api/global/constructor.any.js @@ -1,4 +1,4 @@ -// META: global=jsshell +// META: global=window,dedicatedworker,jsshell // META: script=/wasm/jsapi/assertions.js function assert_Global(actual, expected) { @@ -19,12 +19,12 @@ test(() => { }, "length"); test(() => { - assert_throws(new TypeError(), () => new WebAssembly.Global()); + assert_throws_js(TypeError, () => new WebAssembly.Global()); }, "No arguments"); test(() => { const argument = { "value": "i32" }; - assert_throws(new TypeError(), () => WebAssembly.Global(argument)); + assert_throws_js(TypeError, () => WebAssembly.Global(argument)); }, "Calling"); test(() => { @@ -73,9 +73,9 @@ test(() => { {}, ]; for (const invalidArgument of invalidArguments) { - assert_throws(new TypeError(), - () => new WebAssembly.Global(invalidArgument), - `new Global(${format_value(invalidArgument)})`); + assert_throws_js(TypeError, + () => new WebAssembly.Global(invalidArgument), + `new Global(${format_value(invalidArgument)})`); } }, "Invalid descriptor argument"); @@ -83,15 +83,15 @@ test(() => { const invalidTypes = ["i16", "i128", "f16", "f128", "u32", "u64", "i32\0"]; for (const value of invalidTypes) { const argument = { value }; - assert_throws(new TypeError(), () => new WebAssembly.Global(argument)); + assert_throws_js(TypeError, () => new WebAssembly.Global(argument)); } }, "Invalid type argument"); test(() => { const argument = { "value": "i64" }; const global = new WebAssembly.Global(argument); - assert_throws(new TypeError(), () => global.value); - assert_throws(new TypeError(), () => global.valueOf()); + assert_throws_js(TypeError, () => global.value); + assert_throws_js(TypeError, () => global.valueOf()); }, "i64 with default"); for (const type of ["i32", "f32", "f64"]) { diff --git a/test/js-api/global/toString.any.js b/test/js-api/global/toString.any.js index ca025576c2..359c4273b5 100644 --- a/test/js-api/global/toString.any.js +++ b/test/js-api/global/toString.any.js @@ -1,7 +1,17 @@ -// META: global=jsshell +// META: global=window,dedicatedworker,jsshell test(() => { const argument = { "value": "i32" }; const global = new WebAssembly.Global(argument); assert_class_string(global, "WebAssembly.Global"); }, "Object.prototype.toString on an Global"); + +test(() => { + assert_own_property(WebAssembly.Global.prototype, Symbol.toStringTag); + + const propDesc = Object.getOwnPropertyDescriptor(WebAssembly.Global.prototype, Symbol.toStringTag); + assert_equals(propDesc.value, "WebAssembly.Global", "value"); + assert_equals(propDesc.configurable, true, "configurable"); + assert_equals(propDesc.enumerable, false, "enumerable"); + assert_equals(propDesc.writable, false, "writable"); +}, "@@toStringTag exists on the prototype with the appropriate descriptor"); diff --git a/test/js-api/global/value-get-set.any.js b/test/js-api/global/value-get-set.any.js index 6de62d5f58..43d8474a25 100644 --- a/test/js-api/global/value-get-set.any.js +++ b/test/js-api/global/value-get-set.any.js @@ -1,4 +1,4 @@ -// META: global=jsshell +// META: global=window,dedicatedworker,jsshell test(() => { const thisValues = [ @@ -23,8 +23,8 @@ test(() => { assert_equals(typeof setter, "function"); for (const thisValue of thisValues) { - assert_throws(new TypeError(), () => getter.call(thisValue), `getter with this=${format_value(thisValue)}`); - assert_throws(new TypeError(), () => setter.call(thisValue, 1), `setter with this=${format_value(thisValue)}`); + assert_throws_js(TypeError, () => getter.call(thisValue), `getter with this=${format_value(thisValue)}`); + assert_throws_js(TypeError, () => setter.call(thisValue, 1), `setter with this=${format_value(thisValue)}`); } }, "Branding"); @@ -44,11 +44,27 @@ for (const type of ["i32", "f32", "f64"]) { assert_equals(global.value, 0, "initial value"); assert_equals(global.valueOf(), 0, "initial valueOf"); - assert_throws(new TypeError(), () => global.value = 1); + assert_throws_js(TypeError, () => global.value = 1); assert_equals(global.value, 0, "post-set value"); assert_equals(global.valueOf(), 0, "post-set valueOf"); }, `Immutable ${type} (${name})`); + + test(t => { + opts.value = type; + const global = new WebAssembly.Global(opts); + assert_equals(global.value, 0, "initial value"); + assert_equals(global.valueOf(), 0, "initial valueOf"); + + const value = { + valueOf: t.unreached_func("should not call valueOf"), + toString: t.unreached_func("should not call toString"), + }; + assert_throws_js(TypeError, () => global.value = value); + + assert_equals(global.value, 0, "post-set value"); + assert_equals(global.valueOf(), 0, "post-set valueOf"); + }, `Immutable ${type} with ToNumber side-effects (${name})`); } const mutableOptions = [ @@ -75,11 +91,20 @@ for (const type of ["i32", "f32", "f64"]) { test(() => { const argument = { "value": "i64", "mutable": true }; const global = new WebAssembly.Global(argument); - assert_throws(new TypeError(), () => global.value); - assert_throws(new TypeError(), () => global.value = 0); - assert_throws(new TypeError(), () => global.valueOf()); + assert_throws_js(TypeError, () => global.value); + assert_throws_js(TypeError, () => global.value = 0); + assert_throws_js(TypeError, () => global.valueOf()); }, "i64 with default"); +test(t => { + const argument = { "value": "i64", "mutable": true }; + const global = new WebAssembly.Global(argument); + const value = { + valueOf: t.unreached_func("should not call valueOf"), + toString: t.unreached_func("should not call toString"), + }; + assert_throws_js(TypeError, () => global.value = value); +}, "i64 with ToNumber side-effects"); test(() => { const argument = { "value": "i32", "mutable": true }; @@ -90,7 +115,7 @@ test(() => { const setter = desc.set; assert_equals(typeof setter, "function"); - assert_throws(new TypeError(), () => setter.call(global)); + assert_throws_js(TypeError, () => setter.call(global)); }, "Calling setter without argument"); test(() => { diff --git a/test/js-api/global/valueOf.any.js b/test/js-api/global/valueOf.any.js index d4a84b254f..0695a5a61f 100644 --- a/test/js-api/global/valueOf.any.js +++ b/test/js-api/global/valueOf.any.js @@ -1,4 +1,4 @@ -// META: global=jsshell +// META: global=window,dedicatedworker,jsshell test(() => { const argument = { "value": "i32" }; @@ -17,7 +17,7 @@ test(() => { const fn = WebAssembly.Global.prototype.valueOf; for (const thisValue of thisValues) { - assert_throws(new TypeError(), () => fn.call(thisValue), `this=${format_value(thisValue)}`); + assert_throws_js(TypeError, () => fn.call(thisValue), `this=${format_value(thisValue)}`); } }, "Branding"); diff --git a/test/js-api/instance/constructor-bad-imports.any.js b/test/js-api/instance/constructor-bad-imports.any.js index b90ada2528..e4a5abb8eb 100644 --- a/test/js-api/instance/constructor-bad-imports.any.js +++ b/test/js-api/instance/constructor-bad-imports.any.js @@ -1,4 +1,4 @@ -// META: global=jsshell +// META: global=window,dedicatedworker,jsshell // META: script=/wasm/jsapi/wasm-module-builder.js // META: script=/wasm/jsapi/bad-imports.js @@ -8,6 +8,6 @@ test_bad_imports((name, error, build, ...arguments) => { build(builder); const buffer = builder.toBuffer(); const module = new WebAssembly.Module(buffer); - assert_throws(error, () => new WebAssembly.Instance(module, ...arguments)); + assert_throws_js(error, () => new WebAssembly.Instance(module, ...arguments)); }, `new WebAssembly.Instance(module): ${name}`); }); diff --git a/test/js-api/instance/constructor-caching.any.js b/test/js-api/instance/constructor-caching.any.js new file mode 100644 index 0000000000..1aa4739b62 --- /dev/null +++ b/test/js-api/instance/constructor-caching.any.js @@ -0,0 +1,54 @@ +// META: global=window,dedicatedworker,jsshell +// META: script=/wasm/jsapi/wasm-module-builder.js + +function getExports() { + const builder = new WasmModuleBuilder(); + builder + .addFunction("fn", kSig_v_d) + .addBody([]) + .exportFunc(); + + builder.setTableBounds(1); + builder.addExportOfKind("table", kExternalTable, 0); + builder.addGlobal(kWasmI32, false).exportAs("global"); + builder.addMemory(4, 8, true); + + const buffer = builder.toBuffer(); + const module = new WebAssembly.Module(buffer); + const instance = new WebAssembly.Instance(module); + return instance.exports; +} + +test(() => { + const exports = getExports(); + + const builder = new WasmModuleBuilder(); + const functionIndex = builder.addImport("module", "imported", kSig_v_d); + builder.addExport("exportedFunction", functionIndex); + + const globalIndex = builder.addImportedGlobal("module", "global", kWasmI32); + builder.addExportOfKind("exportedGlobal", kExternalGlobal, globalIndex); + + builder.addImportedMemory("module", "memory", 4); + builder.exportMemoryAs("exportedMemory"); + + const tableIndex = builder.addImportedTable("module", "table", 1); + builder.addExportOfKind("exportedTable", kExternalTable, tableIndex); + + const buffer = builder.toBuffer(); + + const module = new WebAssembly.Module(buffer); + const instance = new WebAssembly.Instance(module, { + "module": { + "imported": exports.fn, + "global": exports.global, + "memory": exports.memory, + "table": exports.table, + } + }); + + assert_equals(instance.exports.exportedFunction, exports.fn); + assert_equals(instance.exports.exportedGlobal, exports.global); + assert_equals(instance.exports.exportedMemory, exports.memory); + assert_equals(instance.exports.exportedTable, exports.table); +}); diff --git a/test/js-api/instance/constructor.any.js b/test/js-api/instance/constructor.any.js index 1ce4de904e..26390ebd2c 100644 --- a/test/js-api/instance/constructor.any.js +++ b/test/js-api/instance/constructor.any.js @@ -1,4 +1,4 @@ -// META: global=jsshell +// META: global=window,dedicatedworker,jsshell // META: script=/wasm/jsapi/wasm-module-builder.js // META: script=/wasm/jsapi/assertions.js // META: script=/wasm/jsapi/instanceTestFactory.js @@ -17,7 +17,7 @@ test(() => { }, "length"); test(() => { - assert_throws(new TypeError(), () => new WebAssembly.Instance()); + assert_throws_js(TypeError, () => new WebAssembly.Instance()); }, "No arguments"); test(() => { @@ -33,14 +33,14 @@ test(() => { WebAssembly.Module.prototype, ]; for (const argument of invalidArguments) { - assert_throws(new TypeError(), () => new WebAssembly.Instance(argument), - `new Instance(${format_value(argument)})`); + assert_throws_js(TypeError, () => new WebAssembly.Instance(argument), + `new Instance(${format_value(argument)})`); } }, "Non-Module arguments"); test(() => { const module = new WebAssembly.Module(emptyModuleBinary); - assert_throws(new TypeError(), () => WebAssembly.Instance(module)); + assert_throws_js(TypeError, () => WebAssembly.Instance(module)); }, "Calling"); for (const [name, fn] of instanceTestFactory) { diff --git a/test/js-api/instance/exports.any.js b/test/js-api/instance/exports.any.js index 2ba57c5e2f..6dcfbcee95 100644 --- a/test/js-api/instance/exports.any.js +++ b/test/js-api/instance/exports.any.js @@ -1,4 +1,4 @@ -// META: global=jsshell +// META: global=window,dedicatedworker,jsshell // META: script=/wasm/jsapi/wasm-module-builder.js let emptyModuleBinary; @@ -28,7 +28,7 @@ test(() => { assert_equals(typeof desc.set, "undefined"); for (const thisValue of thisValues) { - assert_throws(new TypeError(), () => getter.call(thisValue), `this=${format_value(thisValue)}`); + assert_throws_js(TypeError, () => getter.call(thisValue), `this=${format_value(thisValue)}`); } }, "Branding"); @@ -58,7 +58,7 @@ test(() => { const module = new WebAssembly.Module(emptyModuleBinary); const instance = new WebAssembly.Instance(module); const exports = instance.exports; - assert_throws(new TypeError(), () => { + assert_throws_js(TypeError, () => { "use strict"; instance.exports = {}; }); diff --git a/test/js-api/instance/toString.any.js b/test/js-api/instance/toString.any.js index ccd665eb28..547a9ca829 100644 --- a/test/js-api/instance/toString.any.js +++ b/test/js-api/instance/toString.any.js @@ -1,4 +1,4 @@ -// META: global=jsshell +// META: global=window,dedicatedworker,jsshell // META: script=/wasm/jsapi/wasm-module-builder.js test(() => { @@ -7,3 +7,13 @@ test(() => { const instance = new WebAssembly.Instance(module); assert_class_string(instance, "WebAssembly.Instance"); }, "Object.prototype.toString on an Instance"); + +test(() => { + assert_own_property(WebAssembly.Instance.prototype, Symbol.toStringTag); + + const propDesc = Object.getOwnPropertyDescriptor(WebAssembly.Instance.prototype, Symbol.toStringTag); + assert_equals(propDesc.value, "WebAssembly.Instance", "value"); + assert_equals(propDesc.configurable, true, "configurable"); + assert_equals(propDesc.enumerable, false, "enumerable"); + assert_equals(propDesc.writable, false, "writable"); +}, "@@toStringTag exists on the prototype with the appropriate descriptor"); diff --git a/test/js-api/instanceTestFactory.js b/test/js-api/instanceTestFactory.js index 7ccf06c234..c81672f208 100644 --- a/test/js-api/instanceTestFactory.js +++ b/test/js-api/instanceTestFactory.js @@ -183,7 +183,7 @@ const instanceTestFactory = [ builder .addFunction("fn", kSig_i_v) .addBody([ - kExprGetGlobal, + kExprGlobalGet, index, kExprReturn, ]) diff --git a/test/js-api/interface.any.js b/test/js-api/interface.any.js index 98c4a1d781..4551e6e6e3 100644 --- a/test/js-api/interface.any.js +++ b/test/js-api/interface.any.js @@ -1,4 +1,4 @@ -// META: global=jsshell +// META: global=window,dedicatedworker,jsshell // META: script=/wasm/jsapi/assertions.js function test_operations(object, object_name, operations) { @@ -63,11 +63,11 @@ test(() => { }, "WebAssembly: property descriptor"); test(() => { - assert_throws(new TypeError(), () => WebAssembly()); + assert_throws_js(TypeError, () => WebAssembly()); }, "WebAssembly: calling"); test(() => { - assert_throws(new TypeError(), () => new WebAssembly()); + assert_throws_js(TypeError, () => new WebAssembly()); }, "WebAssembly: constructing"); const interfaces = [ diff --git a/test/js-api/limits.any.js b/test/js-api/limits.any.js index a2c33bdf54..d49a51eb1d 100644 --- a/test/js-api/limits.any.js +++ b/test/js-api/limits.any.js @@ -9,8 +9,7 @@ const kJSEmbeddingMaxExports = 100000; const kJSEmbeddingMaxGlobals = 1000000; const kJSEmbeddingMaxDataSegments = 100000; -const kJSEmbeddingMaxInitialMemoryPages = 32767; -const kJSEmbeddingMaxMaximumMemoryPages = 65536; +const kJSEmbeddingMaxMemoryPages = 65536; const kJSEmbeddingMaxModuleSize = 1024 * 1024 * 1024; // = 1 GiB const kJSEmbeddingMaxFunctionSize = 7654321; const kJSEmbeddingMaxFunctionLocals = 50000; @@ -110,22 +109,22 @@ testLimit("data segments", 1, kJSEmbeddingMaxDataSegments, (builder, count) => { } }); -testLimit("initial declared memory pages", 1, kJSEmbeddingMaxInitialMemoryPages, +testLimit("initial declared memory pages", 1, kJSEmbeddingMaxMemoryPages, (builder, count) => { builder.addMemory(count, undefined, false, false); }); -testLimit("maximum declared memory pages", 1, kJSEmbeddingMaxMaximumMemoryPages, +testLimit("maximum declared memory pages", 1, kJSEmbeddingMaxMemoryPages, (builder, count) => { builder.addMemory(1, count, false, false); }); -testLimit("initial imported memory pages", 1, kJSEmbeddingMaxInitialMemoryPages, +testLimit("initial imported memory pages", 1, kJSEmbeddingMaxMemoryPages, (builder, count) => { builder.addImportedMemory("mod", "mem", count, undefined); }); -testLimit("maximum imported memory pages", 1, kJSEmbeddingMaxMaximumMemoryPages, +testLimit("maximum imported memory pages", 1, kJSEmbeddingMaxMemoryPages, (builder, count) => { builder.addImportedMemory("mod", "mem", 1, count); }); diff --git a/test/js-api/memory/assertions.js b/test/js-api/memory/assertions.js new file mode 100644 index 0000000000..b539513adc --- /dev/null +++ b/test/js-api/memory/assertions.js @@ -0,0 +1,38 @@ +function assert_ArrayBuffer(actual, { size=0, shared=false, detached=false }, message) { + // https://github.com/WebAssembly/spec/issues/840 + // See https://github.com/whatwg/html/issues/5380 for why not `self.SharedArrayBuffer` + const isShared = !("isView" in actual.constructor); + assert_equals(isShared, shared, `${message}: constructor`); + const sharedString = shared ? "Shared" : ""; + assert_equals(actual.toString(), `[object ${sharedString}ArrayBuffer]`, `${message}: toString()`); + assert_equals(Object.getPrototypeOf(actual).toString(), `[object ${sharedString}ArrayBuffer]`, `${message}: prototype toString()`); + if (detached) { + // https://github.com/tc39/ecma262/issues/678 + let byteLength; + try { + byteLength = actual.byteLength; + } catch (e) { + byteLength = 0; + } + assert_equals(byteLength, 0, `${message}: detached size`); + } else { + assert_equals(actual.byteLength, 0x10000 * size, `${message}: size`); + if (size > 0) { + const array = new Uint8Array(actual); + assert_equals(array[0], 0, `${message}: first element`); + assert_equals(array[array.byteLength - 1], 0, `${message}: last element`); + } + } + assert_equals(Object.isFrozen(actual), shared, "buffer frozen"); + assert_equals(Object.isExtensible(actual), !shared, "buffer extensibility"); +} + +function assert_Memory(memory, { size=0, shared=false }) { + assert_equals(Object.getPrototypeOf(memory), WebAssembly.Memory.prototype, + "prototype"); + assert_true(Object.isExtensible(memory), "extensible"); + + // https://github.com/WebAssembly/spec/issues/840 + assert_equals(memory.buffer, memory.buffer, "buffer should be idempotent"); + assert_ArrayBuffer(memory.buffer, { size, shared }); +} diff --git a/test/js-api/memory/buffer.any.js b/test/js-api/memory/buffer.any.js index 4788ffcf84..fb1d1200b8 100644 --- a/test/js-api/memory/buffer.any.js +++ b/test/js-api/memory/buffer.any.js @@ -1,4 +1,4 @@ -// META: global=jsshell +// META: global=window,dedicatedworker,jsshell test(() => { const thisValues = [ @@ -22,7 +22,7 @@ test(() => { assert_equals(typeof desc.set, "undefined"); for (const thisValue of thisValues) { - assert_throws(new TypeError(), () => getter.call(thisValue), `this=${format_value(thisValue)}`); + assert_throws_js(TypeError, () => getter.call(thisValue), `this=${format_value(thisValue)}`); } }, "Branding"); @@ -56,7 +56,7 @@ test(() => { const memory2 = new WebAssembly.Memory(argument); const buffer = memory.buffer; assert_not_equals(buffer, memory2.buffer, "Need two distinct buffers"); - assert_throws(new TypeError(), () => { + assert_throws_js(TypeError, () => { "use strict"; memory.buffer = memory2.buffer; }); diff --git a/test/js-api/memory/constructor.any.js b/test/js-api/memory/constructor.any.js index 11e309fe65..6524c8acc4 100644 --- a/test/js-api/memory/constructor.any.js +++ b/test/js-api/memory/constructor.any.js @@ -1,23 +1,6 @@ -// META: global=jsshell +// META: global=window,dedicatedworker,jsshell // META: script=/wasm/jsapi/assertions.js - -function assert_Memory(memory, expected) { - assert_equals(Object.getPrototypeOf(memory), WebAssembly.Memory.prototype, - "prototype"); - assert_true(Object.isExtensible(memory), "extensible"); - - // https://github.com/WebAssembly/spec/issues/840 - assert_equals(memory.buffer, memory.buffer, "buffer should be idempotent"); - assert_equals(Object.getPrototypeOf(memory.buffer), ArrayBuffer.prototype, - "prototype of buffer"); - assert_true(Object.isExtensible(memory.buffer), "buffer extensibility"); - assert_equals(memory.buffer.byteLength, 0x10000 * expected.size, "size of buffer"); - if (expected.size > 0) { - const array = new Uint8Array(memory.buffer); - assert_equals(array[0], 0, "first element of buffer"); - assert_equals(array[array.byteLength - 1], 0, "last element of buffer"); - } -} +// META: script=/wasm/jsapi/memory/assertions.js test(() => { assert_function_name(WebAssembly.Memory, "Memory", "WebAssembly.Memory"); @@ -28,12 +11,12 @@ test(() => { }, "length"); test(() => { - assert_throws(new TypeError(), () => new WebAssembly.Memory()); + assert_throws_js(TypeError, () => new WebAssembly.Memory()); }, "No arguments"); test(() => { const argument = { "initial": 0 }; - assert_throws(new TypeError(), () => WebAssembly.Memory(argument)); + assert_throws_js(TypeError, () => WebAssembly.Memory(argument)); }, "Calling"); test(() => { @@ -50,14 +33,14 @@ test(() => { {}, ]; for (const invalidArgument of invalidArguments) { - assert_throws(new TypeError(), - () => new WebAssembly.Memory(invalidArgument), - `new Memory(${format_value(invalidArgument)})`); + assert_throws_js(TypeError, + () => new WebAssembly.Memory(invalidArgument), + `new Memory(${format_value(invalidArgument)})`); } }, "Invalid descriptor argument"); test(() => { - assert_throws(new TypeError(), () => new WebAssembly.Memory({ "initial": undefined })); + assert_throws_js(TypeError, () => new WebAssembly.Memory({ "initial": undefined })); }, "Undefined initial value in descriptor"); const outOfRangeValues = [ @@ -71,16 +54,16 @@ const outOfRangeValues = [ for (const value of outOfRangeValues) { test(() => { - assert_throws(new TypeError(), () => new WebAssembly.Memory({ "initial": value })); + assert_throws_js(TypeError, () => new WebAssembly.Memory({ "initial": value })); }, `Out-of-range initial value in descriptor: ${format_value(value)}`); test(() => { - assert_throws(new TypeError(), () => new WebAssembly.Memory({ "initial": 0, "maximum": value })); + assert_throws_js(TypeError, () => new WebAssembly.Memory({ "initial": 0, "maximum": value })); }, `Out-of-range maximum value in descriptor: ${format_value(value)}`); } test(() => { - assert_throws(new RangeError(), () => new WebAssembly.Memory({ "initial": 10, "maximum": 9 })); + assert_throws_js(RangeError, () => new WebAssembly.Memory({ "initial": 10, "maximum": 9 })); }, "Initial value exceeds maximum"); test(() => { diff --git a/test/js-api/memory/grow.any.js b/test/js-api/memory/grow.any.js index 1ccfb94675..c511129491 100644 --- a/test/js-api/memory/grow.any.js +++ b/test/js-api/memory/grow.any.js @@ -1,32 +1,10 @@ -// META: global=jsshell - -function assert_ArrayBuffer(actual, expected, message) { - // https://github.com/WebAssembly/spec/issues/840 - assert_equals(Object.getPrototypeOf(actual), ArrayBuffer.prototype, - `${message}: prototype`); - if (expected.detached) { - // https://github.com/tc39/ecma262/issues/678 - let byteLength; - try { - byteLength = actual.byteLength; - } catch (e) { - byteLength = 0; - } - assert_equals(byteLength, 0, `${message}: detached size`); - } else { - assert_equals(actual.byteLength, 0x10000 * expected.size, `${message}: size`); - if (expected.size > 0) { - const array = new Uint8Array(actual); - assert_equals(array[0], 0, `${message}: first element`); - assert_equals(array[array.byteLength - 1], 0, `${message}: last element`); - } - } -} +// META: global=window,dedicatedworker,jsshell +// META: script=/wasm/jsapi/memory/assertions.js test(() => { const argument = { "initial": 0 }; const memory = new WebAssembly.Memory(argument); - assert_throws(new TypeError(), () => memory.grow()); + assert_throws_js(TypeError, () => memory.grow()); }, "Missing arguments"); test(t => { @@ -50,7 +28,7 @@ test(t => { const fn = WebAssembly.Memory.prototype.grow; for (const thisValue of thisValues) { - assert_throws(new TypeError(), () => fn.call(thisValue, argument), `this=${format_value(thisValue)}`); + assert_throws_js(TypeError, () => fn.call(thisValue, argument), `this=${format_value(thisValue)}`); } }, "Branding"); @@ -144,7 +122,7 @@ test(() => { const oldMemory = memory.buffer; assert_ArrayBuffer(oldMemory, { "size": 1 }, "Buffer before growing"); - assert_throws(new RangeError(), () => memory.grow(2)); + assert_throws_js(RangeError, () => memory.grow(2)); assert_equals(memory.buffer, oldMemory); assert_ArrayBuffer(memory.buffer, { "size": 1 }, "Buffer before trying to grow"); }, "Zero initial growing too much"); @@ -165,7 +143,7 @@ for (const value of outOfRangeValues) { test(() => { const argument = { "initial": 0 }; const memory = new WebAssembly.Memory(argument); - assert_throws(new TypeError(), () => memory.grow(value)); + assert_throws_js(TypeError, () => memory.grow(value)); }, `Out-of-range argument: ${format_value(value)}`); } @@ -183,3 +161,29 @@ test(() => { assert_ArrayBuffer(oldMemory, { "detached": true }, "Old buffer after growing"); assert_ArrayBuffer(newMemory, { "size": 2 }, "New buffer after growing"); }, "Stray argument"); + +test(() => { + const argument = { "initial": 1, "maximum": 2, "shared": true }; + const memory = new WebAssembly.Memory(argument); + const oldMemory = memory.buffer; + assert_ArrayBuffer(oldMemory, { "size": 1, "shared": true }, "Buffer before growing"); + + const result = memory.grow(1); + assert_equals(result, 1); + + const newMemory = memory.buffer; + assert_not_equals(oldMemory, newMemory); + assert_ArrayBuffer(oldMemory, { "size": 1, "shared": true }, "Old buffer after growing"); + assert_ArrayBuffer(newMemory, { "size": 2, "shared": true }, "New buffer after growing"); + + // The old and new buffers must have the same value for the + // [[ArrayBufferData]] internal slot. + const oldArray = new Uint8Array(oldMemory); + const newArray = new Uint8Array(newMemory); + assert_equals(oldArray[0], 0, "old first element"); + assert_equals(newArray[0], 0, "new first element"); + oldArray[0] = 1; + assert_equals(oldArray[0], 1, "old first element"); + assert_equals(newArray[0], 1, "new first element"); + +}, "Growing shared memory does not detach old buffer"); diff --git a/test/js-api/memory/toString.any.js b/test/js-api/memory/toString.any.js index 4e15d75ea2..f4059f7657 100644 --- a/test/js-api/memory/toString.any.js +++ b/test/js-api/memory/toString.any.js @@ -1,7 +1,17 @@ -// META: global=jsshell +// META: global=window,dedicatedworker,jsshell test(() => { const argument = { "initial": 0 }; const memory = new WebAssembly.Memory(argument); assert_class_string(memory, "WebAssembly.Memory"); }, "Object.prototype.toString on an Memory"); + +test(() => { + assert_own_property(WebAssembly.Memory.prototype, Symbol.toStringTag); + + const propDesc = Object.getOwnPropertyDescriptor(WebAssembly.Memory.prototype, Symbol.toStringTag); + assert_equals(propDesc.value, "WebAssembly.Memory", "value"); + assert_equals(propDesc.configurable, true, "configurable"); + assert_equals(propDesc.enumerable, false, "enumerable"); + assert_equals(propDesc.writable, false, "writable"); +}, "@@toStringTag exists on the prototype with the appropriate descriptor"); diff --git a/test/js-api/module/constructor.any.js b/test/js-api/module/constructor.any.js index 1d01ea5b62..9978f7e6ac 100644 --- a/test/js-api/module/constructor.any.js +++ b/test/js-api/module/constructor.any.js @@ -1,4 +1,4 @@ -// META: global=jsshell +// META: global=window,dedicatedworker,jsshell // META: script=/wasm/jsapi/wasm-module-builder.js // META: script=/wasm/jsapi/assertions.js @@ -16,11 +16,11 @@ test(() => { }, "length"); test(() => { - assert_throws(new TypeError(), () => new WebAssembly.Module()); + assert_throws_js(TypeError, () => new WebAssembly.Module()); }, "No arguments"); test(() => { - assert_throws(new TypeError(), () => WebAssembly.Module(emptyModuleBinary)); + assert_throws_js(TypeError, () => WebAssembly.Module(emptyModuleBinary)); }, "Calling"); test(() => { @@ -38,16 +38,21 @@ test(() => { Array.from(emptyModuleBinary), ]; for (const argument of invalidArguments) { - assert_throws(new TypeError(), () => new WebAssembly.Module(argument), - `new Module(${format_value(argument)})`); + assert_throws_js(TypeError, () => new WebAssembly.Module(argument), + `new Module(${format_value(argument)})`); } }, "Invalid arguments"); test(() => { const buffer = new Uint8Array(); - assert_throws(new WebAssembly.CompileError(), () => new WebAssembly.Module(buffer)); + assert_throws_js(WebAssembly.CompileError, () => new WebAssembly.Module(buffer)); }, "Empty buffer"); +test(() => { + const buffer = new Uint8Array(Array.from(emptyModuleBinary).concat([0, 0])); + assert_throws_js(WebAssembly.CompileError, () => new WebAssembly.Module(buffer)); +}, "Invalid code"); + test(() => { const module = new WebAssembly.Module(emptyModuleBinary); assert_equals(Object.getPrototypeOf(module), WebAssembly.Module.prototype); diff --git a/test/js-api/module/customSections.any.js b/test/js-api/module/customSections.any.js index 8e9732e551..4029877e92 100644 --- a/test/js-api/module/customSections.any.js +++ b/test/js-api/module/customSections.any.js @@ -1,4 +1,4 @@ -// META: global=jsshell +// META: global=window,dedicatedworker,jsshell // META: script=/wasm/jsapi/wasm-module-builder.js function assert_ArrayBuffer(buffer, expected) { @@ -24,9 +24,9 @@ setup(() => { }); test(() => { - assert_throws(new TypeError(), () => WebAssembly.Module.customSections()); + assert_throws_js(TypeError, () => WebAssembly.Module.customSections()); const module = new WebAssembly.Module(emptyModuleBinary); - assert_throws(new TypeError(), () => WebAssembly.Module.customSections(module)); + assert_throws_js(TypeError, () => WebAssembly.Module.customSections(module)); }, "Missing arguments"); test(() => { @@ -42,8 +42,8 @@ test(() => { WebAssembly.Module.prototype, ]; for (const argument of invalidArguments) { - assert_throws(new TypeError(), () => WebAssembly.Module.customSections(argument, ""), - `customSections(${format_value(argument)})`); + assert_throws_js(TypeError, () => WebAssembly.Module.customSections(argument, ""), + `customSections(${format_value(argument)})`); } }, "Non-Module arguments"); @@ -81,22 +81,10 @@ test(() => { const bytes1 = [87, 101, 98, 65, 115, 115, 101, 109, 98, 108, 121]; const bytes2 = [74, 83, 65, 80, 73]; - const binary = new Binary; - binary.emit_section(kUnknownSectionCode, section => { - section.emit_string("name"); - section.emit_bytes(bytes1); - }); - binary.emit_section(kUnknownSectionCode, section => { - section.emit_string("name"); - section.emit_bytes(bytes2); - }); - binary.emit_section(kUnknownSectionCode, section => { - section.emit_string("foo"); - section.emit_bytes(bytes1); - }); - const builder = new WasmModuleBuilder(); - builder.addExplicitSection(binary.trunc_buffer()); + builder.addCustomSection("name", bytes1); + builder.addCustomSection("name", bytes2); + builder.addCustomSection("foo", bytes1); const buffer = builder.toBuffer() const module = new WebAssembly.Module(buffer); @@ -119,14 +107,8 @@ test(() => { const bytes = [87, 101, 98, 65, 115, 115, 101, 109, 98, 108, 121]; const name = "yee\uD801\uDC37eey" - const binary = new Binary; - binary.emit_section(kUnknownSectionCode, section => { - section.emit_string(name); - section.emit_bytes(bytes); - }); - const builder = new WasmModuleBuilder(); - builder.addExplicitSection(binary.trunc_buffer()); + builder.addCustomSection(name, bytes); const buffer = builder.toBuffer(); const module = new WebAssembly.Module(buffer); @@ -140,14 +122,8 @@ test(() => { test(() => { const bytes = [87, 101, 98, 65, 115, 115, 101, 109, 98, 108, 121]; - const binary = new Binary; - binary.emit_section(kUnknownSectionCode, section => { - section.emit_string("na\uFFFDme"); - section.emit_bytes(bytes); - }); - const builder = new WasmModuleBuilder(); - builder.addExplicitSection(binary.trunc_buffer()); + builder.addCustomSection("na\uFFFDme", bytes); const buffer = builder.toBuffer(); const module = new WebAssembly.Module(buffer); diff --git a/test/js-api/module/exports.any.js b/test/js-api/module/exports.any.js index eadfc84f1e..60b2c04f43 100644 --- a/test/js-api/module/exports.any.js +++ b/test/js-api/module/exports.any.js @@ -1,4 +1,4 @@ -// META: global=jsshell +// META: global=window,dedicatedworker,jsshell // META: script=/wasm/jsapi/wasm-module-builder.js let emptyModuleBinary; @@ -35,7 +35,7 @@ function assert_exports(exports, expected) { } test(() => { - assert_throws(new TypeError(), () => WebAssembly.Module.exports()); + assert_throws_js(TypeError, () => WebAssembly.Module.exports()); }, "Missing arguments"); test(() => { @@ -51,8 +51,8 @@ test(() => { WebAssembly.Module.prototype, ]; for (const argument of invalidArguments) { - assert_throws(new TypeError(), () => WebAssembly.Module.exports(argument), - `exports(${format_value(argument)})`); + assert_throws_js(TypeError, () => WebAssembly.Module.exports(argument), + `exports(${format_value(argument)})`); } }, "Non-Module arguments"); diff --git a/test/js-api/module/imports.any.js b/test/js-api/module/imports.any.js index 9d7ef2f0a9..d6754c9efb 100644 --- a/test/js-api/module/imports.any.js +++ b/test/js-api/module/imports.any.js @@ -1,4 +1,4 @@ -// META: global=jsshell +// META: global=window,dedicatedworker,jsshell // META: script=/wasm/jsapi/wasm-module-builder.js function assert_ModuleImportDescriptor(import_, expected) { @@ -41,7 +41,7 @@ setup(() => { }); test(() => { - assert_throws(new TypeError(), () => WebAssembly.Module.imports()); + assert_throws_js(TypeError, () => WebAssembly.Module.imports()); }, "Missing arguments"); test(() => { @@ -57,8 +57,8 @@ test(() => { WebAssembly.Module.prototype, ]; for (const argument of invalidArguments) { - assert_throws(new TypeError(), () => WebAssembly.Module.imports(argument), - `imports(${format_value(argument)})`); + assert_throws_js(TypeError, () => WebAssembly.Module.imports(argument), + `imports(${format_value(argument)})`); } }, "Non-Module arguments"); diff --git a/test/js-api/module/toString.any.js b/test/js-api/module/toString.any.js index 2db2002ffd..1c20cd6108 100644 --- a/test/js-api/module/toString.any.js +++ b/test/js-api/module/toString.any.js @@ -1,4 +1,4 @@ -// META: global=jsshell +// META: global=window,dedicatedworker,jsshell // META: script=/wasm/jsapi/wasm-module-builder.js test(() => { @@ -6,3 +6,13 @@ test(() => { const module = new WebAssembly.Module(emptyModuleBinary); assert_class_string(module, "WebAssembly.Module"); }, "Object.prototype.toString on an Module"); + +test(() => { + assert_own_property(WebAssembly.Module.prototype, Symbol.toStringTag); + + const propDesc = Object.getOwnPropertyDescriptor(WebAssembly.Module.prototype, Symbol.toStringTag); + assert_equals(propDesc.value, "WebAssembly.Module", "value"); + assert_equals(propDesc.configurable, true, "configurable"); + assert_equals(propDesc.enumerable, false, "enumerable"); + assert_equals(propDesc.writable, false, "writable"); +}, "@@toStringTag exists on the prototype with the appropriate descriptor"); diff --git a/test/js-api/prototypes.any.js b/test/js-api/prototypes.any.js new file mode 100644 index 0000000000..714f4f8430 --- /dev/null +++ b/test/js-api/prototypes.any.js @@ -0,0 +1,43 @@ +// META: global=window,dedicatedworker,jsshell +// META: script=/wasm/jsapi/assertions.js +// META: script=/wasm/jsapi/wasm-module-builder.js + +let emptyModuleBinary; +setup(() => { + emptyModuleBinary = new WasmModuleBuilder().toBuffer(); +}); + +test(() => { + class _Module extends WebAssembly.Module {} + let module = new _Module(emptyModuleBinary); + assert_true(module instanceof _Module, "_Module instanceof _Module"); + assert_true(module instanceof WebAssembly.Module, "_Module instanceof WebAssembly.Module"); +}, "_Module"); + +test(() => { + class _Instance extends WebAssembly.Instance {} + let instance = new _Instance(new WebAssembly.Module(emptyModuleBinary)); + assert_true(instance instanceof _Instance, "_Instance instanceof _Instance"); + assert_true(instance instanceof WebAssembly.Instance, "_Instance instanceof WebAssembly.Instance"); +}, "_Instance"); + +test(() => { + class _Memory extends WebAssembly.Memory {} + let memory = new _Memory({initial: 0, maximum: 1}); + assert_true(memory instanceof _Memory, "_Memory instanceof _Memory"); + assert_true(memory instanceof WebAssembly.Memory, "_Memory instanceof WebAssembly.Memory"); +}, "_Memory"); + +test(() => { + class _Table extends WebAssembly.Table {} + let table = new _Table({initial: 0, element: "anyfunc"}); + assert_true(table instanceof _Table, "_Table instanceof _Table"); + assert_true(table instanceof WebAssembly.Table, "_Table instanceof WebAssembly.Table"); +}, "_Table"); + +test(() => { + class _Global extends WebAssembly.Global {} + let global = new _Global({value: "i32", mutable: false}, 0); + assert_true(global instanceof _Global, "_Global instanceof _Global"); + assert_true(global instanceof WebAssembly.Global, "_Global instanceof WebAssembly.Global"); +}, "_Global"); diff --git a/test/js-api/table/assertions.js b/test/js-api/table/assertions.js index c88972b4eb..b1aeaf1a65 100644 --- a/test/js-api/table/assertions.js +++ b/test/js-api/table/assertions.js @@ -2,12 +2,12 @@ function assert_equal_to_array(table, expected, message) { assert_equals(table.length, expected.length, `${message}: length`); // The argument check in get() happens before the range check, and negative numbers // are illegal, hence will throw TypeError per spec. - assert_throws(new TypeError(), () => table.get(-1), `${message}: table.get(-1)`); + assert_throws_js(TypeError, () => table.get(-1), `${message}: table.get(-1)`); for (let i = 0; i < expected.length; ++i) { assert_equals(table.get(i), expected[i], `${message}: table.get(${i} of ${expected.length})`); } - assert_throws(new RangeError(), () => table.get(expected.length), - `${message}: table.get(${expected.length} of ${expected.length})`); - assert_throws(new RangeError(), () => table.get(expected.length + 1), - `${message}: table.get(${expected.length + 1} of ${expected.length})`); + assert_throws_js(RangeError, () => table.get(expected.length), + `${message}: table.get(${expected.length} of ${expected.length})`); + assert_throws_js(RangeError, () => table.get(expected.length + 1), + `${message}: table.get(${expected.length + 1} of ${expected.length})`); } diff --git a/test/js-api/table/constructor.any.js b/test/js-api/table/constructor.any.js index 99eee19fec..e9e77a132b 100644 --- a/test/js-api/table/constructor.any.js +++ b/test/js-api/table/constructor.any.js @@ -1,4 +1,4 @@ -// META: global=jsshell +// META: global=window,dedicatedworker,jsshell // META: script=/wasm/jsapi/assertions.js function assert_Table(actual, expected) { @@ -21,16 +21,16 @@ test(() => { }, "length"); test(() => { - assert_throws(new TypeError(), () => new WebAssembly.Table()); + assert_throws_js(TypeError, () => new WebAssembly.Table()); }, "No arguments"); test(() => { const argument = { "element": "anyfunc", "initial": 0 }; - assert_throws(new TypeError(), () => WebAssembly.Table(argument)); + assert_throws_js(TypeError, () => WebAssembly.Table(argument)); }, "Calling"); test(() => { - assert_throws(new TypeError(), () => new WebAssembly.Table({})); + assert_throws_js(TypeError, () => new WebAssembly.Table({})); }, "Empty descriptor"); test(() => { @@ -47,18 +47,18 @@ test(() => { {}, ]; for (const invalidArgument of invalidArguments) { - assert_throws(new TypeError(), - () => new WebAssembly.Table(invalidArgument), - `new Table(${format_value(invalidArgument)})`); + assert_throws_js(TypeError, + () => new WebAssembly.Table(invalidArgument), + `new Table(${format_value(invalidArgument)})`); } }, "Invalid descriptor argument"); test(() => { - assert_throws(new TypeError(), () => new WebAssembly.Table({ "element": "anyfunc", "initial": undefined })); + assert_throws_js(TypeError, () => new WebAssembly.Table({ "element": "anyfunc", "initial": undefined })); }, "Undefined initial value in descriptor"); test(() => { - assert_throws(new TypeError(), () => new WebAssembly.Table({ "element": undefined, "initial": 0 })); + assert_throws_js(TypeError, () => new WebAssembly.Table({ "element": undefined, "initial": 0 })); }, "Undefined element value in descriptor"); const outOfRangeValues = [ @@ -72,16 +72,16 @@ const outOfRangeValues = [ for (const value of outOfRangeValues) { test(() => { - assert_throws(new TypeError(), () => new WebAssembly.Table({ "element": "anyfunc", "initial": value })); + assert_throws_js(TypeError, () => new WebAssembly.Table({ "element": "anyfunc", "initial": value })); }, `Out-of-range initial value in descriptor: ${format_value(value)}`); test(() => { - assert_throws(new TypeError(), () => new WebAssembly.Table({ "element": "anyfunc", "initial": 0, "maximum": value })); + assert_throws_js(TypeError, () => new WebAssembly.Table({ "element": "anyfunc", "initial": 0, "maximum": value })); }, `Out-of-range maximum value in descriptor: ${format_value(value)}`); } test(() => { - assert_throws(new RangeError(), () => new WebAssembly.Table({ "element": "anyfunc", "initial": 10, "maximum": 9 })); + assert_throws_js(RangeError, () => new WebAssembly.Table({ "element": "anyfunc", "initial": 10, "maximum": 9 })); }, "Initial value exceeds maximum"); test(() => { diff --git a/test/js-api/table/get-set.any.js b/test/js-api/table/get-set.any.js index 82aa88951a..2e16346c64 100644 --- a/test/js-api/table/get-set.any.js +++ b/test/js-api/table/get-set.any.js @@ -1,8 +1,8 @@ -// META: global=jsshell +// META: global=window,dedicatedworker,jsshell // META: script=/wasm/jsapi/wasm-module-builder.js // META: script=assertions.js -let functions; +let functions = {}; setup(() => { const builder = new WasmModuleBuilder(); @@ -24,7 +24,7 @@ setup(() => { test(() => { const argument = { "element": "anyfunc", "initial": 5 }; const table = new WebAssembly.Table(argument); - assert_throws(new TypeError(), () => table.get()); + assert_throws_js(TypeError, () => table.get()); }, "Missing arguments: get"); test(t => { @@ -48,15 +48,15 @@ test(t => { const fn = WebAssembly.Table.prototype.get; for (const thisValue of thisValues) { - assert_throws(new TypeError(), () => fn.call(thisValue, argument), `this=${format_value(thisValue)}`); + assert_throws_js(TypeError, () => fn.call(thisValue, argument), `this=${format_value(thisValue)}`); } }, "Branding: get"); test(() => { const argument = { "element": "anyfunc", "initial": 5 }; const table = new WebAssembly.Table(argument); - assert_throws(new TypeError(), () => table.set()); - assert_throws(new TypeError(), () => table.set(0)); + assert_throws_js(TypeError, () => table.set()); + assert_throws_js(TypeError, () => table.set(0)); }, "Missing arguments: set"); test(t => { @@ -80,7 +80,7 @@ test(t => { const fn = WebAssembly.Table.prototype.set; for (const thisValue of thisValues) { - assert_throws(new TypeError(), () => fn.call(thisValue, argument, null), `this=${format_value(thisValue)}`); + assert_throws_js(TypeError, () => fn.call(thisValue, argument, null), `this=${format_value(thisValue)}`); } }, "Branding: set"); @@ -128,8 +128,8 @@ test(() => { // -1 is the wrong type hence the type check on entry gets this // before the range check does. - assert_throws(new TypeError(), () => table.set(-1, fn)); - assert_throws(new RangeError(), () => table.set(5, fn)); + assert_throws_js(TypeError, () => table.set(-1, fn)); + assert_throws_js(RangeError, () => table.set(5, fn)); assert_equal_to_array(table, [null, null, null, null, null]); }, "Setting out-of-bounds"); @@ -149,8 +149,8 @@ test(() => { {}, ]; for (const argument of invalidArguments) { - assert_throws(new TypeError(), () => table.set(0, argument), - `set(${format_value(argument)})`); + assert_throws_js(TypeError, () => table.set(0, argument), + `set(${format_value(argument)})`); } assert_equal_to_array(table, [null]); }, "Setting non-function"); @@ -161,7 +161,7 @@ test(() => { assert_equal_to_array(table, [null]); const fn = function() {}; - assert_throws(new TypeError(), () => table.set(0, fn)); + assert_throws_js(TypeError, () => table.set(0, fn)); assert_equal_to_array(table, [null]); }, "Setting non-wasm function"); @@ -171,7 +171,7 @@ test(() => { assert_equal_to_array(table, [null]); const fn = () => {}; - assert_throws(new TypeError(), () => table.set(0, fn)); + assert_throws_js(TypeError, () => table.set(0, fn)); assert_equal_to_array(table, [null]); }, "Setting non-wasm arrow function"); @@ -191,13 +191,13 @@ for (const value of outOfRangeValues) { test(() => { const argument = { "element": "anyfunc", "initial": 1 }; const table = new WebAssembly.Table(argument); - assert_throws(new TypeError(), () => table.get(value)); + assert_throws_js(TypeError, () => table.get(value)); }, `Getting out-of-range argument: ${format_value(value)}`); test(() => { const argument = { "element": "anyfunc", "initial": 1 }; const table = new WebAssembly.Table(argument); - assert_throws(new TypeError(), () => table.set(value, null)); + assert_throws_js(TypeError, () => table.set(value, null)); }, `Setting out-of-range argument: ${format_value(value)}`); } @@ -211,7 +211,7 @@ test(() => { return 0; }, }; - assert_throws(new TypeError(), () => table.set(value, {})); + assert_throws_js(TypeError, () => table.set(value, {})); assert_equals(called, 1); }, "Order of argument conversion"); diff --git a/test/js-api/table/grow.any.js b/test/js-api/table/grow.any.js index 4978e3ca23..3b2ee5fa8e 100644 --- a/test/js-api/table/grow.any.js +++ b/test/js-api/table/grow.any.js @@ -1,4 +1,4 @@ -// META: global=jsshell +// META: global=window,dedicatedworker,jsshell // META: script=assertions.js function nulls(n) { @@ -8,7 +8,7 @@ function nulls(n) { test(() => { const argument = { "element": "anyfunc", "initial": 5 }; const table = new WebAssembly.Table(argument); - assert_throws(new TypeError(), () => table.grow()); + assert_throws_js(TypeError, () => table.grow()); }, "Missing arguments"); test(t => { @@ -32,7 +32,7 @@ test(t => { const fn = WebAssembly.Table.prototype.grow; for (const thisValue of thisValues) { - assert_throws(new TypeError(), () => fn.call(thisValue, argument), `this=${format_value(thisValue)}`); + assert_throws_js(TypeError, () => fn.call(thisValue, argument), `this=${format_value(thisValue)}`); } }, "Branding"); @@ -61,7 +61,7 @@ test(() => { const table = new WebAssembly.Table(argument); assert_equal_to_array(table, nulls(2), "before"); - assert_throws(new RangeError(), () => table.grow(4)); + assert_throws_js(RangeError, () => table.grow(4)); assert_equal_to_array(table, nulls(2), "after"); }, "Exceeded maximum"); @@ -81,7 +81,7 @@ for (const value of outOfRangeValues) { test(() => { const argument = { "element": "anyfunc", "initial": 1 }; const table = new WebAssembly.Table(argument); - assert_throws(new TypeError(), () => table.grow(value)); + assert_throws_js(TypeError, () => table.grow(value)); }, `Out-of-range argument: ${format_value(value)}`); } @@ -90,7 +90,7 @@ test(() => { const table = new WebAssembly.Table(argument); assert_equal_to_array(table, nulls(5), "before"); - const result = table.grow(3, {}); + const result = table.grow(3, null, {}); assert_equals(result, 5); assert_equal_to_array(table, nulls(8), "after"); }, "Stray argument"); diff --git a/test/js-api/table/length.any.js b/test/js-api/table/length.any.js index b1bfa6cfd1..a9ef095ded 100644 --- a/test/js-api/table/length.any.js +++ b/test/js-api/table/length.any.js @@ -1,4 +1,4 @@ -// META: global=jsshell +// META: global=window,dedicatedworker,jsshell test(() => { const thisValues = [ @@ -22,7 +22,7 @@ test(() => { assert_equals(typeof desc.set, "undefined"); for (const thisValue of thisValues) { - assert_throws(new TypeError(), () => getter.call(thisValue), `this=${format_value(thisValue)}`); + assert_throws_js(TypeError, () => getter.call(thisValue), `this=${format_value(thisValue)}`); } }, "Branding"); @@ -52,7 +52,7 @@ test(() => { const argument = { "element": "anyfunc", "initial": 2 }; const table = new WebAssembly.Table(argument); assert_equals(table.length, 2, "Initial length"); - assert_throws(new TypeError(), () => { + assert_throws_js(TypeError, () => { "use strict"; table.length = 4; }); diff --git a/test/js-api/table/toString.any.js b/test/js-api/table/toString.any.js index e576477910..8a09f2832c 100644 --- a/test/js-api/table/toString.any.js +++ b/test/js-api/table/toString.any.js @@ -1,7 +1,17 @@ -// META: global=jsshell +// META: global=window,dedicatedworker,jsshell test(() => { const argument = { "element": "anyfunc", "initial": 0 }; const table = new WebAssembly.Table(argument); assert_class_string(table, "WebAssembly.Table"); }, "Object.prototype.toString on an Table"); + +test(() => { + assert_own_property(WebAssembly.Table.prototype, Symbol.toStringTag); + + const propDesc = Object.getOwnPropertyDescriptor(WebAssembly.Table.prototype, Symbol.toStringTag); + assert_equals(propDesc.value, "WebAssembly.Table", "value"); + assert_equals(propDesc.configurable, true, "configurable"); + assert_equals(propDesc.enumerable, false, "enumerable"); + assert_equals(propDesc.writable, false, "writable"); +}, "@@toStringTag exists on the prototype with the appropriate descriptor"); diff --git a/test/js-api/wasm-module-builder.js b/test/js-api/wasm-module-builder.js index a937eed4c6..82c6e04135 100644 --- a/test/js-api/wasm-module-builder.js +++ b/test/js-api/wasm-module-builder.js @@ -66,6 +66,8 @@ let kStartSectionCode = 8; // Start function declaration let kElementSectionCode = 9; // Elements section let kCodeSectionCode = 10; // Function code let kDataSectionCode = 11; // Data segments +let kDataCountSectionCode = 12; // Data segment count (between Element & Code) +let kExceptionSectionCode = 13; // Exception section (between Global & Export) // Name section types let kModuleNameCode = 0; @@ -76,7 +78,13 @@ let kWasmFunctionTypeForm = 0x60; let kWasmAnyFunctionTypeForm = 0x70; let kHasMaximumFlag = 1; -let kResizableMaximumFlag = 1; +let kSharedHasMaximumFlag = 3; + +// Segment flags +let kActiveNoIndex = 0; +let kPassive = 1; +let kActiveWithIndex = 2; +let kPassiveWithElements = 5; // Function declaration flags let kDeclFunctionName = 0x01; @@ -91,14 +99,21 @@ let kWasmI64 = 0x7e; let kWasmF32 = 0x7d; let kWasmF64 = 0x7c; let kWasmS128 = 0x7b; +let kWasmAnyRef = 0x6f; +let kWasmAnyFunc = 0x70; +let kWasmExnRef = 0x68; let kExternalFunction = 0; let kExternalTable = 1; let kExternalMemory = 2; let kExternalGlobal = 3; +let kExternalException = 4; let kTableZero = 0; let kMemoryZero = 0; +let kSegmentZero = 0; + +let kExceptionAttribute = 0; // Useful signatures let kSig_i_i = makeSig([kWasmI32], [kWasmI32]); @@ -123,11 +138,30 @@ let kSig_v_l = makeSig([kWasmI64], []); let kSig_v_d = makeSig([kWasmF64], []); let kSig_v_dd = makeSig([kWasmF64, kWasmF64], []); let kSig_v_ddi = makeSig([kWasmF64, kWasmF64, kWasmI32], []); +let kSig_ii_v = makeSig([], [kWasmI32, kWasmI32]); +let kSig_iii_v = makeSig([], [kWasmI32, kWasmI32, kWasmI32]); +let kSig_ii_i = makeSig([kWasmI32], [kWasmI32, kWasmI32]); +let kSig_iii_i = makeSig([kWasmI32], [kWasmI32, kWasmI32, kWasmI32]); +let kSig_ii_ii = makeSig([kWasmI32, kWasmI32], [kWasmI32, kWasmI32]); +let kSig_iii_ii = makeSig([kWasmI32, kWasmI32], [kWasmI32, kWasmI32, kWasmI32]); let kSig_v_f = makeSig([kWasmF32], []); let kSig_f_f = makeSig([kWasmF32], [kWasmF32]); let kSig_f_d = makeSig([kWasmF64], [kWasmF32]); let kSig_d_d = makeSig([kWasmF64], [kWasmF64]); +let kSig_r_r = makeSig([kWasmAnyRef], [kWasmAnyRef]); +let kSig_a_a = makeSig([kWasmAnyFunc], [kWasmAnyFunc]); +let kSig_e_e = makeSig([kWasmExnRef], [kWasmExnRef]); +let kSig_i_r = makeSig([kWasmAnyRef], [kWasmI32]); +let kSig_v_r = makeSig([kWasmAnyRef], []); +let kSig_v_a = makeSig([kWasmAnyFunc], []); +let kSig_v_e = makeSig([kWasmExnRef], []); +let kSig_v_rr = makeSig([kWasmAnyRef, kWasmAnyRef], []); +let kSig_v_aa = makeSig([kWasmAnyFunc, kWasmAnyFunc], []); +let kSig_r_v = makeSig([], [kWasmAnyRef]); +let kSig_a_v = makeSig([], [kWasmAnyFunc]); +let kSig_a_i = makeSig([kWasmI32], [kWasmAnyFunc]); +let kSig_e_v = makeSig([], [kWasmExnRef]); function makeSig(params, results) { return {params: params, results: results}; @@ -163,6 +197,8 @@ let kExprElse = 0x05; let kExprTry = 0x06; let kExprCatch = 0x07; let kExprThrow = 0x08; +let kExprRethrow = 0x09; +let kExprBrOnExn = 0x0a; let kExprEnd = 0x0b; let kExprBr = 0x0c; let kExprBrIf = 0x0d; @@ -170,13 +206,17 @@ let kExprBrTable = 0x0e; let kExprReturn = 0x0f; let kExprCallFunction = 0x10; let kExprCallIndirect = 0x11; +let kExprReturnCall = 0x12; +let kExprReturnCallIndirect = 0x13; let kExprDrop = 0x1a; let kExprSelect = 0x1b; -let kExprGetLocal = 0x20; -let kExprSetLocal = 0x21; -let kExprTeeLocal = 0x22; -let kExprGetGlobal = 0x23; -let kExprSetGlobal = 0x24; +let kExprLocalGet = 0x20; +let kExprLocalSet = 0x21; +let kExprLocalTee = 0x22; +let kExprGlobalGet = 0x23; +let kExprGlobalSet = 0x24; +let kExprTableGet = 0x25; +let kExprTableSet = 0x26; let kExprI32LoadMem = 0x28; let kExprI64LoadMem = 0x29; let kExprF32LoadMem = 0x2a; @@ -329,6 +369,108 @@ let kExprI32ReinterpretF32 = 0xbc; let kExprI64ReinterpretF64 = 0xbd; let kExprF32ReinterpretI32 = 0xbe; let kExprF64ReinterpretI64 = 0xbf; +let kExprI32SExtendI8 = 0xc0; +let kExprI32SExtendI16 = 0xc1; +let kExprI64SExtendI8 = 0xc2; +let kExprI64SExtendI16 = 0xc3; +let kExprI64SExtendI32 = 0xc4; +let kExprRefNull = 0xd0; +let kExprRefIsNull = 0xd1; +let kExprRefFunc = 0xd2; + +// Prefix opcodes +let kNumericPrefix = 0xfc; +let kSimdPrefix = 0xfd; +let kAtomicPrefix = 0xfe; + +// Numeric opcodes. +let kExprMemoryInit = 0x08; +let kExprDataDrop = 0x09; +let kExprMemoryCopy = 0x0a; +let kExprMemoryFill = 0x0b; +let kExprTableInit = 0x0c; +let kExprElemDrop = 0x0d; +let kExprTableCopy = 0x0e; +let kExprTableGrow = 0x0f; +let kExprTableSize = 0x10; +let kExprTableFill = 0x11; + +// Atomic opcodes. +let kExprAtomicNotify = 0x00; +let kExprI32AtomicWait = 0x01; +let kExprI64AtomicWait = 0x02; +let kExprI32AtomicLoad = 0x10; +let kExprI32AtomicLoad8U = 0x12; +let kExprI32AtomicLoad16U = 0x13; +let kExprI32AtomicStore = 0x17; +let kExprI32AtomicStore8U = 0x19; +let kExprI32AtomicStore16U = 0x1a; +let kExprI32AtomicAdd = 0x1e; +let kExprI32AtomicAdd8U = 0x20; +let kExprI32AtomicAdd16U = 0x21; +let kExprI32AtomicSub = 0x25; +let kExprI32AtomicSub8U = 0x27; +let kExprI32AtomicSub16U = 0x28; +let kExprI32AtomicAnd = 0x2c; +let kExprI32AtomicAnd8U = 0x2e; +let kExprI32AtomicAnd16U = 0x2f; +let kExprI32AtomicOr = 0x33; +let kExprI32AtomicOr8U = 0x35; +let kExprI32AtomicOr16U = 0x36; +let kExprI32AtomicXor = 0x3a; +let kExprI32AtomicXor8U = 0x3c; +let kExprI32AtomicXor16U = 0x3d; +let kExprI32AtomicExchange = 0x41; +let kExprI32AtomicExchange8U = 0x43; +let kExprI32AtomicExchange16U = 0x44; +let kExprI32AtomicCompareExchange = 0x48; +let kExprI32AtomicCompareExchange8U = 0x4a; +let kExprI32AtomicCompareExchange16U = 0x4b; + +let kExprI64AtomicLoad = 0x11; +let kExprI64AtomicLoad8U = 0x14; +let kExprI64AtomicLoad16U = 0x15; +let kExprI64AtomicLoad32U = 0x16; +let kExprI64AtomicStore = 0x18; +let kExprI64AtomicStore8U = 0x1b; +let kExprI64AtomicStore16U = 0x1c; +let kExprI64AtomicStore32U = 0x1d; +let kExprI64AtomicAdd = 0x1f; +let kExprI64AtomicAdd8U = 0x22; +let kExprI64AtomicAdd16U = 0x23; +let kExprI64AtomicAdd32U = 0x24; +let kExprI64AtomicSub = 0x26; +let kExprI64AtomicSub8U = 0x29; +let kExprI64AtomicSub16U = 0x2a; +let kExprI64AtomicSub32U = 0x2b; +let kExprI64AtomicAnd = 0x2d; +let kExprI64AtomicAnd8U = 0x30; +let kExprI64AtomicAnd16U = 0x31; +let kExprI64AtomicAnd32U = 0x32; +let kExprI64AtomicOr = 0x34; +let kExprI64AtomicOr8U = 0x37; +let kExprI64AtomicOr16U = 0x38; +let kExprI64AtomicOr32U = 0x39; +let kExprI64AtomicXor = 0x3b; +let kExprI64AtomicXor8U = 0x3e; +let kExprI64AtomicXor16U = 0x3f; +let kExprI64AtomicXor32U = 0x40; +let kExprI64AtomicExchange = 0x42; +let kExprI64AtomicExchange8U = 0x45; +let kExprI64AtomicExchange16U = 0x46; +let kExprI64AtomicExchange32U = 0x47; +let kExprI64AtomicCompareExchange = 0x49 +let kExprI64AtomicCompareExchange8U = 0x4c; +let kExprI64AtomicCompareExchange16U = 0x4d; +let kExprI64AtomicCompareExchange32U = 0x4e; + +// Simd opcodes. +let kExprS128LoadMem = 0x00; +let kExprS128StoreMem = 0x01; +let kExprI32x4Splat = 0x0c; +let kExprI32x4Eq = 0x2c; +let kExprS1x4AllTrue = 0x75; +let kExprF32x4Min = 0x9e; class Binary { constructor() { @@ -346,7 +488,7 @@ class Binary { } trunc_buffer() { - return this.buffer = this.buffer.slice(0, this.length); + return new Uint8Array(this.buffer.buffer, 0, this.length); } reset() { @@ -372,7 +514,7 @@ class Binary { this.buffer[this.length++] = val >> 24; } - emit_leb(val, max_len) { + emit_leb_u(val, max_len) { this.ensure_space(max_len); for (let i = 0; i < max_len; ++i) { let v = val & 0xff; @@ -387,11 +529,11 @@ class Binary { } emit_u32v(val) { - this.emit_leb(val, kMaxVarInt32Size); + this.emit_leb_u(val, kMaxVarInt32Size); } emit_u64v(val) { - this.emit_leb(val, kMaxVarInt64Size); + this.emit_leb_u(val, kMaxVarInt64Size); } emit_bytes(data) { @@ -443,6 +585,16 @@ class WasmFunctionBuilder { this.name = name; this.type_index = type_index; this.body = []; + this.locals = []; + this.local_names = []; + } + + numLocalNames() { + let num_local_names = 0; + for (let loc_name of this.local_names) { + if (loc_name !== undefined) ++num_local_names; + } + return num_local_names; } exportAs(name) { @@ -456,9 +608,14 @@ class WasmFunctionBuilder { } addBody(body) { - const bodyCopy = body.slice(); - bodyCopy.push(kExprEnd); - return this.addBodyWithEnd(bodyCopy); + for (let b of body) { + if (typeof b !== 'number' || (b & (~0xFF)) !== 0 ) + throw new Error('invalid body (entries must be 8 bit numbers): ' + body); + } + this.body = body.slice(); + // Automatically add the end for the function block to the body. + this.body.push(kExprEnd); + return this; } addBodyWithEnd(body) { @@ -466,8 +623,23 @@ class WasmFunctionBuilder { return this; } - addLocals(locals) { - this.locals = locals; + getNumLocals() { + let total_locals = 0; + for (let l of this.locals) { + for (let type of ["i32", "i64", "f32", "f64", "s128"]) { + total_locals += l[type + "_count"] || 0; + } + } + return total_locals; + } + + addLocals(locals, names) { + const old_num_locals = this.getNumLocals(); + this.locals.push(locals); + if (names) { + const missing_names = old_num_locals - this.local_names.length; + this.local_names.push(...new Array(missing_names), ...names); + } return this; } @@ -491,21 +663,38 @@ class WasmGlobalBuilder { } } +class WasmTableBuilder { + constructor(module, type, initial_size, max_size) { + this.module = module; + this.type = type; + this.initial_size = initial_size; + this.has_max = max_size != undefined; + this.max_size = max_size; + } + + exportAs(name) { + this.module.exports.push({name: name, kind: kExternalTable, + index: this.index}); + return this; + } +} + class WasmModuleBuilder { constructor() { this.types = []; this.imports = []; this.exports = []; this.globals = []; + this.tables = []; + this.exceptions = []; this.functions = []; - this.table_length_min = 0; - this.table_length_max = undefined; this.element_segments = []; this.data_segments = []; - this.segments = []; this.explicit = []; this.num_imported_funcs = 0; this.num_imported_globals = 0; + this.num_imported_tables = 0; + this.num_imported_exceptions = 0; return this; } @@ -514,8 +703,8 @@ class WasmModuleBuilder { return this; } - addMemory(min, max, exp) { - this.memory = {min: min, max: max, exp: exp}; + addMemory(min, max, exp, shared) { + this.memory = {min: min, max: max, exp: exp, shared: shared}; return this; } @@ -524,6 +713,26 @@ class WasmModuleBuilder { return this; } + stringToBytes(name) { + var result = new Binary(); + result.emit_string(name); + return result.trunc_buffer() + } + + createCustomSection(name, bytes) { + name = this.stringToBytes(name); + var section = new Binary(); + section.emit_u8(kUnknownSectionCode); + section.emit_u32v(name.length + bytes.length); + section.emit_bytes(name); + section.emit_bytes(bytes); + return section.trunc_buffer(); + } + + addCustomSection(name, bytes) { + this.explicit.push(this.createCustomSection(name, bytes)); + } + addType(type) { this.types.push(type); var pl = type.params.length; // should have params @@ -538,6 +747,24 @@ class WasmModuleBuilder { return glob; } + addTable(type, initial_size, max_size = undefined) { + if (type != kWasmAnyRef && type != kWasmAnyFunc && type != kWasmExnRef) { + throw new Error( + 'Tables must be of type kWasmAnyRef, kWasmAnyFunc, or kWasmExnRef'); + } + let table = new WasmTableBuilder(this, type, initial_size, max_size); + table.index = this.tables.length + this.num_imported_tables; + this.tables.push(table); + return table; + } + + addException(type) { + let type_index = (typeof type) == "number" ? type : this.addType(type); + let except_index = this.exceptions.length + this.num_imported_exceptions; + this.exceptions.push(type_index); + return except_index; + } + addFunction(name, type) { let type_index = (typeof type) == "number" ? type : this.addType(type); let func = new WasmFunctionBuilder(this, name, type_index); @@ -547,30 +774,50 @@ class WasmModuleBuilder { } addImport(module, name, type) { + if (this.functions.length != 0) { + throw new Error('Imported functions must be declared before local ones'); + } let type_index = (typeof type) == "number" ? type : this.addType(type); this.imports.push({module: module, name: name, kind: kExternalFunction, type: type_index}); return this.num_imported_funcs++; } - addImportedGlobal(module, name, type) { + addImportedGlobal(module, name, type, mutable = false) { + if (this.globals.length != 0) { + throw new Error('Imported globals must be declared before local ones'); + } let o = {module: module, name: name, kind: kExternalGlobal, type: type, - mutable: false} + mutable: mutable}; this.imports.push(o); return this.num_imported_globals++; } - addImportedMemory(module, name, initial = 0, maximum) { + addImportedMemory(module, name, initial = 0, maximum, shared) { let o = {module: module, name: name, kind: kExternalMemory, - initial: initial, maximum: maximum}; + initial: initial, maximum: maximum, shared: shared}; this.imports.push(o); return this; } - addImportedTable(module, name, initial, maximum) { + addImportedTable(module, name, initial, maximum, type) { + if (this.tables.length != 0) { + throw new Error('Imported tables must be declared before local ones'); + } let o = {module: module, name: name, kind: kExternalTable, initial: initial, - maximum: maximum}; + maximum: maximum, type: type || kWasmAnyFunctionTypeForm}; + this.imports.push(o); + return this.num_imported_tables++; + } + + addImportedException(module, name, type) { + if (this.exceptions.length != 0) { + throw new Error('Imported exceptions must be declared before local ones'); + } + let type_index = (typeof type) == "number" ? type : this.addType(type); + let o = {module: module, name: name, kind: kExternalException, type: type_index}; this.imports.push(o); + return this.num_imported_exceptions++; } addExport(name, index) { @@ -585,7 +832,12 @@ class WasmModuleBuilder { addDataSegment(addr, data, is_global = false) { this.data_segments.push( - {addr: addr, data: data, is_global: is_global}); + {addr: addr, data: data, is_global: is_global, is_active: true}); + return this.data_segments.length - 1; + } + + addPassiveDataSegment(data) { + this.data_segments.push({data: data, is_active: false}); return this.data_segments.length - 1; } @@ -593,18 +845,14 @@ class WasmModuleBuilder { this.exports.push({name: name, kind: kExternalMemory, index: 0}); } - addElementSegment(base, is_global, array, is_import = false) { - this.element_segments.push({base: base, is_global: is_global, - array: array}); - if (!is_global) { - var length = base + array.length; - if (length > this.table_length_min && !is_import) { - this.table_length_min = length; - } - if (length > this.table_length_max && !is_import) { - this.table_length_max = length; - } - } + addElementSegment(table, base, is_global, array) { + this.element_segments.push({table: table, base: base, is_global: is_global, + array: array, is_active: true}); + return this; + } + + addPassiveElementSegment(array, is_import = false) { + this.element_segments.push({array: array, is_active: false}); return this; } @@ -613,12 +861,30 @@ class WasmModuleBuilder { if (typeof n != 'number') throw new Error('invalid table (entries have to be numbers): ' + array); } - return this.addElementSegment(this.table_length_min, false, array); + if (this.tables.length == 0) { + this.addTable(kWasmAnyFunc, 0); + } + // Adjust the table to the correct size. + let table = this.tables[0]; + const base = table.initial_size; + const table_size = base + array.length; + table.initial_size = table_size; + if (table.has_max && table_size > table.max_size) { + table.max_size = table_size; + } + return this.addElementSegment(0, base, false, array); } setTableBounds(min, max = undefined) { - this.table_length_min = min; - this.table_length_max = max; + if (this.tables.length != 0) { + throw new Error("The table bounds of table '0' have already been set."); + } + this.addTable(kWasmAnyFunc, min, max); + return this; + } + + setName(name) { + this.name = name; return this; } @@ -664,15 +930,23 @@ class WasmModuleBuilder { section.emit_u8(imp.mutable); } else if (imp.kind == kExternalMemory) { var has_max = (typeof imp.maximum) != "undefined"; - section.emit_u8(has_max ? 1 : 0); // flags + var is_shared = (typeof imp.shared) != "undefined"; + if (is_shared) { + section.emit_u8(has_max ? 3 : 2); // flags + } else { + section.emit_u8(has_max ? 1 : 0); // flags + } section.emit_u32v(imp.initial); // initial if (has_max) section.emit_u32v(imp.maximum); // maximum } else if (imp.kind == kExternalTable) { - section.emit_u8(kWasmAnyFunctionTypeForm); + section.emit_u8(imp.type); var has_max = (typeof imp.maximum) != "undefined"; section.emit_u8(has_max ? 1 : 0); // flags section.emit_u32v(imp.initial); // initial if (has_max) section.emit_u32v(imp.maximum); // maximum + } else if (imp.kind == kExternalException) { + section.emit_u32v(kExceptionAttribute); + section.emit_u32v(imp.type); } else { throw new Error("unknown/unsupported import kind " + imp.kind); } @@ -681,31 +955,27 @@ class WasmModuleBuilder { } // Add functions declarations - let has_names = false; - let names = false; if (wasm.functions.length > 0) { if (debug) print("emitting function decls @ " + binary.length); binary.emit_section(kFunctionSectionCode, section => { section.emit_u32v(wasm.functions.length); for (let func of wasm.functions) { - has_names = has_names || (func.name != undefined && - func.name.length > 0); section.emit_u32v(func.type_index); } }); } // Add table section - if (wasm.table_length_min > 0) { - if (debug) print("emitting table @ " + binary.length); + if (wasm.tables.length > 0) { + if (debug) print ("emitting tables @ " + binary.length); binary.emit_section(kTableSectionCode, section => { - section.emit_u8(1); // one table entry - section.emit_u8(kWasmAnyFunctionTypeForm); - const max = wasm.table_length_max; - const has_max = max !== undefined; - section.emit_u8(has_max ? kHasMaximumFlag : 0); - section.emit_u32v(wasm.table_length_min); - if (has_max) section.emit_u32v(max); + section.emit_u32v(wasm.tables.length); + for (let table of wasm.tables) { + section.emit_u8(table.type); + section.emit_u8(table.has_max); + section.emit_u32v(table.initial_size); + if (table.has_max) section.emit_u32v(table.max_size); + } }); } @@ -715,7 +985,13 @@ class WasmModuleBuilder { binary.emit_section(kMemorySectionCode, section => { section.emit_u8(1); // one memory entry const has_max = wasm.memory.max !== undefined; - section.emit_u8(has_max ? 1 : 0); + const is_shared = wasm.memory.shared !== undefined; + // Emit flags (bit 0: reszeable max, bit 1: shared memory) + if (is_shared) { + section.emit_u8(has_max ? kSharedHasMaximumFlag : 2); + } else { + section.emit_u8(has_max ? kHasMaximumFlag : 0); + } section.emit_u32v(wasm.memory.min); if (has_max) section.emit_u32v(wasm.memory.max); }); @@ -738,7 +1014,7 @@ class WasmModuleBuilder { break; case kWasmI64: section.emit_u8(kExprI64Const); - section.emit_u8(global.init); + section.emit_u64v(global.init); break; case kWasmF32: section.emit_u8(kExprF32Const); @@ -750,10 +1026,22 @@ class WasmModuleBuilder { f64_view[0] = global.init; section.emit_bytes(f64_bytes_view); break; + case kWasmAnyFunc: + case kWasmAnyRef: + if (global.function_index !== undefined) { + section.emit_u8(kExprRefFunc); + section.emit_u32v(global.function_index); + } else { + section.emit_u8(kExprRefNull); + } + break; + case kWasmExnRef: + section.emit_u8(kExprRefNull); + break; } } else { // Emit a global-index initializer. - section.emit_u8(kExprGetGlobal); + section.emit_u8(kExprGlobalGet); section.emit_u32v(global.init_index); } section.emit_u8(kExprEnd); // end of init expression @@ -761,6 +1049,18 @@ class WasmModuleBuilder { }); } + // Add exceptions. + if (wasm.exceptions.length > 0) { + if (debug) print("emitting exceptions @ " + binary.length); + binary.emit_section(kExceptionSectionCode, section => { + section.emit_u32v(wasm.exceptions.length); + for (let type of wasm.exceptions) { + section.emit_u32v(kExceptionAttribute); + section.emit_u32v(type); + } + }); + } + // Add export table. var mem_export = (wasm.memory !== undefined && wasm.memory.exp); var exports_count = wasm.exports.length + (mem_export ? 1 : 0); @@ -797,22 +1097,55 @@ class WasmModuleBuilder { section.emit_u32v(inits.length); for (let init of inits) { - section.emit_u8(0); // table index / flags - if (init.is_global) { - section.emit_u8(kExprGetGlobal); + if (init.is_active) { + // Active segment. + if (init.table == 0) { + section.emit_u32v(kActiveNoIndex); + } else { + section.emit_u32v(kActiveWithIndex); + section.emit_u32v(init.table); + } + if (init.is_global) { + section.emit_u8(kExprGlobalGet); + } else { + section.emit_u8(kExprI32Const); + } + section.emit_u32v(init.base); + section.emit_u8(kExprEnd); + if (init.table != 0) { + section.emit_u8(kExternalFunction); + } + section.emit_u32v(init.array.length); + for (let index of init.array) { + section.emit_u32v(index); + } } else { - section.emit_u8(kExprI32Const); - } - section.emit_u32v(init.base); - section.emit_u8(kExprEnd); - section.emit_u32v(init.array.length); - for (let index of init.array) { - section.emit_u32v(index); + // Passive segment. + section.emit_u8(kPassiveWithElements); // flags + section.emit_u8(kWasmAnyFunc); + section.emit_u32v(init.array.length); + for (let index of init.array) { + if (index === null) { + section.emit_u8(kExprRefNull); + section.emit_u8(kExprEnd); + } else { + section.emit_u8(kExprRefFunc); + section.emit_u32v(index); + section.emit_u8(kExprEnd); + } + } } } }); } + // If there are any passive data segments, add the DataCount section. + if (wasm.data_segments.some(seg => !seg.is_active)) { + binary.emit_section(kDataCountSectionCode, section => { + section.emit_u32v(wasm.data_segments.length); + }); + } + // Add function bodies. if (wasm.functions.length > 0) { // emit function bodies @@ -824,9 +1157,7 @@ class WasmModuleBuilder { header.reset(); // Function body length will be patched later. let local_decls = []; - let l = func.locals; - if (l != undefined) { - let local_decls_count = 0; + for (let l of func.locals || []) { if (l.i32_count > 0) { local_decls.push({count: l.i32_count, type: kWasmI32}); } @@ -839,6 +1170,18 @@ class WasmModuleBuilder { if (l.f64_count > 0) { local_decls.push({count: l.f64_count, type: kWasmF64}); } + if (l.s128_count > 0) { + local_decls.push({count: l.s128_count, type: kWasmS128}); + } + if (l.anyref_count > 0) { + local_decls.push({count: l.anyref_count, type: kWasmAnyRef}); + } + if (l.anyfunc_count > 0) { + local_decls.push({count: l.anyfunc_count, type: kWasmAnyFunc}); + } + if (l.except_count > 0) { + local_decls.push({count: l.except_count, type: kWasmExnRef}); + } } header.emit_u32v(local_decls.length); @@ -860,17 +1203,21 @@ class WasmModuleBuilder { binary.emit_section(kDataSectionCode, section => { section.emit_u32v(wasm.data_segments.length); for (let seg of wasm.data_segments) { - section.emit_u8(0); // linear memory index 0 / flags - if (seg.is_global) { - // initializer is a global variable - section.emit_u8(kExprGetGlobal); - section.emit_u32v(seg.addr); + if (seg.is_active) { + section.emit_u8(0); // linear memory index 0 / flags + if (seg.is_global) { + // initializer is a global variable + section.emit_u8(kExprGlobalGet); + section.emit_u32v(seg.addr); + } else { + // initializer is a constant + section.emit_u8(kExprI32Const); + section.emit_u32v(seg.addr); + } + section.emit_u8(kExprEnd); } else { - // initializer is a constant - section.emit_u8(kExprI32Const); - section.emit_u32v(seg.addr); + section.emit_u8(kPassive); // flags } - section.emit_u8(kExprEnd); section.emit_u32v(seg.data.length); section.emit_bytes(seg.data); } @@ -883,21 +1230,50 @@ class WasmModuleBuilder { binary.emit_bytes(exp); } - // Add function names. - if (has_names) { - if (debug) print("emitting names @ " + binary.length); + // Add names. + let num_function_names = 0; + let num_functions_with_local_names = 0; + for (let func of wasm.functions) { + if (func.name !== undefined) ++num_function_names; + if (func.numLocalNames() > 0) ++num_functions_with_local_names; + } + if (num_function_names > 0 || num_functions_with_local_names > 0 || + wasm.name !== undefined) { + if (debug) print('emitting names @ ' + binary.length); binary.emit_section(kUnknownSectionCode, section => { - section.emit_string("name"); - var count = wasm.functions.length + wasm.num_imported_funcs; - section.emit_u32v(count); - for (var i = 0; i < wasm.num_imported_funcs; i++) { - section.emit_u8(0); // empty string - section.emit_u8(0); // local names count == 0 + section.emit_string('name'); + // Emit module name. + if (wasm.name !== undefined) { + section.emit_section(kModuleNameCode, name_section => { + name_section.emit_string(wasm.name); + }); } - for (let func of wasm.functions) { - var name = func.name == undefined ? "" : func.name; - section.emit_string(name); - section.emit_u8(0); // local names count == 0 + // Emit function names. + if (num_function_names > 0) { + section.emit_section(kFunctionNamesCode, name_section => { + name_section.emit_u32v(num_function_names); + for (let func of wasm.functions) { + if (func.name === undefined) continue; + name_section.emit_u32v(func.index); + name_section.emit_string(func.name); + } + }); + } + // Emit local names. + if (num_functions_with_local_names > 0) { + section.emit_section(kLocalNamesCode, name_section => { + name_section.emit_u32v(num_functions_with_local_names); + for (let func of wasm.functions) { + if (func.numLocalNames() == 0) continue; + name_section.emit_u32v(func.index); + name_section.emit_u32v(func.numLocalNames()); + for (let i = 0; i < func.local_names.length; ++i) { + if (func.local_names[i] === undefined) continue; + name_section.emit_u32v(i); + name_section.emit_string(func.local_names[i]); + } + } + }); } }); } @@ -925,13 +1301,24 @@ class WasmModuleBuilder { } } -function wasmI32Const(val) { - let bytes = [kExprI32Const]; - for (let i = 0; i < 4; ++i) { - bytes.push(0x80 | ((val >> (7 * i)) & 0x7f)); +function wasmSignedLeb(val, max_len = 5) { + let res = []; + for (let i = 0; i < max_len; ++i) { + let v = val & 0x7f; + // If {v} sign-extended from 7 to 32 bits is equal to val, we are done. + if (((v << 25) >> 25) == val) { + res.push(v); + return res; + } + res.push(v | 0x80); + val = val >> 7; } - bytes.push((val >> (7 * 4)) & 0x7f); - return bytes; + throw new Error( + 'Leb value <' + val + '> exceeds maximum length of ' + max_len); +} + +function wasmI32Const(val) { + return [kExprI32Const, ...wasmSignedLeb(val, 5)]; } function wasmF32Const(f) { diff --git a/test/sync-js-api.py b/test/sync-js-api.py new file mode 100755 index 0000000000..454d69df6b --- /dev/null +++ b/test/sync-js-api.py @@ -0,0 +1,54 @@ +#!/usr/bin/env python3 + +import glob +import os +import shutil +import subprocess + +LOCAL_FILES = [ + "LICENSE.md", + "README.md", + + # Currently doesn't pass the stability checker in wpt. + "limits.any.js", +] + + +def copy_from_local(local_dir, out): + for local_file in LOCAL_FILES: + shutil.copy(os.path.join(local_dir, local_file), out) + + +def copy_from_upstream(upstream, out): + upstream = os.path.abspath(upstream) + paths = glob.glob(os.path.join(upstream, "**", "*.js"), recursive=True) + for path in paths: + relpath = os.path.relpath(path, upstream) + + # Tests for proposals that have not merged here yet. + if ".tentative" in relpath: + continue + + # Requires `fetch()` and various wpt infrastructure. + if os.path.basename(relpath) == "idlharness.any.js": + continue + + dest = os.path.join(out, relpath) + os.makedirs(os.path.dirname(dest), exist_ok=True) + shutil.copy(path, dest) + + +def main(upstream): + local_dir = os.path.join("test", "js-api") + scratch = os.path.join("test", "js-api-temp") + os.mkdir(scratch) + copy_from_local(local_dir, scratch) + copy_from_upstream(os.path.join(upstream, "wasm", "jsapi"), scratch) + shutil.rmtree(local_dir) + os.rename(scratch, local_dir) + subprocess.check_call(["git", "add", local_dir]) + + +if __name__ == "__main__": + import sys + main(*sys.argv[1:]) From e56ef21a334f8b1ca81247230c595b38c2aedebd Mon Sep 17 00:00:00 2001 From: Andreas Rossberg Date: Tue, 12 May 2020 13:17:25 +0200 Subject: [PATCH 160/199] Adjust readme --- interpreter/README.md | 26 ++++++++++++++------------ 1 file changed, 14 insertions(+), 12 deletions(-) diff --git a/interpreter/README.md b/interpreter/README.md index 5377223145..cb5964c15a 100644 --- a/interpreter/README.md +++ b/interpreter/README.md @@ -233,8 +233,8 @@ op: table.copy ? ? table.init ? elem.drop - .load((8|16|32)_)? ? ? - .store(8|16|32)? ? ? + .load((8|16|32)_)? ? ? + .store(8|16|32)? ? ? memory.size memory.grow memory.fill @@ -244,12 +244,12 @@ op: ref.null ref.is_null ref.func - .const - . - . - . - . - ._(_)? + .const + . + . + . + . + ._(_)? func: ( func ? * * ) ( func ? ( export ) <...> ) ;; = (export (func )) (func ? <...>) @@ -362,11 +362,11 @@ assertion: ( assert_trap ) ;; assert module traps on instantiation result: - ( .const ) + ( .const ) ( ref.extern ) ( ref.func ) -numpat: +num_pat: ;; literal result nan:canonical ;; NaN in canonical form nan:arithmetic ;; NaN with 1 in MSB of payload @@ -421,9 +421,11 @@ assertion: ( assert_trap ) ;; assert module traps on instantiation result: - ( .const ) + ( .const ) + ( ref.extern ) + ( ref.func ) -numpat: +num_pat: ;; literal result nan:canonical ;; NaN in canonical form nan:arithmetic ;; NaN with 1 in MSB of payload From c8d58c73f213769320900be771759b9afeef8a99 Mon Sep 17 00:00:00 2001 From: Ryan Hunt Date: Tue, 12 May 2020 09:02:03 -0500 Subject: [PATCH 161/199] Update test/harness/*_index.js for removing subtyping (#88) This applies the changes made to 'script/js.ml' to the standalone test harnesses. --- test/harness/async_index.js | 26 +++++++++++++++----------- test/harness/sync_index.js | 26 +++++++++++++++----------- 2 files changed, 30 insertions(+), 22 deletions(-) diff --git a/test/harness/async_index.js b/test/harness/async_index.js index 094999254c..556a39d2ad 100644 --- a/test/harness/async_index.js +++ b/test/harness/async_index.js @@ -52,19 +52,22 @@ const EXPECT_INVALID = false; /* DATA **********************************************************************/ -let hostrefs = {}; -let hostsym = Symbol("hostref"); -function hostref(s) { - if (! (s in hostrefs)) hostrefs[s] = {[hostsym]: s}; - return hostrefs[s]; +let externrefs = {}; +let externsym = Symbol("externref"); +function externref(s) { + if (! (s in externrefs)) externrefs[s] = {[externsym]: s}; + return externrefs[s]; } -function is_hostref(x) { - return (x !== null && hostsym in x) ? 1 : 0; +function is_externref(x) { + return (x !== null && externsym in x) ? 1 : 0; } function is_funcref(x) { return typeof x === "function" ? 1 : 0; } -function eq_ref(x, y) { +function eq_externref(x, y) { + return x === y ? 1 : 0; +} +function eq_funcref(x, y) { return x === y ? 1 : 0; } @@ -83,10 +86,11 @@ function reinitializeRegistry() { chain = chain.then(_ => { let spectest = { - hostref: hostref, - is_hostref: is_hostref, + externref: externref, + is_externref: is_externref, is_funcref: is_funcref, - eq_ref: eq_ref, + eq_externref: eq_externref, + eq_funcref: eq_funcref, print: console.log.bind(console), print_i32: console.log.bind(console), print_i32_f32: console.log.bind(console), diff --git a/test/harness/sync_index.js b/test/harness/sync_index.js index a060e446ef..af8957322b 100644 --- a/test/harness/sync_index.js +++ b/test/harness/sync_index.js @@ -66,19 +66,22 @@ const EXPECT_INVALID = false; /* DATA **********************************************************************/ -let hostrefs = {}; -let hostsym = Symbol("hostref"); -function hostref(s) { - if (! (s in hostrefs)) hostrefs[s] = {[hostsym]: s}; - return hostrefs[s]; +let externrefs = {}; +let externsym = Symbol("externref"); +function externref(s) { + if (! (s in externrefs)) externrefs[s] = {[externsym]: s}; + return externrefs[s]; } -function is_hostref(x) { - return (x !== null && hostsym in x) ? 1 : 0; +function is_externref(x) { + return (x !== null && externsym in x) ? 1 : 0; } function is_funcref(x) { return typeof x === "function" ? 1 : 0; } -function eq_ref(x, y) { +function eq_externref(x, y) { + return x === y ? 1 : 0; +} +function eq_funcref(x, y) { return x === y ? 1 : 0; } @@ -93,10 +96,11 @@ function reinitializeRegistry() { return; let spectest = { - hostref: hostref, - is_hostref: is_hostref, + externref: externref, + is_externref: is_externref, is_funcref: is_funcref, - eq_ref: eq_ref, + eq_externref: eq_externref, + eq_funcref: eq_funcref, print: console.log.bind(console), print_i32: console.log.bind(console), print_i32_f32: console.log.bind(console), From b728bbce247989535cb61ba6f5e211a4abbd07dc Mon Sep 17 00:00:00 2001 From: Andreas Rossberg Date: Wed, 13 May 2020 20:28:38 +0200 Subject: [PATCH 162/199] [spec/interpreter/test] Relax ref check to whole module (#90) --- document/core/valid/conventions.rst | 2 +- document/core/valid/modules.rst | 26 ++++++++++++--------- interpreter/valid/valid.ml | 2 +- test/core/ref_func.wast | 35 +++++++++++++++++++++++++++-- 4 files changed, 50 insertions(+), 15 deletions(-) diff --git a/document/core/valid/conventions.rst b/document/core/valid/conventions.rst index 405ad23e28..b6a49b0cd3 100644 --- a/document/core/valid/conventions.rst +++ b/document/core/valid/conventions.rst @@ -43,7 +43,7 @@ which collects relevant information about the surrounding :ref:`module ` that occur in element segments and can hence be used to form references elsewhere. +* *References*: the list of :ref:`function indices ` that occur in the module outside functions and can hence be used to form references inside them. In other words, a context contains a sequence of suitable :ref:`types ` for each :ref:`index space `, describing each defined entry in that space. diff --git a/document/core/valid/modules.rst b/document/core/valid/modules.rst index b86a62f086..eeed38f3a0 100644 --- a/document/core/valid/modules.rst +++ b/document/core/valid/modules.rst @@ -526,7 +526,7 @@ Instead, the context :math:`C` for validation of the module's content is constru * :math:`C.\CELEMS` is :math:`{\X{rt}}^\ast` as determined below, - * :math:`C.\CDATAS` is :math:`{\ok}^{N_d}`, where :math:`N_d` is the length of the vector :math:`\module.\MDATAS`, + * :math:`C.\CDATAS` is :math:`{\ok}^n`, where :math:`n` is the length of the vector :math:`\module.\MDATAS`, * :math:`C.\CLOCALS` is empty, @@ -534,7 +534,7 @@ Instead, the context :math:`C` for validation of the module's content is constru * :math:`C.\CRETURN` is empty. - * :math:`C.\CREFS` is the set :math:`\freefuncidx(\module.\MELEMS)`, i.e., the set of :ref:`function indices ` occurring in any of the module's :ref:`element segments `. + * :math:`C.\CREFS` is the set :math:`\freefuncidx(\module \with \MFUNCS = \epsilon \with \MSTART = \epsilon)`, i.e., the set of :ref:`function indices ` occurring in the module, except in its :ref:`functions ` or :ref:`start function `. * Let :math:`C'` be the :ref:`context ` where: @@ -603,7 +603,7 @@ Instead, the context :math:`C` for validation of the module's content is constru .. math:: \frac{ \begin{array}{@{}c@{}} - (\vdashfunctype \functype \ok)^\ast + (\vdashfunctype \type \ok)^\ast \quad (C \vdashfunc \func : \X{ft})^\ast \quad @@ -615,7 +615,7 @@ Instead, the context :math:`C` for validation of the module's content is constru \\ (C \vdashelem \elem : \X{rt})^\ast \quad - (C \vdashdata \data \ok)^{N_d} + (C \vdashdata \data \ok)^n \quad (C \vdashstart \start \ok)^? \quad @@ -631,28 +631,32 @@ Instead, the context :math:`C` for validation of the module's content is constru \qquad \X{igt}^\ast = \etglobals(\X{it}^\ast) \\ - C = \{ \CTYPES~\functype^\ast, \CFUNCS~\X{ift}^\ast~\X{ft}^\ast, \CTABLES~\X{itt}^\ast~\X{tt}^\ast, \CMEMS~\X{imt}^\ast~\X{mt}^\ast, \CGLOBALS~\X{igt}^\ast~\X{gt}^\ast, \CELEMS~\X{rt}^\ast, \CDATAS~{\ok}^{N_d}, \CREFS~\freefuncidx(\elem^\ast) \} + x^\ast = \freefuncidx(\module \with \MFUNCS = \epsilon \with \MSTART = \epsilon) + \\ + C = \{ \CTYPES~\type^\ast, \CFUNCS~\X{ift}^\ast\,\X{ft}^\ast, \CTABLES~\X{itt}^\ast\,\X{tt}^\ast, \CMEMS~\X{imt}^\ast\,\X{mt}^\ast, \CGLOBALS~\X{igt}^\ast\,\X{gt}^\ast, \CELEMS~\X{rt}^\ast, \CDATAS~{\ok}^n, \CREFS~x^\ast \} \\ C' = \{ \CGLOBALS~\X{igt}^\ast, \CFUNCS~(C.\CFUNCS), \CREFS~(C.\CREFS) \} \qquad |C.\CMEMS| \leq 1 \qquad (\export.\ENAME)^\ast ~\F{disjoint} - \end{array} - }{ - \vdashmodule \{ + \\ + \module = \{ \begin{array}[t]{@{}l@{}} - \MTYPES~\functype^\ast, + \MTYPES~\type^\ast, \MFUNCS~\func^\ast, \MTABLES~\table^\ast, \MMEMS~\mem^\ast, \MGLOBALS~\global^\ast, \\ \MELEMS~\elem^\ast, - \MDATAS~\data^{N_d}, + \MDATAS~\data^n, \MSTART~\start^?, \MIMPORTS~\import^\ast, - \MEXPORTS~\export^\ast \} : \X{it}^\ast \to \X{et}^\ast \\ + \MEXPORTS~\export^\ast \} \end{array} + \end{array} + }{ + \vdashmodule \module : \X{it}^\ast \to \X{et}^\ast } .. note:: diff --git a/interpreter/valid/valid.ml b/interpreter/valid/valid.ml index 8099837194..a6a6a2d285 100644 --- a/interpreter/valid/valid.ml +++ b/interpreter/valid/valid.ml @@ -584,7 +584,7 @@ let check_module (m : module_) = let c0 = List.fold_right check_import imports { empty_context with - refs = Free.list Free.elem elems; + refs = Free.module_ ({m.it with funcs = []; start = None} @@ m.at); types = List.map (fun ty -> ty.it) types; } in diff --git a/test/core/ref_func.wast b/test/core/ref_func.wast index 436b386642..c0c5a0cc72 100644 --- a/test/core/ref_func.wast +++ b/test/core/ref_func.wast @@ -74,11 +74,42 @@ "unknown function 7" ) + +;; Reference declaration + +(module + (func $f1) + (func $f2) + (func $f3) + (func $f4) + (func $f5) + (func $f6) + + (table $t 1 funcref) + + (global funcref (ref.func $f1)) + (export "f" (func $f2)) + (elem (table $t) (i32.const 0) func $f3) + (elem (table $t) (i32.const 0) funcref (ref.func $f4)) + (elem func $f5) + (elem funcref (ref.func $f6)) + + (func + (ref.func $f1) + (ref.func $f2) + (ref.func $f3) + (ref.func $f4) + (ref.func $f5) + (ref.func $f6) + (return) + ) +) + (assert_invalid - (module (func $f) (global funcref (ref.func $f))) + (module (func $f (drop (ref.func $f)))) "undeclared function reference" ) (assert_invalid - (module (func $f (drop (ref.func $f)))) + (module (start $f) (func $f (drop (ref.func $f)))) "undeclared function reference" ) From 37e44c9c437d6560bb02cf17371ed0adcd0a4fcf Mon Sep 17 00:00:00 2001 From: Ben Smith Date: Wed, 13 May 2020 13:19:01 -0700 Subject: [PATCH 163/199] Update `ref.null` encoding after subtyping change (#149) Issue https://github.com/WebAssembly/reference-types/issues/69 requires that `ref.null` instructions include a reference type immediate. This concept isn't present in the bulk-memory proposal, but the encoding is (in element segment expressions). This change updates the binary and text format, but not the syntax. This is OK for now, since the only reference type allowed here is `funcref`. --- document/core/binary/modules.rst | 2 +- document/core/text/modules.rst | 2 +- interpreter/binary/decode.ml | 5 ++++- interpreter/binary/encode.ml | 2 +- interpreter/text/arrange.ml | 2 +- interpreter/text/parser.mly | 2 +- test/core/binary.wast | 4 ++-- test/core/bulk.wast | 2 +- test/core/elem.wast | 18 +++++++++--------- 9 files changed, 21 insertions(+), 18 deletions(-) diff --git a/document/core/binary/modules.rst b/document/core/binary/modules.rst index 7ba296f285..05cff7711b 100644 --- a/document/core/binary/modules.rst +++ b/document/core/binary/modules.rst @@ -343,7 +343,7 @@ It decodes into a vector of :ref:`element segments ` that represent \production{element kind} & \Belemkind &::=& \hex{00} &\Rightarrow& \FUNCREF \\ \production{element expression} & \Belemexpr &::=& - \hex{D0}~\hex{0B} &\Rightarrow& \REFNULL~\END \\ &&|& + \hex{D0}~\hex{70}~\hex{0B} &\Rightarrow& \REFNULL~\END \\ &&|& \hex{D2}~x{:}\Bfuncidx~\hex{0B} &\Rightarrow& (\REFFUNC~x)~\END \\ \end{array} diff --git a/document/core/text/modules.rst b/document/core/text/modules.rst index 06941d1520..9c9201652b 100644 --- a/document/core/text/modules.rst +++ b/document/core/text/modules.rst @@ -503,7 +503,7 @@ Element segments allow for an optional :ref:`table index ` to ide \production{element list} & \Telemlist &::=& et{:}\Telemtype~~y^\ast{:}\Tvec(\Telemexpr_I) \qquad\Rightarrow\quad ( \ETYPE~et, \EINIT~y^\ast ) \\ \production{element expression} & \Telemexpr &::=& - \text{(}~\text{ref.null}~\text{)} \\ &&|& + \text{(}~\text{ref.null}~~\text{func}~\text{)} \\ &&|& \text{(}~\text{ref.func}~~\Tfuncidx_I~\text{)} \\ \production{table use} & \Ttableuse_I &::=& \text{(}~\text{table}~~x{:}\Ttableidx_I ~\text{)} diff --git a/interpreter/binary/decode.ml b/interpreter/binary/decode.ml index 5974e99efb..5fb92ef9c4 100644 --- a/interpreter/binary/decode.ml +++ b/interpreter/binary/decode.ml @@ -636,7 +636,10 @@ let elem_kind s = let elem_expr s = match u8 s with - | 0xd0 -> end_ s; ref_null + | 0xd0 -> + expect 0x70 s "funcref expected"; + end_ s; + ref_null | 0xd2 -> let x = at var s in end_ s; diff --git a/interpreter/binary/encode.ml b/interpreter/binary/encode.ml index 1be8b07f98..54908ea3d7 100644 --- a/interpreter/binary/encode.ml +++ b/interpreter/binary/encode.ml @@ -482,7 +482,7 @@ let encode m = let elem_expr e = match e.it with - | RefNull -> u8 0xd0; end_ () + | RefNull -> u8 0xd0; u8 0x70; end_ () | RefFunc x -> u8 0xd2; var x; end_ () let elem_index e = diff --git a/interpreter/text/arrange.ml b/interpreter/text/arrange.ml index 25368b1126..00c608d843 100644 --- a/interpreter/text/arrange.ml +++ b/interpreter/text/arrange.ml @@ -307,7 +307,7 @@ let elem_index el = let elem_expr el = match el.it with - | RefNull -> Node ("ref.null", []) + | RefNull -> Node ("ref.null", [atom elem_kind FuncRefType]) | RefFunc x -> Node ("ref.func", [atom var x]) let segment_mode category mode = diff --git a/interpreter/text/parser.mly b/interpreter/text/parser.mly index 16ccdb863f..95432091d1 100644 --- a/interpreter/text/parser.mly +++ b/interpreter/text/parser.mly @@ -591,7 +591,7 @@ elem_kind : | FUNC { FuncRefType } elem_expr : - | LPAR REF_NULL RPAR { let at = at () in fun c -> ref_null @@ at } + | LPAR REF_NULL elem_kind RPAR { let at = at () in fun c -> ref_null @@ at } | LPAR REF_FUNC var RPAR { let at = at () in fun c -> ref_func ($3 c func) @@ at } elem_expr_list : diff --git a/test/core/binary.wast b/test/core/binary.wast index 8385826390..8219079502 100644 --- a/test/core/binary.wast +++ b/test/core/binary.wast @@ -809,10 +809,10 @@ "\05\03\01\00\00" ;; Memory section - "\09\06\01" ;; Element section with one segment + "\09\07\01" ;; Element section with one segment "\05\70" ;; Passive, funcref "\01" ;; 1 element - "\d0\0b" ;; ref.null, end + "\d0\70\0b" ;; ref.null, end "\0a\04\01" ;; Code section diff --git a/test/core/bulk.wast b/test/core/bulk.wast index 6fb1f0decc..3bb794815c 100644 --- a/test/core/bulk.wast +++ b/test/core/bulk.wast @@ -5,7 +5,7 @@ (module (table 3 funcref) - (elem funcref (ref.func 0) (ref.null) (ref.func 1)) + (elem funcref (ref.func 0) (ref.null func) (ref.func 1)) (func) (func)) diff --git a/test/core/elem.wast b/test/core/elem.wast index bb622ee662..a50a1a2b36 100644 --- a/test/core/elem.wast +++ b/test/core/elem.wast @@ -8,18 +8,18 @@ ;; Passive (elem funcref) - (elem funcref (ref.func $f) (ref.func $f) (ref.null) (ref.func $g)) + (elem funcref (ref.func $f) (ref.func $f) (ref.null func) (ref.func $g)) (elem func) (elem func $f $f $g $g) (elem $p1 funcref) - (elem $p2 funcref (ref.func $f) (ref.func $f) (ref.null) (ref.func $g)) + (elem $p2 funcref (ref.func $f) (ref.func $f) (ref.null func) (ref.func $g)) (elem $p3 func) (elem $p4 func $f $f $g $g) ;; Active (elem (table $t) (i32.const 0) funcref) - (elem (table $t) (i32.const 0) funcref (ref.func $f) (ref.null)) + (elem (table $t) (i32.const 0) funcref (ref.func $f) (ref.null func)) (elem (table $t) (i32.const 0) func) (elem (table $t) (i32.const 0) func $f $g) (elem (table $t) (offset (i32.const 0)) funcref) @@ -33,16 +33,16 @@ (elem (table $t) (offset (i32.const 0)) func) (elem (table $t) (offset (i32.const 0)) func $f $f) (elem (offset (i32.const 0))) - (elem (offset (i32.const 0)) funcref (ref.func $f) (ref.null)) + (elem (offset (i32.const 0)) funcref (ref.func $f) (ref.null func)) (elem (offset (i32.const 0)) func $f $f) (elem (offset (i32.const 0)) $f $f) (elem (i32.const 0)) - (elem (i32.const 0) funcref (ref.func $f) (ref.null)) + (elem (i32.const 0) funcref (ref.func $f) (ref.null func)) (elem (i32.const 0) func $f $f) (elem (i32.const 0) $f $f) (elem $a1 (table $t) (i32.const 0) funcref) - (elem $a2 (table $t) (i32.const 0) funcref (ref.func $f) (ref.null)) + (elem $a2 (table $t) (i32.const 0) funcref (ref.func $f) (ref.null func)) (elem $a3 (table $t) (i32.const 0) func) (elem $a4 (table $t) (i32.const 0) func $f $g) (elem $a9 (table $t) (offset (i32.const 0)) funcref) @@ -56,11 +56,11 @@ (elem $a17 (table $t) (offset (i32.const 0)) func) (elem $a18 (table $t) (offset (i32.const 0)) func $f $f) (elem $a19 (offset (i32.const 0))) - (elem $a20 (offset (i32.const 0)) funcref (ref.func $f) (ref.null)) + (elem $a20 (offset (i32.const 0)) funcref (ref.func $f) (ref.null func)) (elem $a21 (offset (i32.const 0)) func $f $f) (elem $a22 (offset (i32.const 0)) $f $f) (elem $a23 (i32.const 0)) - (elem $a24 (i32.const 0) funcref (ref.func $f) (ref.null)) + (elem $a24 (i32.const 0) funcref (ref.func $f) (ref.null func)) (elem $a25 (i32.const 0) func $f $f) (elem $a26 (i32.const 0) $f $f) ) @@ -69,7 +69,7 @@ (func $f) (func $g) - (table $t funcref (elem (ref.func $f) (ref.null) (ref.func $g))) + (table $t funcref (elem (ref.func $f) (ref.null func) (ref.func $g))) ) ;; Basic use From 66d90a7de541a9954af09cb9777f20cc0bd8bbe1 Mon Sep 17 00:00:00 2001 From: Nick Fitzgerald Date: Wed, 13 May 2020 16:26:53 -0700 Subject: [PATCH 164/199] Test that partially out of bounds segments don't write to a memory/table (#139) Fixes #138 --- test/core/linking.wast | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/test/core/linking.wast b/test/core/linking.wast index 2d92078f9a..cdb584d4a2 100644 --- a/test/core/linking.wast +++ b/test/core/linking.wast @@ -231,11 +231,12 @@ (table (import "Mt" "tab") 10 funcref) (func $f (result i32) (i32.const 0)) (elem (i32.const 7) $f) - (elem (i32.const 12) $f) ;; out of bounds + (elem (i32.const 8) $f $f $f $f $f) ;; (partially) out of bounds ) "out of bounds" ) (assert_return (invoke $Mt "call" (i32.const 7)) (i32.const 0)) +(assert_trap (invoke $Mt "call" (i32.const 8)) "uninitialized") (assert_trap (module @@ -337,13 +338,15 @@ ;; after the instantiation failure. (assert_trap (module + ;; Note: the memory is 5 pages large by the time we get here. (memory (import "Mm" "mem") 1) (data (i32.const 0) "abc") - (data (i32.const 0x50000) "d") ;; out of bounds + (data (i32.const 327670) "zzzzzzzzzzzzzzzzzz") ;; (partially) out of bounds ) "out of bounds" ) (assert_return (invoke $Mm "load" (i32.const 0)) (i32.const 97)) +(assert_return (invoke $Mm "load" (i32.const 327670)) (i32.const 0)) (assert_trap (module From 0b6f6750d8b9c02ac81a075c812f0e94c61aee14 Mon Sep 17 00:00:00 2001 From: Ryan Hunt Date: Mon, 18 May 2020 03:01:36 -0500 Subject: [PATCH 165/199] Re-add test that fails with a bottom type (#93) The original commit to add a bottom type removed this test as it would now unexpectedly validate. Now that a bottom type is removed it would be good to keep it. --- test/core/unreached-invalid.wast | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/test/core/unreached-invalid.wast b/test/core/unreached-invalid.wast index 3ddd77385f..aeecf28c2f 100644 --- a/test/core/unreached-invalid.wast +++ b/test/core/unreached-invalid.wast @@ -536,6 +536,21 @@ "type mismatch" ) +(assert_invalid + (module (func $type-br_table-label-num-vs-label-num-after-unreachable + (block (result f64) + (block (result f32) + (unreachable) + (br_table 0 1 1 (i32.const 1)) + ) + (drop) + (f64.const 0) + ) + (drop) + )) + "type mismatch" +) + (assert_invalid (module (func $type-block-value-nested-unreachable-num-vs-void (block (i32.const 3) (block (unreachable))) From a83b16e433d33e6e41c3add097e8297f77fcc899 Mon Sep 17 00:00:00 2001 From: gahaas Date: Mon, 18 May 2020 10:21:39 +0200 Subject: [PATCH 166/199] [tests] Delete leftover harness function (#92) In the generated test files the generic imports contained a function that does not exist anymore. This caused all tests to fail. This PR removes the function from the imports. --- interpreter/script/js.ml | 1 - 1 file changed, 1 deletion(-) diff --git a/interpreter/script/js.ml b/interpreter/script/js.ml index a68e224186..27a0b5daf0 100644 --- a/interpreter/script/js.ml +++ b/interpreter/script/js.ml @@ -33,7 +33,6 @@ let spectest = { externref: externref, is_externref: is_externref, is_funcref: is_funcref, - eq_ref: eq_ref, print: console.log.bind(console), print_i32: console.log.bind(console), print_i32_f32: console.log.bind(console), From f23154ef3cd70ae577491bd048be6964769236ca Mon Sep 17 00:00:00 2001 From: Andreas Rossberg Date: Tue, 19 May 2020 13:08:58 +0200 Subject: [PATCH 167/199] [interpreter] Improve error message --- interpreter/valid/valid.ml | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/interpreter/valid/valid.ml b/interpreter/valid/valid.ml index 7dbe96647c..596bee2256 100644 --- a/interpreter/valid/valid.ml +++ b/interpreter/valid/valid.ml @@ -316,8 +316,8 @@ let rec check_instr (c : context) (e : instr) (s : infer_stack_type) : op_type = let TableType (_lim1, t1) = table c x in let t2 = elem c y in require (t1 = t2) x.at - ("type mismatch: source element type " ^ string_of_ref_type t1 ^ - " does not match destination element type " ^ string_of_ref_type t2); + ("type mismatch: element segment's type " ^ string_of_ref_type t1 ^ + " does not match table's element type " ^ string_of_ref_type t2); [NumType I32Type; NumType I32Type; NumType I32Type] --> [] | ElemDrop x -> @@ -511,7 +511,8 @@ let check_elem_mode (c : context) (t : ref_type) (mode : segment_mode) = | Active {index; offset} -> let TableType (_, et) = table c index in require (t = et) mode.at - "type mismatch in active element segment"; + ("type mismatch: element segment's type " ^ string_of_ref_type t ^ + " does not match table's element type " ^ string_of_ref_type et); check_const c offset (NumType I32Type) | Declarative -> () From 8dd9a90f92fb6b9d34c159d3e9ec5b46947526ed Mon Sep 17 00:00:00 2001 From: gahaas Date: Wed, 20 May 2020 15:43:55 +0200 Subject: [PATCH 168/199] [test] Fix JS harness and binary test (#95) --- interpreter/script/js.ml | 2 ++ test/core/binary-leb128.wast | 5 +++-- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/interpreter/script/js.ml b/interpreter/script/js.ml index 27a0b5daf0..804deef06c 100644 --- a/interpreter/script/js.ml +++ b/interpreter/script/js.ml @@ -33,6 +33,8 @@ let spectest = { externref: externref, is_externref: is_externref, is_funcref: is_funcref, + eq_externref: eq_externref, + eq_funcref: eq_funcref, print: console.log.bind(console), print_i32: console.log.bind(console), print_i32_f32: console.log.bind(console), diff --git a/test/core/binary-leb128.wast b/test/core/binary-leb128.wast index 9afcb540ce..e147c980cf 100644 --- a/test/core/binary-leb128.wast +++ b/test/core/binary-leb128.wast @@ -33,9 +33,10 @@ "\00asm" "\01\00\00\00" "\04\04\01" ;; Table section with 1 entry "\70\00\00" ;; no max, minimum 0, funcref - "\09\07\01" ;; Element section with 1 entry + "\09\09\01" ;; Element section with 1 entry + "\02" ;; Element with explicit table index "\80\00" ;; Table index 0, encoded with 2 bytes - "\41\00\0b\00" ;; (i32.const 0) with no elements + "\41\00\0b\00\00" ;; (i32.const 0) with no elements ) (module binary "\00asm" "\01\00\00\00" From 5bc46bbd387b51f52ee0088e76ff401ece0c8e4a Mon Sep 17 00:00:00 2001 From: Ms2ger Date: Mon, 25 May 2020 12:49:05 +0200 Subject: [PATCH 169/199] [js-api] More subtyping removal. (#96) * [js-api] Link to the fork for the core specification. * [js-api] More subtyping removal. * [js-api] Fix bugs in Table constructor. * Add an assertion to ToWebAssemblyValue. --- document/js-api/index.bs | 52 +++++++++++++++++++--------------------- 1 file changed, 25 insertions(+), 27 deletions(-) diff --git a/document/js-api/index.bs b/document/js-api/index.bs index 55ebf5f156..c784b27398 100644 --- a/document/js-api/index.bs +++ b/document/js-api/index.bs @@ -91,7 +91,7 @@ urlPrefix: https://tc39.github.io/ecma262/; spec: ECMASCRIPT text: IterableToList; url: sec-iterabletolist type: abstract-op text: CreateMethodProperty; url: sec-createmethodproperty -urlPrefix: https://webassembly.github.io/spec/core/; spec: WebAssembly; type: dfn +urlPrefix: https://webassembly.github.io/reference-types/core/; spec: WebAssembly; type: dfn url: valid/modules.html#valid-module text: valid text: WebAssembly module validation @@ -110,6 +110,7 @@ urlPrefix: https://webassembly.github.io/spec/core/; spec: WebAssembly; type: df text: f64.const text: ref.null text: ref.func + text: ref.extern text: function index; url: syntax/modules.html#syntax-funcidx text: function instance; url: exec/runtime.html#function-instances text: store_init; url: appendix/embedding.html#embed-store-init @@ -145,6 +146,7 @@ urlPrefix: https://webassembly.github.io/spec/core/; spec: WebAssembly; type: df text: function address; url: exec/runtime.html#syntax-funcaddr text: memory address; url: exec/runtime.html#syntax-memaddr text: global address; url: exec/runtime.html#syntax-globaladdr + text: extern address; url: exec/runtime.html#syntax-externaddr url: syntax/types.html#syntax-numtype text: i32 text: i64 @@ -254,7 +256,7 @@ Each [=agent=] is associated with the following [=ordered map=]s: * The Table object cache, mapping [=table address=]es to {{Table}} objects. * The Exported Function cache, mapping [=function address=]es to [=Exported Function=] objects. * The Global object cache, mapping [=global address=]es to {{Global}} objects. - * The Host value cache, mapping [=host address=]es to values. + * The Extern value cache, mapping [=extern address=]es to values.

    The WebAssembly Namespace

    @@ -754,7 +756,7 @@ Each {{Table}} object has the following internal slots:
    The Table(|descriptor|, |value|) constructor, when invoked, performs the following steps: - 1. Let |elementType| be ToValueType(descriptor|["element"]). + 1. Let |elementType| be [=ToValueType=](|descriptor|["element"]). 1. let |initial| be |descriptor|["initial"]. 1. If |descriptor|["maximum"] [=map/exists=], let |maximum| be |descriptor|["maximum"]; otherwise, let |maximum| be empty. 1. If |maximum| is not empty and |maximum| < |initial|, throw a {{RangeError}} exception. @@ -762,7 +764,7 @@ Each {{Table}} object has the following internal slots: 1. Let |ref| be [=DefaultValue=](|elementType|). 1. Otherwise, 1. Let |ref| be ? [=ToWebAssemblyValue=](|value|, |elementType|). - 1. Let |type| be the [=table type=] {[=table type|min=] |initial|, [=table type|ma𝗑=] |maximum|} [=table type|an𝗒func=]. + 1. Let |type| be the [=table type=] {[=table type|min=] |initial|, [=table type|ma𝗑=] |maximum|} |elementType|. 1. Let |store| be the [=surrounding agent=]'s [=associated store=]. 1. Let (|store|, |tableaddr|) be [=table_alloc=](|store|, |type|, |ref|). 1. Set the [=surrounding agent=]'s [=associated store=] to |store|. @@ -1065,9 +1067,9 @@ The algorithm ToJSValue(|w|) coerces a [=WebAssembly value=] to a Jav 1. If |w| is of the form [=i32.const=] |i32|, return [=the Number value=] for [=signed_32=](|i32|). 1. If |w| is of the form [=f32.const=] |f32|, return [=the Number value=] for |f32|. 1. If |w| is of the form [=f64.const=] |f64|, return [=the Number value=] for |f64|. -1. If |w| is of the form [=ref.null=], return null. +1. If |w| is of the form [=ref.null=] t, return null. 1. If |w| is of the form [=ref.func=] |funcaddr|, return the result of creating [=a new Exported Function=] from |funcaddr|. -1. If |w| is of the form [=ref.host=] |hostaddr|, return the result of [=retrieving a host value=] from |hostaddr|. +1. If |w| is of the form [=ref.extern=] |externaddr|, return the result of [=retrieving an extern value=] from |externaddr|. @@ -1075,10 +1077,10 @@ Note: Number values which are equal to NaN may have various observable NaN paylo
    - For retrieving a host value from a [=host address=] |hostaddr|, perform the following steps: - 1. Let |map| be the [=surrounding agent=]'s associated [=host value cache=]. - 1. Assert: |map|[|hostaddr|] [=map/exists=]. - 1. Return |map|[|hostaddr|]. + For retrieving an extern value from a [=extern address=] |externaddr|, perform the following steps: + 1. Let |map| be the [=surrounding agent=]'s associated [=extern value cache=]. + 1. Assert: |map|[|externaddr|] [=map/exists=]. + 1. Return |map|[|externaddr|].
    @@ -1095,28 +1097,24 @@ The algorithm ToWebAssemblyValue(|v|, |type|) coerces a JavaScript va 1. If |type| is [=f64=], 1. Let |f64| be ? [=ToNumber=](|v|). 1. Return [=f64.const=] |f64|. -1. Assert: |type| is a reference type. -1. If |type| is [=externref=], - 1. Do nothing. 1. If |type| is [=funcref=], - 1. If |v| is not an [=Exported function=] or null, throw a {{TypeError}}. -1. Return the result of [=allocating a host address=] for |v|. - -
    - -
    - For allocating a host address for a value |v|, perform the following steps: 1. If |v| is null, - 1. Return [=ref.null=]. + 1. Return [=ref.null=] [=funcref=]. 1. If |v| is an [=Exported Function=], 1. Let |funcaddr| be the value of |v|'s \[[FunctionAddress]] internal slot. 1. Return [=ref.func=] |funcaddr|. - 1. Let |map| be the [=surrounding agent=]'s associated [=host value cache=]. - 1. If a [=host address=] |hostaddr| exists such that |map|[|hostaddr|] is the same as |v|, - 1. Return [=ref.host=] |hostaddr|. - 1. Let [=host address=] |hostaddr| be the smallest address such that |map|[|hostaddr|] [=map/exists=] is false. - 1. [=map/Set=] |map|[|hostaddr|] to |v|. - 1. Return [=ref.host=] |hostaddr|. + 1. Throw a {{TypeError}}. +1. If |type| is [=externref=], + 1. If |v| is null, + 1. Return [=ref.null=] [=externref=]. + 1. Let |map| be the [=surrounding agent=]'s associated [=extern value cache=]. + 1. If a [=extern address=] |externaddr| exists such that |map|[|externaddr|] is the same as |v|, + 1. Return [=ref.extern=] |externaddr|. + 1. Let [=extern address=] |externaddr| be the smallest address such that |map|[|externaddr|] [=map/exists=] is false. + 1. [=map/Set=] |map|[|externaddr|] to |v|. + 1. Return [=ref.extern=] |externaddr|. +1. Assert: This step is not reached. +
    From b4f254b6bf571c8c51202c9689be028fdced4107 Mon Sep 17 00:00:00 2001 From: Andreas Rossberg Date: Fri, 5 Jun 2020 10:10:32 +0200 Subject: [PATCH 170/199] Add select to Overview --- proposals/reference-types/Overview.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/proposals/reference-types/Overview.md b/proposals/reference-types/Overview.md index 14ff3b4163..0e258e7267 100644 --- a/proposals/reference-types/Overview.md +++ b/proposals/reference-types/Overview.md @@ -60,6 +60,11 @@ Typing extensions: New/extended instructions: +* The `select` instruction now optionally takes a value type immediate. Only annotated `select` can be used with reference types. + - `select : [t t i32] -> [t]` + - iff `t` is a `numtype` + - `select t : [t t i32] -> [t]` + * The new instruction `ref.null` evaluates to the null reference constant. - `ref.null rt : [] -> [rtref]` - iff `rt = func` or `rt = extern` From f18a4eb997d276c41596ea53bd649f9509000012 Mon Sep 17 00:00:00 2001 From: Andreas Rossberg Date: Tue, 9 Jun 2020 19:20:29 +0200 Subject: [PATCH 171/199] Fix off-by-one in spec --- document/core/valid/types.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/document/core/valid/types.rst b/document/core/valid/types.rst index 8c97856910..214014564c 100644 --- a/document/core/valid/types.rst +++ b/document/core/valid/types.rst @@ -111,13 +111,13 @@ Table Types :math:`\limits~\reftype` ........................ -* The limits :math:`\limits` must be :ref:`valid ` within range :math:`2^{32}`. +* The limits :math:`\limits` must be :ref:`valid ` within range :math:`2^{32}-1`. * Then the table type is valid. .. math:: \frac{ - \vdashlimits \limits : 2^{32} + \vdashlimits \limits : 2^{32} - 1 }{ \vdashtabletype \limits~\reftype \ok } From 6c0beae408aefae08481d6beff22875268cc7a54 Mon Sep 17 00:00:00 2001 From: Andreas Rossberg Date: Wed, 10 Jun 2020 08:46:12 +0200 Subject: [PATCH 172/199] Remove type annotation on ref.is_null (#100) --- document/core/appendix/index-instructions.rst | 2 +- document/core/binary/instructions.rst | 2 +- document/core/exec/instructions.rst | 8 ++++---- document/core/syntax/instructions.rst | 2 +- document/core/text/instructions.rst | 2 +- document/core/valid/instructions.rst | 9 +++++---- interpreter/binary/decode.ml | 2 +- interpreter/binary/encode.ml | 2 +- interpreter/exec/eval.ml | 2 +- interpreter/script/js.ml | 2 +- interpreter/syntax/ast.ml | 2 +- interpreter/syntax/free.ml | 2 +- interpreter/syntax/operators.ml | 2 +- interpreter/text/arrange.ml | 2 +- interpreter/text/parser.mly | 2 +- interpreter/valid/valid.ml | 8 ++++++-- test/core/ref_func.wast | 6 +++--- test/core/ref_is_null.wast | 4 ++-- test/core/table_get.wast | 2 +- test/core/table_grow.wast | 2 +- test/core/table_set.wast | 2 +- 21 files changed, 36 insertions(+), 31 deletions(-) diff --git a/document/core/appendix/index-instructions.rst b/document/core/appendix/index-instructions.rst index e0c683cedb..694b47d02c 100644 --- a/document/core/appendix/index-instructions.rst +++ b/document/core/appendix/index-instructions.rst @@ -221,7 +221,7 @@ Instruction Binary Opcode Type (reserved) :math:`\hex{CE}` (reserved) :math:`\hex{CF}` :math:`\REFNULL~t` :math:`\hex{D0}` :math:`[] \to [t]` :ref:`validation ` :ref:`execution ` -:math:`\REFISNULL~t` :math:`\hex{D1}` :math:`[t] \to [\I32]` :ref:`validation ` :ref:`execution ` +:math:`\REFISNULL` :math:`\hex{D1}` :math:`[t] \to [\I32]` :ref:`validation ` :ref:`execution ` :math:`\REFFUNC~x` :math:`\hex{D2}` :math:`[] \to [\FUNCREF]` :ref:`validation ` :ref:`execution ` (reserved) :math:`\hex{D3}` (reserved) :math:`\hex{D4}` diff --git a/document/core/binary/instructions.rst b/document/core/binary/instructions.rst index b6c60661f4..23ee488978 100644 --- a/document/core/binary/instructions.rst +++ b/document/core/binary/instructions.rst @@ -91,7 +91,7 @@ Reference Instructions \begin{array}{llclll} \production{instruction} & \Binstr &::=& \dots \\ &&|& \hex{D0}~~t{:}\Breftype &\Rightarrow& \REFNULL~t \\ &&|& - \hex{D1}~~t{:}\Breftype &\Rightarrow& \REFISNULL~t \\ &&|& + \hex{D1} &\Rightarrow& \REFISNULL \\ &&|& \hex{D2}~~x{:}\Bfuncidx &\Rightarrow& \REFFUNC~x \\ \end{array} diff --git a/document/core/exec/instructions.rst b/document/core/exec/instructions.rst index dd364c28ec..20822a28aa 100644 --- a/document/core/exec/instructions.rst +++ b/document/core/exec/instructions.rst @@ -203,8 +203,8 @@ Reference Instructions .. _exec-ref.is_null: -:math:`\REFISNULL~t` -.................... +:math:`\REFISNULL` +.................. 1. Assert: due to :ref:`validation `, a :ref:`reference value ` is on the top of the stack. @@ -220,9 +220,9 @@ Reference Instructions .. math:: \begin{array}{lcl@{\qquad}l} - \val~\REFISNULL~t &\stepto& \I32.\CONST~1 + \val~\REFISNULL &\stepto& \I32.\CONST~1 & (\iff \val = \REFNULL~t) \\ - \val~\REFISNULL~t &\stepto& \I32.\CONST~0 + \val~\REFISNULL &\stepto& \I32.\CONST~0 & (\otherwise) \\ \end{array} diff --git a/document/core/syntax/instructions.rst b/document/core/syntax/instructions.rst index 03db47d3cc..85c641f01e 100644 --- a/document/core/syntax/instructions.rst +++ b/document/core/syntax/instructions.rst @@ -187,7 +187,7 @@ Instructions in this group are concerned with accessing :ref:`references ` :math:`t`. .. math:: \frac{ + t = \reftype }{ - C \vdashinstr \REFISNULL~t : [t] \to [\I32] + C \vdashinstr \REFISNULL : [t] \to [\I32] } .. _valid-ref.func: diff --git a/interpreter/binary/decode.ml b/interpreter/binary/decode.ml index e9561c4c52..93e180d630 100644 --- a/interpreter/binary/decode.ml +++ b/interpreter/binary/decode.ml @@ -453,7 +453,7 @@ let rec instr s = | 0xcc | 0xcd | 0xce | 0xcf as b -> illegal s pos b | 0xd0 -> ref_null (ref_type s) - | 0xd1 -> ref_is_null (ref_type s) + | 0xd1 -> ref_is_null | 0xd2 -> ref_func (at var s) | 0xfc as b1 -> diff --git a/interpreter/binary/encode.ml b/interpreter/binary/encode.ml index 0132d0d4eb..9c44f5f0bb 100644 --- a/interpreter/binary/encode.ml +++ b/interpreter/binary/encode.ml @@ -230,7 +230,7 @@ let encode m = | DataDrop x -> op 0xfc; op 0x09; var x | RefNull t -> op 0xd0; ref_type t - | RefIsNull t -> op 0xd1; ref_type t + | RefIsNull -> op 0xd1 | RefFunc x -> op 0xd2; var x | Const {it = I32 c; _} -> op 0x41; vs32 c diff --git a/interpreter/exec/eval.ml b/interpreter/exec/eval.ml index 813f75d4f7..0db5a228a9 100644 --- a/interpreter/exec/eval.ml +++ b/interpreter/exec/eval.ml @@ -427,7 +427,7 @@ let rec step (c : config) : config = | RefNull t, vs' -> Ref (NullRef t) :: vs', [] - | RefIsNull _, Ref r :: vs' -> + | RefIsNull, Ref r :: vs' -> (match r with | NullRef _ -> Num (I32 1l) :: vs', [] diff --git a/interpreter/script/js.ml b/interpreter/script/js.ml index 804deef06c..ae2d14c806 100644 --- a/interpreter/script/js.ml +++ b/interpreter/script/js.ml @@ -287,7 +287,7 @@ let assert_return ress ts at = Test (Values.I32 I32Op.Eqz) @@ at; BrIf (0l @@ at) @@ at ] | LitResult {it = Values.Ref (Values.NullRef t); _} -> - [ RefIsNull t @@ at; + [ RefIsNull @@ at; Test (Values.I32 I32Op.Eqz) @@ at; BrIf (0l @@ at) @@ at ] | LitResult {it = Values.Ref (ExternRef n); _} -> diff --git a/interpreter/syntax/ast.ml b/interpreter/syntax/ast.ml index 8add923dc3..38e5506256 100644 --- a/interpreter/syntax/ast.ml +++ b/interpreter/syntax/ast.ml @@ -106,7 +106,7 @@ and instr' = | MemoryInit of var (* initialize memory range from segment *) | DataDrop of var (* drop passive data segment *) | RefNull of ref_type (* null reference *) - | RefIsNull of ref_type (* null test *) + | RefIsNull (* null test *) | RefFunc of var (* function reference *) | Const of num (* constant *) | Test of testop (* numeric test *) diff --git a/interpreter/syntax/free.ml b/interpreter/syntax/free.ml index fb8973cf49..33bfefc0aa 100644 --- a/interpreter/syntax/free.ml +++ b/interpreter/syntax/free.ml @@ -62,7 +62,7 @@ let list free xs = List.fold_left union empty (List.map free xs) let rec instr (e : instr) = match e.it with | Unreachable | Nop | Drop | Select _ -> empty - | RefNull _ | RefIsNull _ -> empty + | RefNull _ | RefIsNull -> empty | RefFunc x -> funcs (var x) | Const _ | Test _ | Compare _ | Unary _ | Binary _ | Convert _ -> empty | Block (_, es) | Loop (_, es) -> block es diff --git a/interpreter/syntax/operators.ml b/interpreter/syntax/operators.ml index f9583188b1..2b80b627c9 100644 --- a/interpreter/syntax/operators.ml +++ b/interpreter/syntax/operators.ml @@ -10,7 +10,7 @@ let f32_const n = Const (F32 n.it @@ n.at) let f64_const n = Const (F64 n.it @@ n.at) let ref_func x = RefFunc x let ref_null t = RefNull t -let ref_is_null t = RefIsNull t +let ref_is_null = RefIsNull let unreachable = Unreachable let nop = Nop diff --git a/interpreter/text/arrange.ml b/interpreter/text/arrange.ml index ffb12794ee..01e9c8adbd 100644 --- a/interpreter/text/arrange.ml +++ b/interpreter/text/arrange.ml @@ -271,7 +271,7 @@ let rec instr e = | MemoryInit x -> "memory.init " ^ var x, [] | DataDrop x -> "data.drop " ^ var x, [] | RefNull t -> "ref.null", [Atom (refed_type t)] - | RefIsNull t -> "ref.is_null", [Atom (refed_type t)] + | RefIsNull -> "ref.is_null", [] | RefFunc x -> "ref.func " ^ var x, [] | Const n -> constop n ^ " " ^ num n, [] | Test op -> testop op, [] diff --git a/interpreter/text/parser.mly b/interpreter/text/parser.mly index 04a3993e08..33a9bc5ac2 100644 --- a/interpreter/text/parser.mly +++ b/interpreter/text/parser.mly @@ -376,7 +376,7 @@ plain_instr : | MEMORY_INIT var { fun c -> memory_init ($2 c data) } | DATA_DROP var { fun c -> data_drop ($2 c data) } | REF_NULL ref_kind { fun c -> ref_null $2 } - | REF_IS_NULL ref_kind { fun c -> ref_is_null $2 } + | REF_IS_NULL { fun c -> ref_is_null } | REF_FUNC var { fun c -> ref_func ($2 c func) } | CONST num { fun c -> fst (num $1 $2) } | TEST { fun c -> $1 } diff --git a/interpreter/valid/valid.ml b/interpreter/valid/valid.ml index 596bee2256..5aecc31832 100644 --- a/interpreter/valid/valid.ml +++ b/interpreter/valid/valid.ml @@ -360,8 +360,12 @@ let rec check_instr (c : context) (e : instr) (s : infer_stack_type) : op_type = | RefNull t -> [] --> [RefType t] - | RefIsNull t -> - [RefType t] --> [NumType I32Type] + | RefIsNull -> + let t = peek 1 s in + require (match t with None -> true | Some t -> is_ref_type t) e.at + ("type mismatch: instruction requires reference type" ^ + " but stack has " ^ string_of_infer_type t); + [t] -~> [Some (NumType I32Type)] | RefFunc x -> let _ft = func c x in diff --git a/test/core/ref_func.wast b/test/core/ref_func.wast index c0c5a0cc72..adb5cb788d 100644 --- a/test/core/ref_func.wast +++ b/test/core/ref_func.wast @@ -24,13 +24,13 @@ (func $ff2) (func (export "is_null-f") (result i32) - (ref.is_null func (ref.func $f)) + (ref.is_null (ref.func $f)) ) (func (export "is_null-g") (result i32) - (ref.is_null func (ref.func $g)) + (ref.is_null (ref.func $g)) ) (func (export "is_null-v") (result i32) - (ref.is_null func (global.get $v)) + (ref.is_null (global.get $v)) ) (func (export "set-f") (global.set $v (ref.func $f))) diff --git a/test/core/ref_is_null.wast b/test/core/ref_is_null.wast index 7c01bb5410..5d624a0f85 100644 --- a/test/core/ref_is_null.wast +++ b/test/core/ref_is_null.wast @@ -1,9 +1,9 @@ (module (func $f1 (export "funcref") (param $x funcref) (result i32) - (ref.is_null func (local.get $x)) + (ref.is_null (local.get $x)) ) (func $f2 (export "externref") (param $x externref) (result i32) - (ref.is_null extern (local.get $x)) + (ref.is_null (local.get $x)) ) (table $t1 2 funcref) diff --git a/test/core/table_get.wast b/test/core/table_get.wast index 3df7190e37..0cb0c3c4a7 100644 --- a/test/core/table_get.wast +++ b/test/core/table_get.wast @@ -17,7 +17,7 @@ ) (func (export "is_null-funcref") (param $i i32) (result i32) - (ref.is_null func (call $f3 (local.get $i))) + (ref.is_null (call $f3 (local.get $i))) ) ) diff --git a/test/core/table_grow.wast b/test/core/table_grow.wast index 2b992ff7d7..7d5b5630fc 100644 --- a/test/core/table_grow.wast +++ b/test/core/table_grow.wast @@ -90,7 +90,7 @@ (block (loop (local.set 2 (table.get $t (local.get 0))) - (br_if 1 (i32.eqz (ref.is_null func (local.get 2)))) + (br_if 1 (i32.eqz (ref.is_null (local.get 2)))) (br_if 1 (i32.ge_u (local.get 0) (local.get 1))) (local.set 0 (i32.add (local.get 0) (i32.const 1))) (br_if 0 (i32.le_u (local.get 0) (local.get 1))) diff --git a/test/core/table_set.wast b/test/core/table_set.wast index 6da9db87d6..f37ef14d6c 100644 --- a/test/core/table_set.wast +++ b/test/core/table_set.wast @@ -22,7 +22,7 @@ ) (func (export "is_null-funcref") (param $i i32) (result i32) - (ref.is_null func (call $f3 (local.get $i))) + (ref.is_null (call $f3 (local.get $i))) ) ) From b583fad682d7fc28d6ee938cdea5e3fcc2ab7ac4 Mon Sep 17 00:00:00 2001 From: Andreas Rossberg Date: Wed, 10 Jun 2020 11:11:10 +0200 Subject: [PATCH 173/199] [interpreter] Hot fix --- interpreter/valid/valid.ml | 18 ++++++++++++------ test/core/ref_is_null.wast | 9 +++++++++ 2 files changed, 21 insertions(+), 6 deletions(-) diff --git a/interpreter/valid/valid.ml b/interpreter/valid/valid.ml index 5aecc31832..8d8db820a9 100644 --- a/interpreter/valid/valid.ml +++ b/interpreter/valid/valid.ml @@ -87,7 +87,7 @@ let string_of_infer_types ts = let eq_ty t1 t2 = (t1 = t2 || t1 = None || t2 = None) let check_stack ts1 ts2 at = require (List.length ts1 = List.length ts2 && List.for_all2 eq_ty ts1 ts2) at - ("type mismatch: operator requires " ^ string_of_infer_types ts1 ^ + ("type mismatch: instruction requires " ^ string_of_infer_types ts1 ^ " but stack has " ^ string_of_infer_types ts2) let pop (ell1, ts1) (ell2, ts2) at = @@ -103,8 +103,14 @@ let push (ell1, ts1) (ell2, ts2) = (if ell1 = Ellipses || ell2 = Ellipses then Ellipses else NoEllipses), ts2 @ ts1 -let peek i (ell, ts) = - try List.nth (List.rev ts) i with Failure _ -> None +let peek i (ell, ts) at = + try + List.nth (List.rev ts) i + with Failure _ -> + require (ell = Ellipses) at + ("type mismatch: instruction requires at least " ^ string_of_int (i + 1) ^ + " operand(s) but stack has " ^ string_of_infer_types ts); + None (* Type Synthesis *) @@ -211,10 +217,10 @@ let rec check_instr (c : context) (e : instr) (s : infer_stack_type) : op_type = [] --> [] | Drop -> - [peek 0 s] -~> [] + [peek 0 s e.at] -~> [] | Select None -> - let t = peek 1 s in + let t = peek 1 s e.at in require (match t with None -> true | Some t -> is_num_type t) e.at ("type mismatch: instruction requires numeric type" ^ " but stack has " ^ string_of_infer_type t); @@ -361,7 +367,7 @@ let rec check_instr (c : context) (e : instr) (s : infer_stack_type) : op_type = [] --> [RefType t] | RefIsNull -> - let t = peek 1 s in + let t = peek 0 s e.at in require (match t with None -> true | Some t -> is_ref_type t) e.at ("type mismatch: instruction requires reference type" ^ " but stack has " ^ string_of_infer_type t); diff --git a/test/core/ref_is_null.wast b/test/core/ref_is_null.wast index 5d624a0f85..8396da4a7e 100644 --- a/test/core/ref_is_null.wast +++ b/test/core/ref_is_null.wast @@ -47,3 +47,12 @@ (assert_return (invoke "funcref-elem" (i32.const 1)) (i32.const 1)) (assert_return (invoke "externref-elem" (i32.const 1)) (i32.const 1)) + +(assert_invalid + (module (func $ref-vs-num (param i32) (ref.is_null (local.get 0)))) + "type mismatch" +) +(assert_invalid + (module (func $ref-vs-empty (ref.is_null))) + "type mismatch" +) From 7ab584608356afefcf8589dde7c552b9320b01d6 Mon Sep 17 00:00:00 2001 From: Andreas Rossberg Date: Wed, 10 Jun 2020 11:15:19 +0200 Subject: [PATCH 174/199] [interpreter] Simplify hot fix --- interpreter/valid/valid.ml | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/interpreter/valid/valid.ml b/interpreter/valid/valid.ml index 8d8db820a9..4ba2f7dd07 100644 --- a/interpreter/valid/valid.ml +++ b/interpreter/valid/valid.ml @@ -104,13 +104,7 @@ let push (ell1, ts1) (ell2, ts2) = ts2 @ ts1 let peek i (ell, ts) at = - try - List.nth (List.rev ts) i - with Failure _ -> - require (ell = Ellipses) at - ("type mismatch: instruction requires at least " ^ string_of_int (i + 1) ^ - " operand(s) but stack has " ^ string_of_infer_types ts); - None + try List.nth (List.rev ts) i with Failure _ -> None (* Type Synthesis *) From da20676706a9442812a2c167e3a16c723f165cbc Mon Sep 17 00:00:00 2001 From: Andreas Rossberg Date: Wed, 10 Jun 2020 11:38:29 +0200 Subject: [PATCH 175/199] [interpreter] ARgh --- interpreter/valid/valid.ml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/interpreter/valid/valid.ml b/interpreter/valid/valid.ml index 4ba2f7dd07..aff90b0c30 100644 --- a/interpreter/valid/valid.ml +++ b/interpreter/valid/valid.ml @@ -103,7 +103,7 @@ let push (ell1, ts1) (ell2, ts2) = (if ell1 = Ellipses || ell2 = Ellipses then Ellipses else NoEllipses), ts2 @ ts1 -let peek i (ell, ts) at = +let peek i (ell, ts) = try List.nth (List.rev ts) i with Failure _ -> None @@ -211,10 +211,10 @@ let rec check_instr (c : context) (e : instr) (s : infer_stack_type) : op_type = [] --> [] | Drop -> - [peek 0 s e.at] -~> [] + [peek 0 s] -~> [] | Select None -> - let t = peek 1 s e.at in + let t = peek 1 s in require (match t with None -> true | Some t -> is_num_type t) e.at ("type mismatch: instruction requires numeric type" ^ " but stack has " ^ string_of_infer_type t); @@ -361,7 +361,7 @@ let rec check_instr (c : context) (e : instr) (s : infer_stack_type) : op_type = [] --> [RefType t] | RefIsNull -> - let t = peek 0 s e.at in + let t = peek 0 s in require (match t with None -> true | Some t -> is_ref_type t) e.at ("type mismatch: instruction requires reference type" ^ " but stack has " ^ string_of_infer_type t); From 9df8a3e3efe02970e6b362ad6cb6e71fc9957ea0 Mon Sep 17 00:00:00 2001 From: Andreas Rossberg Date: Wed, 17 Jun 2020 09:13:26 +0200 Subject: [PATCH 176/199] Update Overview wrt table.grow --- proposals/reference-types/Overview.md | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/proposals/reference-types/Overview.md b/proposals/reference-types/Overview.md index 0e258e7267..e0d10e7fe5 100644 --- a/proposals/reference-types/Overview.md +++ b/proposals/reference-types/Overview.md @@ -135,12 +135,15 @@ Table extensions: - For backwards compatibility, the index may be omitted in the text format, in which case it defaults to 0. -API extensions: +JS API extensions: * Any JS value can be passed as `externref` to a Wasm function, stored in a global, or in a table. * Any Wasm exported function object or `null` can be passed as `funcref` to a Wasm function, stored in a global, or in a table. +* The `WebAssembly.Table#grow` method takes an additional initialisation argument. + - optional for backwards compatibility, defaults to default value of respective type + ## Possible Future Extensions @@ -212,11 +215,6 @@ Additions: * Typed function references cannot be null! -* The `table.grow` instruction (see the [bulk operation proposal](https://github.com/WebAssembly/bulk-memory-operations/blob/master/proposals/bulk-memory-operations/Overview.md)) needs to take an initialisation argument. - -* Likewise `WebAssembly.Table#grow` takes an additional initialisation argument. - - optional for backwards compatibility, defaults to `null` - ### Type Import/Export From 401c8eb929d6ee4ec0e7d6c2963997d15324f0b4 Mon Sep 17 00:00:00 2001 From: Nick Fitzgerald Date: Mon, 22 Jun 2020 00:40:11 -0700 Subject: [PATCH 177/199] Fix links to `table.fill`'s validation and execution in appendix (#103) --- document/core/appendix/index-instructions.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/document/core/appendix/index-instructions.rst b/document/core/appendix/index-instructions.rst index 694b47d02c..223efccfe3 100644 --- a/document/core/appendix/index-instructions.rst +++ b/document/core/appendix/index-instructions.rst @@ -265,7 +265,7 @@ Instruction Binary Opcode Type :math:`\TABLECOPY` :math:`\hex{FC}~\hex{0E}` :math:`[\I32~\I32~\I32] \to []` :ref:`validation ` :ref:`execution ` :math:`\TABLEGROW` :math:`\hex{FC}~\hex{0F}` :math:`[t~\I32] \to []` :ref:`validation ` :ref:`execution ` :math:`\TABLESIZE` :math:`\hex{FC}~\hex{10}` :math:`[] \to []` :ref:`validation ` :ref:`execution ` -:math:`\TABLEFILL` :math:`\hex{FC}~\hex{11}` :math:`[\I32~t~\I32] \to []` :ref:`validation ` :ref:`execution ` +:math:`\TABLEFILL` :math:`\hex{FC}~\hex{11}` :math:`[\I32~t~\I32] \to []` :ref:`validation ` :ref:`execution ` (reserved) :math:`\hex{FD}` (reserved) :math:`\hex{FE}` (reserved) :math:`\hex{FF}` From 1e652dda77308bae38942c167b622be31041cc22 Mon Sep 17 00:00:00 2001 From: Nick Fitzgerald Date: Wed, 15 Jul 2020 23:41:26 -0700 Subject: [PATCH 178/199] Add a test for mutating `externref` globals (#104) While `linking.wast` tests that we can link modules that are importing and exporting mutable `externref` globals, there were no tests exercising `global.{get,set}` on mutable `externref` globals. --- test/core/global.wast | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/test/core/global.wast b/test/core/global.wast index a19ae5e739..c98037aeb8 100644 --- a/test/core/global.wast +++ b/test/core/global.wast @@ -12,15 +12,18 @@ (global $y (mut i64) (i64.const -15)) (global $r externref (ref.null extern)) + (global $mr (mut externref) (ref.null extern)) (global funcref (ref.null func)) (func (export "get-a") (result i32) (global.get $a)) (func (export "get-b") (result i64) (global.get $b)) (func (export "get-r") (result externref) (global.get $r)) + (func (export "get-mr") (result externref) (global.get $mr)) (func (export "get-x") (result i32) (global.get $x)) (func (export "get-y") (result i64) (global.get $y)) (func (export "set-x") (param i32) (global.set $x (local.get 0))) (func (export "set-y") (param i64) (global.set $y (local.get 0))) + (func (export "set-mr") (param externref) (global.set $mr (local.get 0))) (func (export "get-1") (result f32) (global.get 1)) (func (export "get-2") (result f64) (global.get 2)) @@ -185,6 +188,7 @@ (assert_return (invoke "get-a") (i32.const -2)) (assert_return (invoke "get-b") (i64.const -5)) (assert_return (invoke "get-r") (ref.null extern)) +(assert_return (invoke "get-mr") (ref.null extern)) (assert_return (invoke "get-x") (i32.const -12)) (assert_return (invoke "get-y") (i64.const -15)) @@ -197,11 +201,13 @@ (assert_return (invoke "set-y" (i64.const 7))) (assert_return (invoke "set-5" (f32.const 8))) (assert_return (invoke "set-6" (f64.const 9))) +(assert_return (invoke "set-mr" (ref.extern 10))) (assert_return (invoke "get-x") (i32.const 6)) (assert_return (invoke "get-y") (i64.const 7)) (assert_return (invoke "get-5") (f32.const 8)) (assert_return (invoke "get-6") (f64.const 9)) +(assert_return (invoke "get-mr") (ref.extern 10)) (assert_return (invoke "as-select-first") (i32.const 6)) (assert_return (invoke "as-select-mid") (i32.const 2)) From c360086d82ef6338329301de88db4b8b1be41892 Mon Sep 17 00:00:00 2001 From: Nick Fitzgerald Date: Tue, 21 Jul 2020 09:51:29 -0700 Subject: [PATCH 179/199] table.fill: Bounds check before mutating the table (#106) Fixes https://github.com/WebAssembly/reference-types/issues/105 --- document/core/exec/instructions.rst | 53 ++++++++++++++++------------- 1 file changed, 30 insertions(+), 23 deletions(-) diff --git a/document/core/exec/instructions.rst b/document/core/exec/instructions.rst index 20822a28aa..ab3ef5b0ab 100644 --- a/document/core/exec/instructions.rst +++ b/document/core/exec/instructions.rst @@ -651,42 +651,49 @@ Table Instructions 11. Pop the value :math:`\I32.\CONST~i` from the stack. -12. If :math:`n` is :math:`0`, then: +12. If :math:`i + n` is larger than the length of :math:`\X{tab}.\TIELEM`, then: - a. If :math:`i` is larger than the length of :math:`\X{tab}.\TIELEM`, then: + a. Trap. - i. Trap. +12. If :math:`n` is :math:`0`, then: -12. Else: + a. Return. - a. Push the value :math:`\I32.CONST~i` to the stack. +13. Push the value :math:`\I32.CONST~i` to the stack. - b. Push the value :math:`\val` to the stack. +14. Push the value :math:`\val` to the stack. - c. Execute the instruction :math:`\TABLESET~x`. +15. Execute the instruction :math:`\TABLESET~x`. - d. Push the value :math:`\I32.CONST~(i+1)` to the stack. +16. Push the value :math:`\I32.CONST~(i+1)` to the stack. - e. Push the value :math:`\val` to the stack. +17. Push the value :math:`\val` to the stack. - f. Push the value :math:`\I32.CONST~(n-1)` to the stack. +18. Push the value :math:`\I32.CONST~(n-1)` to the stack. - c. Execute the instruction :math:`\TABLEFILL~x`. +19. Execute the instruction :math:`\TABLEFILL~x`. .. math:: \begin{array}{l} - \begin{array}{lcl@{\qquad}l} - S; F; (\I32.\CONST~i)~\val~(\I32.\CONST~(n+1))~(\TABLEFILL~x) &\stepto& S'; F; (\I32.\CONST~i)~\val~(\TABLESET~x)~(\I32.\CONST~(i+1))~\val~(\I32.\CONST~n)~(\TABLEFILL~x) - \end{array} \\ - \begin{array}{lcl@{\qquad}l} - S; F; (\I32.\CONST~i)~\val~(\I32.\CONST~0)~(\TABLEFILL~x) &\stepto& S'; F; \epsilon - \end{array} - \\ \qquad - (\iff i \leq |\STABLES[F.\AMODULE.\MITABLES[x]]|) \\ - \begin{array}{lcl@{\qquad}l} - S; F; (\I32.\CONST~i)~\val~(\I32.\CONST~0)~(\TABLEFILL~x) &\stepto& S; F; \TRAP - \end{array} - \\ \qquad + S; F; (\I32.\CONST~i)~\val~(\I32.\CONST~n)~(\TABLEFILL~x) + \quad\stepto\quad S; F; \TRAP + \\ \qquad + \begin{array}[t]{@{}r@{~}l@{}} + (\iff & i + n > |S.\STABLES[F.\AMODULE.\MITABLES[x]].\TIELEM|) \\ + \end{array} + \\[1ex] + S; F; (\I32.\CONST~i)~\val~(\I32.\CONST~0)~(\TABLEFILL~x) + \quad\stepto\quad S; F; \epsilon + \\ \qquad + (\otherwise) + \\[1ex] + S; F; (\I32.\CONST~i)~\val~(\I32.\CONST~n+1)~(\TABLEFILL~x) + \quad\stepto\quad S; F; + \begin{array}[t]{@{}l@{}} + (\I32.\CONST~i)~\val~(\TABLESET~x) \\ + (\I32.\CONST~i+1)~\val~(\I32.\CONST~n)~(\TABLEFILL~x) \\ + \end{array} + \\ \qquad (\otherwise) \\ \end{array} From 50e699f111381488f03ce7b09bd8e174091d1add Mon Sep 17 00:00:00 2001 From: Heejin Ahn Date: Wed, 26 Aug 2020 09:26:31 -0700 Subject: [PATCH 180/199] Remove type annotation on ref.is_null in overview See #99. --- proposals/reference-types/Overview.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/proposals/reference-types/Overview.md b/proposals/reference-types/Overview.md index e0d10e7fe5..43a36d351b 100644 --- a/proposals/reference-types/Overview.md +++ b/proposals/reference-types/Overview.md @@ -71,8 +71,7 @@ New/extended instructions: - allowed in constant expressions * The new instruction `ref.is_null` checks for null. - - `ref.is_null rt : [rtref] -> [i32]` - - iff `rt = func` or `rt = extern` + - `ref.is_null : [rtref] -> [i32]` * The new instruction `ref.func` creates a reference to a given function. - `ref.func $x : [] -> [funcref]` From ec4bcea21ef98b18503dced66ac7c6e87e43d16c Mon Sep 17 00:00:00 2001 From: Ben Smith Date: Fri, 28 Aug 2020 14:25:03 -0700 Subject: [PATCH 181/199] Update document to use u32 for opcode after prefix (#155) This has already been updated in the upstream spec, but also needs to be fixed in proposals. --- document/core/appendix/index-instructions.rst | 432 +++++++++--------- document/core/binary/instructions.rst | 14 +- 2 files changed, 223 insertions(+), 223 deletions(-) diff --git a/document/core/appendix/index-instructions.rst b/document/core/appendix/index-instructions.rst index bac73ad4fe..535549484c 100644 --- a/document/core/appendix/index-instructions.rst +++ b/document/core/appendix/index-instructions.rst @@ -4,219 +4,219 @@ Index of Instructions --------------------- -========================================= ========================= ============================================= ======================================= =============================================================== -Instruction Binary Opcode Type Validation Execution -========================================= ========================= ============================================= ======================================= =============================================================== -:math:`\UNREACHABLE` :math:`\hex{00}` :math:`[t_1^\ast] \to [t_2^\ast]` :ref:`validation ` :ref:`execution ` -:math:`\NOP` :math:`\hex{01}` :math:`[] \to []` :ref:`validation ` :ref:`execution ` -:math:`\BLOCK~\X{bt}` :math:`\hex{02}` :math:`[t_1^\ast] \to [t_2^\ast]` :ref:`validation ` :ref:`execution ` -:math:`\LOOP~\X{bt}` :math:`\hex{03}` :math:`[t_1^\ast] \to [t_2^\ast]` :ref:`validation ` :ref:`execution ` -:math:`\IF~\X{bt}` :math:`\hex{04}` :math:`[t_1^\ast] \to [t_2^\ast]` :ref:`validation ` :ref:`execution ` -:math:`\ELSE` :math:`\hex{05}` -(reserved) :math:`\hex{06}` -(reserved) :math:`\hex{07}` -(reserved) :math:`\hex{08}` -(reserved) :math:`\hex{09}` -(reserved) :math:`\hex{0A}` -:math:`\END` :math:`\hex{0B}` -:math:`\BR~l` :math:`\hex{0C}` :math:`[t_1^\ast~t^\ast] \to [t_2^\ast]` :ref:`validation ` :ref:`execution ` -:math:`\BRIF~l` :math:`\hex{0D}` :math:`[t^\ast~\I32] \to [t^\ast]` :ref:`validation ` :ref:`execution ` -:math:`\BRTABLE~l^\ast~l` :math:`\hex{0E}` :math:`[t_1^\ast~t^\ast~\I32] \to [t_2^\ast]` :ref:`validation ` :ref:`execution ` -:math:`\RETURN` :math:`\hex{0F}` :math:`[t_1^\ast~t^\ast] \to [t_2^\ast]` :ref:`validation ` :ref:`execution ` -:math:`\CALL~x` :math:`\hex{10}` :math:`[t_1^\ast] \to [t_2^\ast]` :ref:`validation ` :ref:`execution ` -:math:`\CALLINDIRECT~x` :math:`\hex{11}` :math:`[t_1^\ast~\I32] \to [t_2^\ast]` :ref:`validation ` :ref:`execution ` -(reserved) :math:`\hex{12}` -(reserved) :math:`\hex{13}` -(reserved) :math:`\hex{14}` -(reserved) :math:`\hex{15}` -(reserved) :math:`\hex{16}` -(reserved) :math:`\hex{17}` -(reserved) :math:`\hex{18}` -(reserved) :math:`\hex{19}` -:math:`\DROP` :math:`\hex{1A}` :math:`[t] \to []` :ref:`validation ` :ref:`execution ` -:math:`\SELECT` :math:`\hex{1B}` :math:`[t~t~\I32] \to [t]` :ref:`validation ` :ref:`execution ` -(reserved) :math:`\hex{1C}` -(reserved) :math:`\hex{1D}` -(reserved) :math:`\hex{1E}` -(reserved) :math:`\hex{1F}` -:math:`\LOCALGET~x` :math:`\hex{20}` :math:`[] \to [t]` :ref:`validation ` :ref:`execution ` -:math:`\LOCALSET~x` :math:`\hex{21}` :math:`[t] \to []` :ref:`validation ` :ref:`execution ` -:math:`\LOCALTEE~x` :math:`\hex{22}` :math:`[t] \to [t]` :ref:`validation ` :ref:`execution ` -:math:`\GLOBALGET~x` :math:`\hex{23}` :math:`[] \to [t]` :ref:`validation ` :ref:`execution ` -:math:`\GLOBALSET~x` :math:`\hex{24}` :math:`[t] \to []` :ref:`validation ` :ref:`execution ` -(reserved) :math:`\hex{25}` -(reserved) :math:`\hex{26}` -(reserved) :math:`\hex{27}` -:math:`\I32.\LOAD~\memarg` :math:`\hex{28}` :math:`[\I32] \to [\I32]` :ref:`validation ` :ref:`execution ` -:math:`\I64.\LOAD~\memarg` :math:`\hex{29}` :math:`[\I32] \to [\I64]` :ref:`validation ` :ref:`execution ` -:math:`\F32.\LOAD~\memarg` :math:`\hex{2A}` :math:`[\I32] \to [\F32]` :ref:`validation ` :ref:`execution ` -:math:`\F64.\LOAD~\memarg` :math:`\hex{2B}` :math:`[\I32] \to [\F64]` :ref:`validation ` :ref:`execution ` -:math:`\I32.\LOAD\K{8\_s}~\memarg` :math:`\hex{2C}` :math:`[\I32] \to [\I32]` :ref:`validation ` :ref:`execution ` -:math:`\I32.\LOAD\K{8\_u}~\memarg` :math:`\hex{2D}` :math:`[\I32] \to [\I32]` :ref:`validation ` :ref:`execution ` -:math:`\I32.\LOAD\K{16\_s}~\memarg` :math:`\hex{2E}` :math:`[\I32] \to [\I32]` :ref:`validation ` :ref:`execution ` -:math:`\I32.\LOAD\K{16\_u}~\memarg` :math:`\hex{2F}` :math:`[\I32] \to [\I32]` :ref:`validation ` :ref:`execution ` -:math:`\I64.\LOAD\K{8\_s}~\memarg` :math:`\hex{30}` :math:`[\I32] \to [\I64]` :ref:`validation ` :ref:`execution ` -:math:`\I64.\LOAD\K{8\_u}~\memarg` :math:`\hex{31}` :math:`[\I32] \to [\I64]` :ref:`validation ` :ref:`execution ` -:math:`\I64.\LOAD\K{16\_s}~\memarg` :math:`\hex{32}` :math:`[\I32] \to [\I64]` :ref:`validation ` :ref:`execution ` -:math:`\I64.\LOAD\K{16\_u}~\memarg` :math:`\hex{33}` :math:`[\I32] \to [\I64]` :ref:`validation ` :ref:`execution ` -:math:`\I64.\LOAD\K{32\_s}~\memarg` :math:`\hex{34}` :math:`[\I32] \to [\I64]` :ref:`validation ` :ref:`execution ` -:math:`\I64.\LOAD\K{32\_u}~\memarg` :math:`\hex{35}` :math:`[\I32] \to [\I64]` :ref:`validation ` :ref:`execution ` -:math:`\I32.\STORE~\memarg` :math:`\hex{36}` :math:`[\I32~\I32] \to []` :ref:`validation ` :ref:`execution ` -:math:`\I64.\STORE~\memarg` :math:`\hex{37}` :math:`[\I32~\I64] \to []` :ref:`validation ` :ref:`execution ` -:math:`\F32.\STORE~\memarg` :math:`\hex{38}` :math:`[\I32~\F32] \to []` :ref:`validation ` :ref:`execution ` -:math:`\F64.\STORE~\memarg` :math:`\hex{39}` :math:`[\I32~\F64] \to []` :ref:`validation ` :ref:`execution ` -:math:`\I32.\STORE\K{8}~\memarg` :math:`\hex{3A}` :math:`[\I32~\I32] \to []` :ref:`validation ` :ref:`execution ` -:math:`\I32.\STORE\K{16}~\memarg` :math:`\hex{3B}` :math:`[\I32~\I32] \to []` :ref:`validation ` :ref:`execution ` -:math:`\I64.\STORE\K{8}~\memarg` :math:`\hex{3C}` :math:`[\I32~\I64] \to []` :ref:`validation ` :ref:`execution ` -:math:`\I64.\STORE\K{16}~\memarg` :math:`\hex{3D}` :math:`[\I32~\I64] \to []` :ref:`validation ` :ref:`execution ` -:math:`\I64.\STORE\K{32}~\memarg` :math:`\hex{3E}` :math:`[\I32~\I64] \to []` :ref:`validation ` :ref:`execution ` -:math:`\MEMORYSIZE` :math:`\hex{3F}` :math:`[] \to [\I32]` :ref:`validation ` :ref:`execution ` -:math:`\MEMORYGROW` :math:`\hex{40}` :math:`[\I32] \to [\I32]` :ref:`validation ` :ref:`execution ` -:math:`\I32.\CONST~\i32` :math:`\hex{41}` :math:`[] \to [\I32]` :ref:`validation ` :ref:`execution ` -:math:`\I64.\CONST~\i64` :math:`\hex{42}` :math:`[] \to [\I64]` :ref:`validation ` :ref:`execution ` -:math:`\F32.\CONST~\f32` :math:`\hex{43}` :math:`[] \to [\F32]` :ref:`validation ` :ref:`execution ` -:math:`\F64.\CONST~\f64` :math:`\hex{44}` :math:`[] \to [\F64]` :ref:`validation ` :ref:`execution ` -:math:`\I32.\EQZ` :math:`\hex{45}` :math:`[\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I32.\EQ` :math:`\hex{46}` :math:`[\I32~\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I32.\NE` :math:`\hex{47}` :math:`[\I32~\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I32.\LT\K{\_s}` :math:`\hex{48}` :math:`[\I32~\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I32.\LT\K{\_u}` :math:`\hex{49}` :math:`[\I32~\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I32.\GT\K{\_s}` :math:`\hex{4A}` :math:`[\I32~\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I32.\GT\K{\_u}` :math:`\hex{4B}` :math:`[\I32~\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I32.\LE\K{\_s}` :math:`\hex{4C}` :math:`[\I32~\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I32.\LE\K{\_u}` :math:`\hex{4D}` :math:`[\I32~\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I32.\GE\K{\_s}` :math:`\hex{4E}` :math:`[\I32~\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I32.\GE\K{\_u}` :math:`\hex{4F}` :math:`[\I32~\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I64.\EQZ` :math:`\hex{50}` :math:`[\I64] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I64.\EQ` :math:`\hex{51}` :math:`[\I64~\I64] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I64.\NE` :math:`\hex{52}` :math:`[\I64~\I64] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I64.\LT\K{\_s}` :math:`\hex{53}` :math:`[\I64~\I64] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I64.\LT\K{\_u}` :math:`\hex{54}` :math:`[\I64~\I64] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I64.\GT\K{\_s}` :math:`\hex{55}` :math:`[\I64~\I64] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I64.\GT\K{\_u}` :math:`\hex{56}` :math:`[\I64~\I64] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I64.\LE\K{\_s}` :math:`\hex{57}` :math:`[\I64~\I64] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I64.\LE\K{\_u}` :math:`\hex{58}` :math:`[\I64~\I64] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I64.\GE\K{\_s}` :math:`\hex{59}` :math:`[\I64~\I64] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I64.\GE\K{\_u}` :math:`\hex{5A}` :math:`[\I64~\I64] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F32.\EQ` :math:`\hex{5B}` :math:`[\F32~\F32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F32.\NE` :math:`\hex{5C}` :math:`[\F32~\F32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F32.\LT` :math:`\hex{5D}` :math:`[\F32~\F32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F32.\GT` :math:`\hex{5E}` :math:`[\F32~\F32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F32.\LE` :math:`\hex{5F}` :math:`[\F32~\F32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F32.\GE` :math:`\hex{60}` :math:`[\F32~\F32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F64.\EQ` :math:`\hex{61}` :math:`[\F64~\F64] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F64.\NE` :math:`\hex{62}` :math:`[\F64~\F64] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F64.\LT` :math:`\hex{63}` :math:`[\F64~\F64] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F64.\GT` :math:`\hex{64}` :math:`[\F64~\F64] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F64.\LE` :math:`\hex{65}` :math:`[\F64~\F64] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F64.\GE` :math:`\hex{66}` :math:`[\F64~\F64] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I32.\CLZ` :math:`\hex{67}` :math:`[\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I32.\CTZ` :math:`\hex{68}` :math:`[\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I32.\POPCNT` :math:`\hex{69}` :math:`[\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I32.\ADD` :math:`\hex{6A}` :math:`[\I32~\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I32.\SUB` :math:`\hex{6B}` :math:`[\I32~\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I32.\MUL` :math:`\hex{6C}` :math:`[\I32~\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I32.\DIV\K{\_s}` :math:`\hex{6D}` :math:`[\I32~\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I32.\DIV\K{\_u}` :math:`\hex{6E}` :math:`[\I32~\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I32.\REM\K{\_s}` :math:`\hex{6F}` :math:`[\I32~\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I32.\REM\K{\_u}` :math:`\hex{70}` :math:`[\I32~\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I32.\AND` :math:`\hex{71}` :math:`[\I32~\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I32.\OR` :math:`\hex{72}` :math:`[\I32~\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I32.\XOR` :math:`\hex{73}` :math:`[\I32~\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I32.\SHL` :math:`\hex{74}` :math:`[\I32~\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I32.\SHR\K{\_s}` :math:`\hex{75}` :math:`[\I32~\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I32.\SHR\K{\_u}` :math:`\hex{76}` :math:`[\I32~\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I32.\ROTL` :math:`\hex{77}` :math:`[\I32~\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I32.\ROTR` :math:`\hex{78}` :math:`[\I32~\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I64.\CLZ` :math:`\hex{79}` :math:`[\I64] \to [\I64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I64.\CTZ` :math:`\hex{7A}` :math:`[\I64] \to [\I64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I64.\POPCNT` :math:`\hex{7B}` :math:`[\I64] \to [\I64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I64.\ADD` :math:`\hex{7C}` :math:`[\I64~\I64] \to [\I64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I64.\SUB` :math:`\hex{7D}` :math:`[\I64~\I64] \to [\I64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I64.\MUL` :math:`\hex{7E}` :math:`[\I64~\I64] \to [\I64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I64.\DIV\K{\_s}` :math:`\hex{7F}` :math:`[\I64~\I64] \to [\I64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I64.\DIV\K{\_u}` :math:`\hex{80}` :math:`[\I64~\I64] \to [\I64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I64.\REM\K{\_s}` :math:`\hex{81}` :math:`[\I64~\I64] \to [\I64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I64.\REM\K{\_u}` :math:`\hex{82}` :math:`[\I64~\I64] \to [\I64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I64.\AND` :math:`\hex{83}` :math:`[\I64~\I64] \to [\I64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I64.\OR` :math:`\hex{84}` :math:`[\I64~\I64] \to [\I64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I64.\XOR` :math:`\hex{85}` :math:`[\I64~\I64] \to [\I64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I64.\SHL` :math:`\hex{86}` :math:`[\I64~\I64] \to [\I64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I64.\SHR\K{\_s}` :math:`\hex{87}` :math:`[\I64~\I64] \to [\I64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I64.\SHR\K{\_u}` :math:`\hex{88}` :math:`[\I64~\I64] \to [\I64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I64.\ROTL` :math:`\hex{89}` :math:`[\I64~\I64] \to [\I64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I64.\ROTR` :math:`\hex{8A}` :math:`[\I64~\I64] \to [\I64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F32.\ABS` :math:`\hex{8B}` :math:`[\F32] \to [\F32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F32.\NEG` :math:`\hex{8C}` :math:`[\F32] \to [\F32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F32.\CEIL` :math:`\hex{8D}` :math:`[\F32] \to [\F32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F32.\FLOOR` :math:`\hex{8E}` :math:`[\F32] \to [\F32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F32.\TRUNC` :math:`\hex{8F}` :math:`[\F32] \to [\F32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F32.\NEAREST` :math:`\hex{90}` :math:`[\F32] \to [\F32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F32.\SQRT` :math:`\hex{91}` :math:`[\F32] \to [\F32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F32.\ADD` :math:`\hex{92}` :math:`[\F32~\F32] \to [\F32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F32.\SUB` :math:`\hex{93}` :math:`[\F32~\F32] \to [\F32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F32.\MUL` :math:`\hex{94}` :math:`[\F32~\F32] \to [\F32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F32.\DIV` :math:`\hex{95}` :math:`[\F32~\F32] \to [\F32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F32.\FMIN` :math:`\hex{96}` :math:`[\F32~\F32] \to [\F32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F32.\FMAX` :math:`\hex{97}` :math:`[\F32~\F32] \to [\F32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F32.\COPYSIGN` :math:`\hex{98}` :math:`[\F32~\F32] \to [\F32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F64.\ABS` :math:`\hex{99}` :math:`[\F64] \to [\F64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F64.\NEG` :math:`\hex{9A}` :math:`[\F64] \to [\F64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F64.\CEIL` :math:`\hex{9B}` :math:`[\F64] \to [\F64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F64.\FLOOR` :math:`\hex{9C}` :math:`[\F64] \to [\F64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F64.\TRUNC` :math:`\hex{9D}` :math:`[\F64] \to [\F64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F64.\NEAREST` :math:`\hex{9E}` :math:`[\F64] \to [\F64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F64.\SQRT` :math:`\hex{9F}` :math:`[\F64] \to [\F64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F64.\ADD` :math:`\hex{A0}` :math:`[\F64~\F64] \to [\F64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F64.\SUB` :math:`\hex{A1}` :math:`[\F64~\F64] \to [\F64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F64.\MUL` :math:`\hex{A2}` :math:`[\F64~\F64] \to [\F64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F64.\DIV` :math:`\hex{A3}` :math:`[\F64~\F64] \to [\F64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F64.\FMIN` :math:`\hex{A4}` :math:`[\F64~\F64] \to [\F64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F64.\FMAX` :math:`\hex{A5}` :math:`[\F64~\F64] \to [\F64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F64.\COPYSIGN` :math:`\hex{A6}` :math:`[\F64~\F64] \to [\F64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I32.\WRAP\K{\_}\I64` :math:`\hex{A7}` :math:`[\I64] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I32.\TRUNC\K{\_}\F32\K{\_s}` :math:`\hex{A8}` :math:`[\F32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I32.\TRUNC\K{\_}\F32\K{\_u}` :math:`\hex{A9}` :math:`[\F32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I32.\TRUNC\K{\_}\F64\K{\_s}` :math:`\hex{AA}` :math:`[\F64] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I32.\TRUNC\K{\_}\F64\K{\_u}` :math:`\hex{AB}` :math:`[\F64] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I64.\EXTEND\K{\_}\I32\K{\_s}` :math:`\hex{AC}` :math:`[\I32] \to [\I64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I64.\EXTEND\K{\_}\I32\K{\_u}` :math:`\hex{AD}` :math:`[\I32] \to [\I64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I64.\TRUNC\K{\_}\F32\K{\_s}` :math:`\hex{AE}` :math:`[\F32] \to [\I64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I64.\TRUNC\K{\_}\F32\K{\_u}` :math:`\hex{AF}` :math:`[\F32] \to [\I64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I64.\TRUNC\K{\_}\F64\K{\_s}` :math:`\hex{B0}` :math:`[\F64] \to [\I64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I64.\TRUNC\K{\_}\F64\K{\_u}` :math:`\hex{B1}` :math:`[\F64] \to [\I64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F32.\CONVERT\K{\_}\I32\K{\_s}` :math:`\hex{B2}` :math:`[\I32] \to [\F32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F32.\CONVERT\K{\_}\I32\K{\_u}` :math:`\hex{B3}` :math:`[\I32] \to [\F32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F32.\CONVERT\K{\_}\I64\K{\_s}` :math:`\hex{B4}` :math:`[\I64] \to [\F32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F32.\CONVERT\K{\_}\I64\K{\_u}` :math:`\hex{B5}` :math:`[\I64] \to [\F32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F32.\DEMOTE\K{\_}\F64` :math:`\hex{B6}` :math:`[\F64] \to [\F32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F64.\CONVERT\K{\_}\I32\K{\_s}` :math:`\hex{B7}` :math:`[\I32] \to [\F64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F64.\CONVERT\K{\_}\I32\K{\_u}` :math:`\hex{B8}` :math:`[\I32] \to [\F64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F64.\CONVERT\K{\_}\I64\K{\_s}` :math:`\hex{B9}` :math:`[\I64] \to [\F64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F64.\CONVERT\K{\_}\I64\K{\_u}` :math:`\hex{BA}` :math:`[\I64] \to [\F64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F64.\PROMOTE\K{\_}\F32` :math:`\hex{BB}` :math:`[\F32] \to [\F64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I32.\REINTERPRET\K{\_}\F32` :math:`\hex{BC}` :math:`[\F32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I64.\REINTERPRET\K{\_}\F64` :math:`\hex{BD}` :math:`[\F64] \to [\I64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F32.\REINTERPRET\K{\_}\I32` :math:`\hex{BE}` :math:`[\I32] \to [\F32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F64.\REINTERPRET\K{\_}\I64` :math:`\hex{BF}` :math:`[\I64] \to [\F64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I32.\EXTEND\K{8\_s}` :math:`\hex{C0}` :math:`[\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I32.\EXTEND\K{16\_s}` :math:`\hex{C1}` :math:`[\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I64.\EXTEND\K{8\_s}` :math:`\hex{C2}` :math:`[\I64] \to [\I64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I64.\EXTEND\K{16\_s}` :math:`\hex{C3}` :math:`[\I64] \to [\I64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I64.\EXTEND\K{32\_s}` :math:`\hex{C4}` :math:`[\I64] \to [\I64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I32.\TRUNC\K{\_sat\_}\F32\K{\_s}` :math:`\hex{FC}~~0` :math:`[\F32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I32.\TRUNC\K{\_sat\_}\F32\K{\_u}` :math:`\hex{FC}~~1` :math:`[\F32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I32.\TRUNC\K{\_sat\_}\F64\K{\_s}` :math:`\hex{FC}~~2` :math:`[\F64] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I32.\TRUNC\K{\_sat\_}\F64\K{\_u}` :math:`\hex{FC}~~3` :math:`[\F64] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I64.\TRUNC\K{\_sat\_}\F32\K{\_s}` :math:`\hex{FC}~~4` :math:`[\F32] \to [\I64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I64.\TRUNC\K{\_sat\_}\F32\K{\_u}` :math:`\hex{FC}~~5` :math:`[\F32] \to [\I64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I64.\TRUNC\K{\_sat}\_\F64\K{\_s}` :math:`\hex{FC}~~6` :math:`[\F64] \to [\I64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I64.\TRUNC\K{\_sat\_}\F64\K{\_u}` :math:`\hex{FC}~~7` :math:`[\F64] \to [\I64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\MEMORYINIT` :math:`\hex{FC}~\hex{08}` :math:`[\I32~\I32~\I32] \to []` :ref:`validation ` :ref:`execution ` -:math:`\DATADROP` :math:`\hex{FC}~\hex{09}` :math:`[] \to []` :ref:`validation ` :ref:`execution ` -:math:`\MEMORYCOPY` :math:`\hex{FC}~\hex{0A}` :math:`[\I32~\I32~\I32] \to []` :ref:`validation ` :ref:`execution ` -:math:`\MEMORYFILL` :math:`\hex{FC}~\hex{0B}` :math:`[\I32~\I32~\I32] \to []` :ref:`validation ` :ref:`execution ` -:math:`\TABLEINIT` :math:`\hex{FC}~\hex{0C}` :math:`[\I32~\I32~\I32] \to []` :ref:`validation ` :ref:`execution ` -:math:`\ELEMDROP` :math:`\hex{FC}~\hex{0D}` :math:`[] \to []` :ref:`validation ` :ref:`execution ` -:math:`\TABLECOPY` :math:`\hex{FC}~\hex{0E}` :math:`[\I32~\I32~\I32] \to []` :ref:`validation ` :ref:`execution ` -========================================= ========================= ============================================= ======================================= =============================================================== +========================================= ==================== ============================================= ======================================= =============================================================== +Instruction Binary Opcode Type Validation Execution +========================================= ==================== ============================================= ======================================= =============================================================== +:math:`\UNREACHABLE` :math:`\hex{00}` :math:`[t_1^\ast] \to [t_2^\ast]` :ref:`validation ` :ref:`execution ` +:math:`\NOP` :math:`\hex{01}` :math:`[] \to []` :ref:`validation ` :ref:`execution ` +:math:`\BLOCK~\X{bt}` :math:`\hex{02}` :math:`[t_1^\ast] \to [t_2^\ast]` :ref:`validation ` :ref:`execution ` +:math:`\LOOP~\X{bt}` :math:`\hex{03}` :math:`[t_1^\ast] \to [t_2^\ast]` :ref:`validation ` :ref:`execution ` +:math:`\IF~\X{bt}` :math:`\hex{04}` :math:`[t_1^\ast] \to [t_2^\ast]` :ref:`validation ` :ref:`execution ` +:math:`\ELSE` :math:`\hex{05}` +(reserved) :math:`\hex{06}` +(reserved) :math:`\hex{07}` +(reserved) :math:`\hex{08}` +(reserved) :math:`\hex{09}` +(reserved) :math:`\hex{0A}` +:math:`\END` :math:`\hex{0B}` +:math:`\BR~l` :math:`\hex{0C}` :math:`[t_1^\ast~t^\ast] \to [t_2^\ast]` :ref:`validation ` :ref:`execution ` +:math:`\BRIF~l` :math:`\hex{0D}` :math:`[t^\ast~\I32] \to [t^\ast]` :ref:`validation ` :ref:`execution ` +:math:`\BRTABLE~l^\ast~l` :math:`\hex{0E}` :math:`[t_1^\ast~t^\ast~\I32] \to [t_2^\ast]` :ref:`validation ` :ref:`execution ` +:math:`\RETURN` :math:`\hex{0F}` :math:`[t_1^\ast~t^\ast] \to [t_2^\ast]` :ref:`validation ` :ref:`execution ` +:math:`\CALL~x` :math:`\hex{10}` :math:`[t_1^\ast] \to [t_2^\ast]` :ref:`validation ` :ref:`execution ` +:math:`\CALLINDIRECT~x` :math:`\hex{11}` :math:`[t_1^\ast~\I32] \to [t_2^\ast]` :ref:`validation ` :ref:`execution ` +(reserved) :math:`\hex{12}` +(reserved) :math:`\hex{13}` +(reserved) :math:`\hex{14}` +(reserved) :math:`\hex{15}` +(reserved) :math:`\hex{16}` +(reserved) :math:`\hex{17}` +(reserved) :math:`\hex{18}` +(reserved) :math:`\hex{19}` +:math:`\DROP` :math:`\hex{1A}` :math:`[t] \to []` :ref:`validation ` :ref:`execution ` +:math:`\SELECT` :math:`\hex{1B}` :math:`[t~t~\I32] \to [t]` :ref:`validation ` :ref:`execution ` +(reserved) :math:`\hex{1C}` +(reserved) :math:`\hex{1D}` +(reserved) :math:`\hex{1E}` +(reserved) :math:`\hex{1F}` +:math:`\LOCALGET~x` :math:`\hex{20}` :math:`[] \to [t]` :ref:`validation ` :ref:`execution ` +:math:`\LOCALSET~x` :math:`\hex{21}` :math:`[t] \to []` :ref:`validation ` :ref:`execution ` +:math:`\LOCALTEE~x` :math:`\hex{22}` :math:`[t] \to [t]` :ref:`validation ` :ref:`execution ` +:math:`\GLOBALGET~x` :math:`\hex{23}` :math:`[] \to [t]` :ref:`validation ` :ref:`execution ` +:math:`\GLOBALSET~x` :math:`\hex{24}` :math:`[t] \to []` :ref:`validation ` :ref:`execution ` +(reserved) :math:`\hex{25}` +(reserved) :math:`\hex{26}` +(reserved) :math:`\hex{27}` +:math:`\I32.\LOAD~\memarg` :math:`\hex{28}` :math:`[\I32] \to [\I32]` :ref:`validation ` :ref:`execution ` +:math:`\I64.\LOAD~\memarg` :math:`\hex{29}` :math:`[\I32] \to [\I64]` :ref:`validation ` :ref:`execution ` +:math:`\F32.\LOAD~\memarg` :math:`\hex{2A}` :math:`[\I32] \to [\F32]` :ref:`validation ` :ref:`execution ` +:math:`\F64.\LOAD~\memarg` :math:`\hex{2B}` :math:`[\I32] \to [\F64]` :ref:`validation ` :ref:`execution ` +:math:`\I32.\LOAD\K{8\_s}~\memarg` :math:`\hex{2C}` :math:`[\I32] \to [\I32]` :ref:`validation ` :ref:`execution ` +:math:`\I32.\LOAD\K{8\_u}~\memarg` :math:`\hex{2D}` :math:`[\I32] \to [\I32]` :ref:`validation ` :ref:`execution ` +:math:`\I32.\LOAD\K{16\_s}~\memarg` :math:`\hex{2E}` :math:`[\I32] \to [\I32]` :ref:`validation ` :ref:`execution ` +:math:`\I32.\LOAD\K{16\_u}~\memarg` :math:`\hex{2F}` :math:`[\I32] \to [\I32]` :ref:`validation ` :ref:`execution ` +:math:`\I64.\LOAD\K{8\_s}~\memarg` :math:`\hex{30}` :math:`[\I32] \to [\I64]` :ref:`validation ` :ref:`execution ` +:math:`\I64.\LOAD\K{8\_u}~\memarg` :math:`\hex{31}` :math:`[\I32] \to [\I64]` :ref:`validation ` :ref:`execution ` +:math:`\I64.\LOAD\K{16\_s}~\memarg` :math:`\hex{32}` :math:`[\I32] \to [\I64]` :ref:`validation ` :ref:`execution ` +:math:`\I64.\LOAD\K{16\_u}~\memarg` :math:`\hex{33}` :math:`[\I32] \to [\I64]` :ref:`validation ` :ref:`execution ` +:math:`\I64.\LOAD\K{32\_s}~\memarg` :math:`\hex{34}` :math:`[\I32] \to [\I64]` :ref:`validation ` :ref:`execution ` +:math:`\I64.\LOAD\K{32\_u}~\memarg` :math:`\hex{35}` :math:`[\I32] \to [\I64]` :ref:`validation ` :ref:`execution ` +:math:`\I32.\STORE~\memarg` :math:`\hex{36}` :math:`[\I32~\I32] \to []` :ref:`validation ` :ref:`execution ` +:math:`\I64.\STORE~\memarg` :math:`\hex{37}` :math:`[\I32~\I64] \to []` :ref:`validation ` :ref:`execution ` +:math:`\F32.\STORE~\memarg` :math:`\hex{38}` :math:`[\I32~\F32] \to []` :ref:`validation ` :ref:`execution ` +:math:`\F64.\STORE~\memarg` :math:`\hex{39}` :math:`[\I32~\F64] \to []` :ref:`validation ` :ref:`execution ` +:math:`\I32.\STORE\K{8}~\memarg` :math:`\hex{3A}` :math:`[\I32~\I32] \to []` :ref:`validation ` :ref:`execution ` +:math:`\I32.\STORE\K{16}~\memarg` :math:`\hex{3B}` :math:`[\I32~\I32] \to []` :ref:`validation ` :ref:`execution ` +:math:`\I64.\STORE\K{8}~\memarg` :math:`\hex{3C}` :math:`[\I32~\I64] \to []` :ref:`validation ` :ref:`execution ` +:math:`\I64.\STORE\K{16}~\memarg` :math:`\hex{3D}` :math:`[\I32~\I64] \to []` :ref:`validation ` :ref:`execution ` +:math:`\I64.\STORE\K{32}~\memarg` :math:`\hex{3E}` :math:`[\I32~\I64] \to []` :ref:`validation ` :ref:`execution ` +:math:`\MEMORYSIZE` :math:`\hex{3F}` :math:`[] \to [\I32]` :ref:`validation ` :ref:`execution ` +:math:`\MEMORYGROW` :math:`\hex{40}` :math:`[\I32] \to [\I32]` :ref:`validation ` :ref:`execution ` +:math:`\I32.\CONST~\i32` :math:`\hex{41}` :math:`[] \to [\I32]` :ref:`validation ` :ref:`execution ` +:math:`\I64.\CONST~\i64` :math:`\hex{42}` :math:`[] \to [\I64]` :ref:`validation ` :ref:`execution ` +:math:`\F32.\CONST~\f32` :math:`\hex{43}` :math:`[] \to [\F32]` :ref:`validation ` :ref:`execution ` +:math:`\F64.\CONST~\f64` :math:`\hex{44}` :math:`[] \to [\F64]` :ref:`validation ` :ref:`execution ` +:math:`\I32.\EQZ` :math:`\hex{45}` :math:`[\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I32.\EQ` :math:`\hex{46}` :math:`[\I32~\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I32.\NE` :math:`\hex{47}` :math:`[\I32~\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I32.\LT\K{\_s}` :math:`\hex{48}` :math:`[\I32~\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I32.\LT\K{\_u}` :math:`\hex{49}` :math:`[\I32~\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I32.\GT\K{\_s}` :math:`\hex{4A}` :math:`[\I32~\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I32.\GT\K{\_u}` :math:`\hex{4B}` :math:`[\I32~\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I32.\LE\K{\_s}` :math:`\hex{4C}` :math:`[\I32~\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I32.\LE\K{\_u}` :math:`\hex{4D}` :math:`[\I32~\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I32.\GE\K{\_s}` :math:`\hex{4E}` :math:`[\I32~\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I32.\GE\K{\_u}` :math:`\hex{4F}` :math:`[\I32~\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I64.\EQZ` :math:`\hex{50}` :math:`[\I64] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I64.\EQ` :math:`\hex{51}` :math:`[\I64~\I64] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I64.\NE` :math:`\hex{52}` :math:`[\I64~\I64] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I64.\LT\K{\_s}` :math:`\hex{53}` :math:`[\I64~\I64] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I64.\LT\K{\_u}` :math:`\hex{54}` :math:`[\I64~\I64] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I64.\GT\K{\_s}` :math:`\hex{55}` :math:`[\I64~\I64] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I64.\GT\K{\_u}` :math:`\hex{56}` :math:`[\I64~\I64] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I64.\LE\K{\_s}` :math:`\hex{57}` :math:`[\I64~\I64] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I64.\LE\K{\_u}` :math:`\hex{58}` :math:`[\I64~\I64] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I64.\GE\K{\_s}` :math:`\hex{59}` :math:`[\I64~\I64] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I64.\GE\K{\_u}` :math:`\hex{5A}` :math:`[\I64~\I64] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\F32.\EQ` :math:`\hex{5B}` :math:`[\F32~\F32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\F32.\NE` :math:`\hex{5C}` :math:`[\F32~\F32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\F32.\LT` :math:`\hex{5D}` :math:`[\F32~\F32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\F32.\GT` :math:`\hex{5E}` :math:`[\F32~\F32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\F32.\LE` :math:`\hex{5F}` :math:`[\F32~\F32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\F32.\GE` :math:`\hex{60}` :math:`[\F32~\F32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\F64.\EQ` :math:`\hex{61}` :math:`[\F64~\F64] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\F64.\NE` :math:`\hex{62}` :math:`[\F64~\F64] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\F64.\LT` :math:`\hex{63}` :math:`[\F64~\F64] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\F64.\GT` :math:`\hex{64}` :math:`[\F64~\F64] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\F64.\LE` :math:`\hex{65}` :math:`[\F64~\F64] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\F64.\GE` :math:`\hex{66}` :math:`[\F64~\F64] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I32.\CLZ` :math:`\hex{67}` :math:`[\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I32.\CTZ` :math:`\hex{68}` :math:`[\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I32.\POPCNT` :math:`\hex{69}` :math:`[\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I32.\ADD` :math:`\hex{6A}` :math:`[\I32~\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I32.\SUB` :math:`\hex{6B}` :math:`[\I32~\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I32.\MUL` :math:`\hex{6C}` :math:`[\I32~\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I32.\DIV\K{\_s}` :math:`\hex{6D}` :math:`[\I32~\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I32.\DIV\K{\_u}` :math:`\hex{6E}` :math:`[\I32~\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I32.\REM\K{\_s}` :math:`\hex{6F}` :math:`[\I32~\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I32.\REM\K{\_u}` :math:`\hex{70}` :math:`[\I32~\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I32.\AND` :math:`\hex{71}` :math:`[\I32~\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I32.\OR` :math:`\hex{72}` :math:`[\I32~\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I32.\XOR` :math:`\hex{73}` :math:`[\I32~\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I32.\SHL` :math:`\hex{74}` :math:`[\I32~\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I32.\SHR\K{\_s}` :math:`\hex{75}` :math:`[\I32~\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I32.\SHR\K{\_u}` :math:`\hex{76}` :math:`[\I32~\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I32.\ROTL` :math:`\hex{77}` :math:`[\I32~\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I32.\ROTR` :math:`\hex{78}` :math:`[\I32~\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I64.\CLZ` :math:`\hex{79}` :math:`[\I64] \to [\I64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I64.\CTZ` :math:`\hex{7A}` :math:`[\I64] \to [\I64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I64.\POPCNT` :math:`\hex{7B}` :math:`[\I64] \to [\I64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I64.\ADD` :math:`\hex{7C}` :math:`[\I64~\I64] \to [\I64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I64.\SUB` :math:`\hex{7D}` :math:`[\I64~\I64] \to [\I64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I64.\MUL` :math:`\hex{7E}` :math:`[\I64~\I64] \to [\I64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I64.\DIV\K{\_s}` :math:`\hex{7F}` :math:`[\I64~\I64] \to [\I64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I64.\DIV\K{\_u}` :math:`\hex{80}` :math:`[\I64~\I64] \to [\I64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I64.\REM\K{\_s}` :math:`\hex{81}` :math:`[\I64~\I64] \to [\I64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I64.\REM\K{\_u}` :math:`\hex{82}` :math:`[\I64~\I64] \to [\I64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I64.\AND` :math:`\hex{83}` :math:`[\I64~\I64] \to [\I64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I64.\OR` :math:`\hex{84}` :math:`[\I64~\I64] \to [\I64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I64.\XOR` :math:`\hex{85}` :math:`[\I64~\I64] \to [\I64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I64.\SHL` :math:`\hex{86}` :math:`[\I64~\I64] \to [\I64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I64.\SHR\K{\_s}` :math:`\hex{87}` :math:`[\I64~\I64] \to [\I64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I64.\SHR\K{\_u}` :math:`\hex{88}` :math:`[\I64~\I64] \to [\I64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I64.\ROTL` :math:`\hex{89}` :math:`[\I64~\I64] \to [\I64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I64.\ROTR` :math:`\hex{8A}` :math:`[\I64~\I64] \to [\I64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\F32.\ABS` :math:`\hex{8B}` :math:`[\F32] \to [\F32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\F32.\NEG` :math:`\hex{8C}` :math:`[\F32] \to [\F32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\F32.\CEIL` :math:`\hex{8D}` :math:`[\F32] \to [\F32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\F32.\FLOOR` :math:`\hex{8E}` :math:`[\F32] \to [\F32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\F32.\TRUNC` :math:`\hex{8F}` :math:`[\F32] \to [\F32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\F32.\NEAREST` :math:`\hex{90}` :math:`[\F32] \to [\F32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\F32.\SQRT` :math:`\hex{91}` :math:`[\F32] \to [\F32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\F32.\ADD` :math:`\hex{92}` :math:`[\F32~\F32] \to [\F32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\F32.\SUB` :math:`\hex{93}` :math:`[\F32~\F32] \to [\F32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\F32.\MUL` :math:`\hex{94}` :math:`[\F32~\F32] \to [\F32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\F32.\DIV` :math:`\hex{95}` :math:`[\F32~\F32] \to [\F32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\F32.\FMIN` :math:`\hex{96}` :math:`[\F32~\F32] \to [\F32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\F32.\FMAX` :math:`\hex{97}` :math:`[\F32~\F32] \to [\F32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\F32.\COPYSIGN` :math:`\hex{98}` :math:`[\F32~\F32] \to [\F32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\F64.\ABS` :math:`\hex{99}` :math:`[\F64] \to [\F64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\F64.\NEG` :math:`\hex{9A}` :math:`[\F64] \to [\F64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\F64.\CEIL` :math:`\hex{9B}` :math:`[\F64] \to [\F64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\F64.\FLOOR` :math:`\hex{9C}` :math:`[\F64] \to [\F64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\F64.\TRUNC` :math:`\hex{9D}` :math:`[\F64] \to [\F64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\F64.\NEAREST` :math:`\hex{9E}` :math:`[\F64] \to [\F64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\F64.\SQRT` :math:`\hex{9F}` :math:`[\F64] \to [\F64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\F64.\ADD` :math:`\hex{A0}` :math:`[\F64~\F64] \to [\F64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\F64.\SUB` :math:`\hex{A1}` :math:`[\F64~\F64] \to [\F64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\F64.\MUL` :math:`\hex{A2}` :math:`[\F64~\F64] \to [\F64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\F64.\DIV` :math:`\hex{A3}` :math:`[\F64~\F64] \to [\F64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\F64.\FMIN` :math:`\hex{A4}` :math:`[\F64~\F64] \to [\F64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\F64.\FMAX` :math:`\hex{A5}` :math:`[\F64~\F64] \to [\F64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\F64.\COPYSIGN` :math:`\hex{A6}` :math:`[\F64~\F64] \to [\F64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I32.\WRAP\K{\_}\I64` :math:`\hex{A7}` :math:`[\I64] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I32.\TRUNC\K{\_}\F32\K{\_s}` :math:`\hex{A8}` :math:`[\F32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I32.\TRUNC\K{\_}\F32\K{\_u}` :math:`\hex{A9}` :math:`[\F32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I32.\TRUNC\K{\_}\F64\K{\_s}` :math:`\hex{AA}` :math:`[\F64] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I32.\TRUNC\K{\_}\F64\K{\_u}` :math:`\hex{AB}` :math:`[\F64] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I64.\EXTEND\K{\_}\I32\K{\_s}` :math:`\hex{AC}` :math:`[\I32] \to [\I64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I64.\EXTEND\K{\_}\I32\K{\_u}` :math:`\hex{AD}` :math:`[\I32] \to [\I64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I64.\TRUNC\K{\_}\F32\K{\_s}` :math:`\hex{AE}` :math:`[\F32] \to [\I64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I64.\TRUNC\K{\_}\F32\K{\_u}` :math:`\hex{AF}` :math:`[\F32] \to [\I64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I64.\TRUNC\K{\_}\F64\K{\_s}` :math:`\hex{B0}` :math:`[\F64] \to [\I64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I64.\TRUNC\K{\_}\F64\K{\_u}` :math:`\hex{B1}` :math:`[\F64] \to [\I64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\F32.\CONVERT\K{\_}\I32\K{\_s}` :math:`\hex{B2}` :math:`[\I32] \to [\F32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\F32.\CONVERT\K{\_}\I32\K{\_u}` :math:`\hex{B3}` :math:`[\I32] \to [\F32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\F32.\CONVERT\K{\_}\I64\K{\_s}` :math:`\hex{B4}` :math:`[\I64] \to [\F32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\F32.\CONVERT\K{\_}\I64\K{\_u}` :math:`\hex{B5}` :math:`[\I64] \to [\F32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\F32.\DEMOTE\K{\_}\F64` :math:`\hex{B6}` :math:`[\F64] \to [\F32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\F64.\CONVERT\K{\_}\I32\K{\_s}` :math:`\hex{B7}` :math:`[\I32] \to [\F64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\F64.\CONVERT\K{\_}\I32\K{\_u}` :math:`\hex{B8}` :math:`[\I32] \to [\F64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\F64.\CONVERT\K{\_}\I64\K{\_s}` :math:`\hex{B9}` :math:`[\I64] \to [\F64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\F64.\CONVERT\K{\_}\I64\K{\_u}` :math:`\hex{BA}` :math:`[\I64] \to [\F64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\F64.\PROMOTE\K{\_}\F32` :math:`\hex{BB}` :math:`[\F32] \to [\F64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I32.\REINTERPRET\K{\_}\F32` :math:`\hex{BC}` :math:`[\F32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I64.\REINTERPRET\K{\_}\F64` :math:`\hex{BD}` :math:`[\F64] \to [\I64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\F32.\REINTERPRET\K{\_}\I32` :math:`\hex{BE}` :math:`[\I32] \to [\F32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\F64.\REINTERPRET\K{\_}\I64` :math:`\hex{BF}` :math:`[\I64] \to [\F64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I32.\EXTEND\K{8\_s}` :math:`\hex{C0}` :math:`[\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I32.\EXTEND\K{16\_s}` :math:`\hex{C1}` :math:`[\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I64.\EXTEND\K{8\_s}` :math:`\hex{C2}` :math:`[\I64] \to [\I64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I64.\EXTEND\K{16\_s}` :math:`\hex{C3}` :math:`[\I64] \to [\I64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I64.\EXTEND\K{32\_s}` :math:`\hex{C4}` :math:`[\I64] \to [\I64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I32.\TRUNC\K{\_sat\_}\F32\K{\_s}` :math:`\hex{FC}~~0` :math:`[\F32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I32.\TRUNC\K{\_sat\_}\F32\K{\_u}` :math:`\hex{FC}~~1` :math:`[\F32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I32.\TRUNC\K{\_sat\_}\F64\K{\_s}` :math:`\hex{FC}~~2` :math:`[\F64] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I32.\TRUNC\K{\_sat\_}\F64\K{\_u}` :math:`\hex{FC}~~3` :math:`[\F64] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I64.\TRUNC\K{\_sat\_}\F32\K{\_s}` :math:`\hex{FC}~~4` :math:`[\F32] \to [\I64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I64.\TRUNC\K{\_sat\_}\F32\K{\_u}` :math:`\hex{FC}~~5` :math:`[\F32] \to [\I64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I64.\TRUNC\K{\_sat}\_\F64\K{\_s}` :math:`\hex{FC}~~6` :math:`[\F64] \to [\I64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I64.\TRUNC\K{\_sat\_}\F64\K{\_u}` :math:`\hex{FC}~~7` :math:`[\F64] \to [\I64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\MEMORYINIT` :math:`\hex{FC}~~8` :math:`[\I32~\I32~\I32] \to []` :ref:`validation ` :ref:`execution ` +:math:`\DATADROP` :math:`\hex{FC}~~9` :math:`[] \to []` :ref:`validation ` :ref:`execution ` +:math:`\MEMORYCOPY` :math:`\hex{FC}~~10` :math:`[\I32~\I32~\I32] \to []` :ref:`validation ` :ref:`execution ` +:math:`\MEMORYFILL` :math:`\hex{FC}~~11` :math:`[\I32~\I32~\I32] \to []` :ref:`validation ` :ref:`execution ` +:math:`\TABLEINIT` :math:`\hex{FC}~~12` :math:`[\I32~\I32~\I32] \to []` :ref:`validation ` :ref:`execution ` +:math:`\ELEMDROP` :math:`\hex{FC}~~13` :math:`[] \to []` :ref:`validation ` :ref:`execution ` +:math:`\TABLECOPY` :math:`\hex{FC}~~14` :math:`[\I32~\I32~\I32] \to []` :ref:`validation ` :ref:`execution ` +========================================= ==================== ============================================= ======================================= =============================================================== diff --git a/document/core/binary/instructions.rst b/document/core/binary/instructions.rst index 5947f1aab5..97bedbd1d3 100644 --- a/document/core/binary/instructions.rst +++ b/document/core/binary/instructions.rst @@ -133,9 +133,9 @@ Each variant of :ref:`table instruction ` is encoded with a .. math:: \begin{array}{llclll} \production{instruction} & \Binstr &::=& \dots \\ &&|& - \hex{FC}~\hex{0C}~~x{:}\Belemidx~\hex{00} &\Rightarrow& \TABLEINIT~x \\ &&|& - \hex{FC}~\hex{0D}~~x{:}\Belemidx &\Rightarrow& \ELEMDROP~x \\ &&|& - \hex{FC}~\hex{0E}~~\hex{00}~~\hex{00} &\Rightarrow& \TABLECOPY \\ + \hex{FC}~~12{:}\Bu32~~x{:}\Belemidx~\hex{00} &\Rightarrow& \TABLEINIT~x \\ &&|& + \hex{FC}~~13{:}\Bu32~~x{:}\Belemidx &\Rightarrow& \ELEMDROP~x \\ &&|& + \hex{FC}~~14{:}\Bu32~~\hex{00}~~\hex{00} &\Rightarrow& \TABLECOPY \\ \end{array} .. note:: @@ -193,10 +193,10 @@ Each variant of :ref:`memory instruction ` is encoded with \hex{3E}~~m{:}\Bmemarg &\Rightarrow& \I64.\STORE\K{32}~m \\ &&|& \hex{3F}~~\hex{00} &\Rightarrow& \MEMORYSIZE \\ &&|& \hex{40}~~\hex{00} &\Rightarrow& \MEMORYGROW \\ &&|& - \hex{FC}~\hex{08}~~x{:}\Bdataidx~\hex{00} &\Rightarrow& \MEMORYINIT~x \\ &&|& - \hex{FC}~\hex{09}~~x{:}\Bdataidx &\Rightarrow& \DATADROP~x \\ &&|& - \hex{FC}~\hex{0A}~~\hex{00}~~\hex{00} &\Rightarrow& \MEMORYCOPY \\ &&|& - \hex{FC}~\hex{0B}~~\hex{00} &\Rightarrow& \MEMORYFILL \\ + \hex{FC}~~8{:}\Bu32~~x{:}\Bdataidx~\hex{00} &\Rightarrow& \MEMORYINIT~x \\ &&|& + \hex{FC}~~9{:}\Bu32~~x{:}\Bdataidx &\Rightarrow& \DATADROP~x \\ &&|& + \hex{FC}~~10{:}\Bu32~~\hex{00}~~\hex{00} &\Rightarrow& \MEMORYCOPY \\ &&|& + \hex{FC}~~11{:}\Bu32~~\hex{00} &\Rightarrow& \MEMORYFILL \\ \end{array} .. note:: From 7ae4890e50cd7be817073349a3f02c9cc6a2ca39 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bastian=20M=C3=BCller?= Date: Sat, 12 Sep 2020 10:43:43 -0700 Subject: [PATCH 182/199] fix decription of ref.func The incorrect description is a leftover from the original proposal, which specified a ref.eq instruction: https://github.com/WebAssembly/reference-types/commit/1f29a8ee7af86c45769fd130c67e09ad0f9b197f#diff-90422c6925e039f03d4bcf0359947b08R187-R190 --- document/core/syntax/instructions.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/document/core/syntax/instructions.rst b/document/core/syntax/instructions.rst index 85c641f01e..a967474288 100644 --- a/document/core/syntax/instructions.rst +++ b/document/core/syntax/instructions.rst @@ -191,7 +191,7 @@ Instructions in this group are concerned with accessing :ref:`references Date: Wed, 23 Sep 2020 13:38:44 +0800 Subject: [PATCH 183/199] [test] Uniform failure strings (#117) --- test/core/bulk.wast | 12 ++++----- test/core/data.wast | 28 ++++++++++----------- test/core/elem.wast | 28 ++++++++++----------- test/core/linking.wast | 48 ++++++++++++++++++------------------ test/core/memory_copy.wast | 36 +++++++++++++-------------- test/core/memory_fill.wast | 8 +++--- test/core/memory_init.wast | 28 ++++++++++----------- test/core/table_copy.wast | 50 +++++++++++++++++++------------------- test/core/table_fill.wast | 6 ++--- test/core/table_get.wast | 8 +++--- test/core/table_init.wast | 36 +++++++++++++-------------- test/core/table_set.wast | 16 ++++++------ 12 files changed, 152 insertions(+), 152 deletions(-) diff --git a/test/core/bulk.wast b/test/core/bulk.wast index 3bb794815c..5dcac724cf 100644 --- a/test/core/bulk.wast +++ b/test/core/bulk.wast @@ -169,11 +169,11 @@ (invoke "drop_passive") (invoke "drop_passive") (assert_return (invoke "init_passive" (i32.const 0))) -(assert_trap (invoke "init_passive" (i32.const 1)) "out of bounds") +(assert_trap (invoke "init_passive" (i32.const 1)) "out of bounds memory access") (invoke "init_passive" (i32.const 0)) (invoke "drop_active") (assert_return (invoke "init_active" (i32.const 0))) -(assert_trap (invoke "init_active" (i32.const 1)) "out of bounds") +(assert_trap (invoke "init_active" (i32.const 1)) "out of bounds memory access") (invoke "init_active" (i32.const 0)) ;; Test that the data segment index is properly encoded as an unsigned (not @@ -262,11 +262,11 @@ (invoke "drop_passive") (invoke "drop_passive") (assert_return (invoke "init_passive" (i32.const 0))) -(assert_trap (invoke "init_passive" (i32.const 1)) "out of bounds") +(assert_trap (invoke "init_passive" (i32.const 1)) "out of bounds table access") (invoke "init_passive" (i32.const 0)) (invoke "drop_active") (assert_return (invoke "init_active" (i32.const 0))) -(assert_trap (invoke "init_active" (i32.const 1)) "out of bounds") +(assert_trap (invoke "init_active" (i32.const 1)) "out of bounds table access") (invoke "init_active" (i32.const 0)) ;; Test that the elem segment index is properly encoded as an unsigned (not @@ -346,6 +346,6 @@ ;; Fail on out-of-bounds when copying 0 elements outside of table. (assert_trap (invoke "copy" (i32.const 11) (i32.const 0) (i32.const 0)) - "out of bounds") + "out of bounds table access") (assert_trap (invoke "copy" (i32.const 0) (i32.const 11) (i32.const 0)) - "out of bounds") + "out of bounds table access") diff --git a/test/core/data.wast b/test/core/data.wast index aabe1021b2..f4d9146319 100644 --- a/test/core/data.wast +++ b/test/core/data.wast @@ -175,7 +175,7 @@ (memory 0) (data (i32.const 0) "a") ) - "out of bounds" + "out of bounds memory access" ) (assert_trap @@ -183,7 +183,7 @@ (memory 0 0) (data (i32.const 0) "a") ) - "out of bounds" + "out of bounds memory access" ) (assert_trap @@ -191,21 +191,21 @@ (memory 0 1) (data (i32.const 0) "a") ) - "out of bounds" + "out of bounds memory access" ) (assert_trap (module (memory 0) (data (i32.const 1)) ) - "out of bounds" + "out of bounds memory access" ) (assert_trap (module (memory 0 1) (data (i32.const 1)) ) - "out of bounds" + "out of bounds memory access" ) ;; This seems to cause a time-out on Travis. @@ -223,7 +223,7 @@ (memory 0) (data (global.get 0) "a") ) - "out of bounds" + "out of bounds memory access" ) (assert_trap @@ -231,14 +231,14 @@ (memory 1 2) (data (i32.const 0x1_0000) "a") ) - "out of bounds" + "out of bounds memory access" ) (assert_trap (module (import "spectest" "memory" (memory 1)) (data (i32.const 0x1_0000) "a") ) - "out of bounds" + "out of bounds memory access" ) (assert_trap @@ -246,7 +246,7 @@ (memory 2) (data (i32.const 0x2_0000) "a") ) - "out of bounds" + "out of bounds memory access" ) (assert_trap @@ -254,7 +254,7 @@ (memory 2 3) (data (i32.const 0x2_0000) "a") ) - "out of bounds" + "out of bounds memory access" ) (assert_trap @@ -262,14 +262,14 @@ (memory 1) (data (i32.const -1) "a") ) - "out of bounds" + "out of bounds memory access" ) (assert_trap (module (import "spectest" "memory" (memory 1)) (data (i32.const -1) "a") ) - "out of bounds" + "out of bounds memory access" ) (assert_trap @@ -277,14 +277,14 @@ (memory 2) (data (i32.const -100) "a") ) - "out of bounds" + "out of bounds memory access" ) (assert_trap (module (import "spectest" "memory" (memory 1)) (data (i32.const -100) "a") ) - "out of bounds" + "out of bounds memory access" ) ;; Data without memory diff --git a/test/core/elem.wast b/test/core/elem.wast index d0537aa2b0..ddc5087905 100644 --- a/test/core/elem.wast +++ b/test/core/elem.wast @@ -211,7 +211,7 @@ (func $f) (elem (i32.const 0) $f) ) - "out of bounds" + "out of bounds table access" ) (assert_trap @@ -220,7 +220,7 @@ (func $f) (elem (i32.const 0) $f) ) - "out of bounds" + "out of bounds table access" ) (assert_trap @@ -229,7 +229,7 @@ (func $f) (elem (i32.const 0) $f) ) - "out of bounds" + "out of bounds table access" ) (assert_trap @@ -237,7 +237,7 @@ (table 0 funcref) (elem (i32.const 1)) ) - "out of bounds" + "out of bounds table access" ) (assert_trap (module @@ -245,7 +245,7 @@ (func $f) (elem (i32.const 10) $f) ) - "out of bounds" + "out of bounds table access" ) (assert_trap (module @@ -253,7 +253,7 @@ (func $f) (elem (i32.const 10) $f) ) - "out of bounds" + "out of bounds table access" ) (assert_trap @@ -262,7 +262,7 @@ (func $f) (elem (i32.const 10) $f) ) - "out of bounds" + "out of bounds table access" ) (assert_trap (module @@ -270,7 +270,7 @@ (func $f) (elem (i32.const 10) $f) ) - "out of bounds" + "out of bounds table access" ) (assert_trap @@ -279,7 +279,7 @@ (func $f) (elem (i32.const -1) $f) ) - "out of bounds" + "out of bounds table access" ) (assert_trap (module @@ -287,7 +287,7 @@ (func $f) (elem (i32.const -1) $f) ) - "out of bounds" + "out of bounds table access" ) (assert_trap @@ -296,7 +296,7 @@ (func $f) (elem (i32.const -10) $f) ) - "out of bounds" + "out of bounds table access" ) (assert_trap (module @@ -304,7 +304,7 @@ (func $f) (elem (i32.const -10) $f) ) - "out of bounds" + "out of bounds table access" ) ;; Implicitly dropped elements @@ -317,7 +317,7 @@ (table.init $e (i32.const 0) (i32.const 0) (i32.const 1)) ) ) -(assert_trap (invoke "init") "out of bounds") +(assert_trap (invoke "init") "out of bounds table access") (module (table 10 funcref) @@ -327,7 +327,7 @@ (table.init $e (i32.const 0) (i32.const 0) (i32.const 1)) ) ) -(assert_trap (invoke "init") "out of bounds") +(assert_trap (invoke "init") "out of bounds table access") ;; Element without table diff --git a/test/core/linking.wast b/test/core/linking.wast index e5b22dde80..994e0f49d0 100644 --- a/test/core/linking.wast +++ b/test/core/linking.wast @@ -170,23 +170,23 @@ (assert_return (invoke $Nt "call" (i32.const 2)) (i32.const 5)) (assert_return (invoke $Nt "call Mt.call" (i32.const 2)) (i32.const 4)) -(assert_trap (invoke $Mt "call" (i32.const 1)) "uninitialized") -(assert_trap (invoke $Nt "Mt.call" (i32.const 1)) "uninitialized") +(assert_trap (invoke $Mt "call" (i32.const 1)) "uninitialized element") +(assert_trap (invoke $Nt "Mt.call" (i32.const 1)) "uninitialized element") (assert_return (invoke $Nt "call" (i32.const 1)) (i32.const 5)) -(assert_trap (invoke $Nt "call Mt.call" (i32.const 1)) "uninitialized") +(assert_trap (invoke $Nt "call Mt.call" (i32.const 1)) "uninitialized element") -(assert_trap (invoke $Mt "call" (i32.const 0)) "uninitialized") -(assert_trap (invoke $Nt "Mt.call" (i32.const 0)) "uninitialized") +(assert_trap (invoke $Mt "call" (i32.const 0)) "uninitialized element") +(assert_trap (invoke $Nt "Mt.call" (i32.const 0)) "uninitialized element") (assert_return (invoke $Nt "call" (i32.const 0)) (i32.const 5)) -(assert_trap (invoke $Nt "call Mt.call" (i32.const 0)) "uninitialized") +(assert_trap (invoke $Nt "call Mt.call" (i32.const 0)) "uninitialized element") -(assert_trap (invoke $Mt "call" (i32.const 20)) "undefined") -(assert_trap (invoke $Nt "Mt.call" (i32.const 20)) "undefined") -(assert_trap (invoke $Nt "call" (i32.const 7)) "undefined") -(assert_trap (invoke $Nt "call Mt.call" (i32.const 20)) "undefined") +(assert_trap (invoke $Mt "call" (i32.const 20)) "undefined element") +(assert_trap (invoke $Nt "Mt.call" (i32.const 20)) "undefined element") +(assert_trap (invoke $Nt "call" (i32.const 7)) "undefined element") +(assert_trap (invoke $Nt "call Mt.call" (i32.const 20)) "undefined element") (assert_return (invoke $Nt "call" (i32.const 3)) (i32.const -4)) -(assert_trap (invoke $Nt "call" (i32.const 4)) "indirect call") +(assert_trap (invoke $Nt "call" (i32.const 4)) "indirect call type mismatch") (module $Ot (type (func (result i32))) @@ -218,13 +218,13 @@ (assert_return (invoke $Nt "call Mt.call" (i32.const 1)) (i32.const 6)) (assert_return (invoke $Ot "call" (i32.const 1)) (i32.const 6)) -(assert_trap (invoke $Mt "call" (i32.const 0)) "uninitialized") -(assert_trap (invoke $Nt "Mt.call" (i32.const 0)) "uninitialized") +(assert_trap (invoke $Mt "call" (i32.const 0)) "uninitialized element") +(assert_trap (invoke $Nt "Mt.call" (i32.const 0)) "uninitialized element") (assert_return (invoke $Nt "call" (i32.const 0)) (i32.const 5)) -(assert_trap (invoke $Nt "call Mt.call" (i32.const 0)) "uninitialized") -(assert_trap (invoke $Ot "call" (i32.const 0)) "uninitialized") +(assert_trap (invoke $Nt "call Mt.call" (i32.const 0)) "uninitialized element") +(assert_trap (invoke $Ot "call" (i32.const 0)) "uninitialized element") -(assert_trap (invoke $Ot "call" (i32.const 20)) "undefined") +(assert_trap (invoke $Ot "call" (i32.const 20)) "undefined element") (module (table (import "Mt" "tab") 0 funcref) @@ -246,7 +246,7 @@ (elem (i32.const 10) $f) (func $f) ) - "out of bounds" + "out of bounds table access" ) (assert_unlinkable @@ -259,7 +259,7 @@ ) "unknown import" ) -(assert_trap (invoke $Mt "call" (i32.const 7)) "uninitialized") +(assert_trap (invoke $Mt "call" (i32.const 7)) "uninitialized element") ;; Unlike in the v1 spec, active element segments stored before an ;; out-of-bounds access persist after the instantiation failure. @@ -270,10 +270,10 @@ (elem (i32.const 7) $f) (elem (i32.const 8) $f $f $f $f $f) ;; (partially) out of bounds ) - "out of bounds" + "out of bounds table access" ) (assert_return (invoke $Mt "call" (i32.const 7)) (i32.const 0)) -(assert_trap (invoke $Mt "call" (i32.const 8)) "uninitialized") +(assert_trap (invoke $Mt "call" (i32.const 8)) "uninitialized element") (assert_trap (module @@ -283,7 +283,7 @@ (memory 1) (data (i32.const 0x10000) "d") ;; out of bounds ) - "out of bounds" + "out of bounds memory access" ) (assert_return (invoke $Mt "call" (i32.const 7)) (i32.const 0)) @@ -361,7 +361,7 @@ (memory (import "Mm" "mem") 0) (data (i32.const 0x10000) "a") ) - "out of bounds" + "out of bounds memory access" ) (module $Pm @@ -401,7 +401,7 @@ (data (i32.const 0) "abc") (data (i32.const 327670) "zzzzzzzzzzzzzzzzzz") ;; (partially) out of bounds ) - "out of bounds" + "out of bounds memory access" ) (assert_return (invoke $Mm "load" (i32.const 0)) (i32.const 97)) (assert_return (invoke $Mm "load" (i32.const 327670)) (i32.const 0)) @@ -414,7 +414,7 @@ (func) (elem (i32.const 0) 0) ;; out of bounds ) - "out of bounds" + "out of bounds table access" ) (assert_return (invoke $Mm "load" (i32.const 0)) (i32.const 97)) diff --git a/test/core/memory_copy.wast b/test/core/memory_copy.wast index 58973d94a5..472995d79d 100644 --- a/test/core/memory_copy.wast +++ b/test/core/memory_copy.wast @@ -348,7 +348,7 @@ (i32.load8_u (local.get 0)))) (assert_trap (invoke "run" (i32.const 65516) (i32.const 0) (i32.const 40)) - "out of bounds") + "out of bounds memory access") (assert_return (invoke "load8_u" (i32.const 0)) (i32.const 0)) (assert_return (invoke "load8_u" (i32.const 1)) (i32.const 1)) @@ -709,7 +709,7 @@ (i32.load8_u (local.get 0)))) (assert_trap (invoke "run" (i32.const 65515) (i32.const 0) (i32.const 39)) - "out of bounds") + "out of bounds memory access") (assert_return (invoke "load8_u" (i32.const 0)) (i32.const 0)) (assert_return (invoke "load8_u" (i32.const 1)) (i32.const 1)) @@ -1071,7 +1071,7 @@ (i32.load8_u (local.get 0)))) (assert_trap (invoke "run" (i32.const 0) (i32.const 65516) (i32.const 40)) - "out of bounds") + "out of bounds memory access") (assert_return (invoke "load8_u" (i32.const 198)) (i32.const 0)) (assert_return (invoke "load8_u" (i32.const 397)) (i32.const 0)) @@ -1432,7 +1432,7 @@ (i32.load8_u (local.get 0)))) (assert_trap (invoke "run" (i32.const 0) (i32.const 65515) (i32.const 39)) - "out of bounds") + "out of bounds memory access") (assert_return (invoke "load8_u" (i32.const 198)) (i32.const 0)) (assert_return (invoke "load8_u" (i32.const 397)) (i32.const 0)) @@ -1794,7 +1794,7 @@ (i32.load8_u (local.get 0)))) (assert_trap (invoke "run" (i32.const 65516) (i32.const 65486) (i32.const 40)) - "out of bounds") + "out of bounds memory access") (assert_return (invoke "load8_u" (i32.const 198)) (i32.const 0)) (assert_return (invoke "load8_u" (i32.const 397)) (i32.const 0)) @@ -2155,7 +2155,7 @@ (i32.load8_u (local.get 0)))) (assert_trap (invoke "run" (i32.const 65486) (i32.const 65516) (i32.const 40)) - "out of bounds") + "out of bounds memory access") (assert_return (invoke "load8_u" (i32.const 198)) (i32.const 0)) (assert_return (invoke "load8_u" (i32.const 397)) (i32.const 0)) @@ -2516,7 +2516,7 @@ (i32.load8_u (local.get 0)))) (assert_trap (invoke "run" (i32.const 65516) (i32.const 65506) (i32.const 40)) - "out of bounds") + "out of bounds memory access") (assert_return (invoke "load8_u" (i32.const 198)) (i32.const 0)) (assert_return (invoke "load8_u" (i32.const 397)) (i32.const 0)) @@ -2877,7 +2877,7 @@ (i32.load8_u (local.get 0)))) (assert_trap (invoke "run" (i32.const 65506) (i32.const 65516) (i32.const 40)) - "out of bounds") + "out of bounds memory access") (assert_return (invoke "load8_u" (i32.const 198)) (i32.const 0)) (assert_return (invoke "load8_u" (i32.const 397)) (i32.const 0)) @@ -3238,7 +3238,7 @@ (i32.load8_u (local.get 0)))) (assert_trap (invoke "run" (i32.const 65516) (i32.const 65516) (i32.const 40)) - "out of bounds") + "out of bounds memory access") (assert_return (invoke "load8_u" (i32.const 198)) (i32.const 0)) (assert_return (invoke "load8_u" (i32.const 397)) (i32.const 0)) @@ -3599,7 +3599,7 @@ (i32.load8_u (local.get 0)))) (assert_trap (invoke "run" (i32.const 0) (i32.const 65516) (i32.const 4294963200)) - "out of bounds") + "out of bounds memory access") (assert_return (invoke "load8_u" (i32.const 198)) (i32.const 0)) (assert_return (invoke "load8_u" (i32.const 397)) (i32.const 0)) @@ -3960,7 +3960,7 @@ (i32.load8_u (local.get 0)))) (assert_trap (invoke "run" (i32.const 65516) (i32.const 61440) (i32.const 4294967040)) - "out of bounds") + "out of bounds memory access") (assert_return (invoke "load8_u" (i32.const 198)) (i32.const 0)) (assert_return (invoke "load8_u" (i32.const 397)) (i32.const 0)) @@ -4816,25 +4816,25 @@ (memory 1 1) (func (export "test") (memory.copy (i32.const 0xFF00) (i32.const 0x8000) (i32.const 257)))) -(assert_trap (invoke "test") "out of bounds") +(assert_trap (invoke "test") "out of bounds memory access") (module (memory 1 1) (func (export "test") (memory.copy (i32.const 0xFFFFFF00) (i32.const 0x4000) (i32.const 257)))) -(assert_trap (invoke "test") "out of bounds") +(assert_trap (invoke "test") "out of bounds memory access") (module (memory 1 1) (func (export "test") (memory.copy (i32.const 0x8000) (i32.const 0xFF00) (i32.const 257)))) -(assert_trap (invoke "test") "out of bounds") +(assert_trap (invoke "test") "out of bounds memory access") (module (memory 1 1) (func (export "test") (memory.copy (i32.const 0x4000) (i32.const 0xFFFFFF00) (i32.const 257)))) -(assert_trap (invoke "test") "out of bounds") +(assert_trap (invoke "test") "out of bounds memory access") (module (memory 1 1) @@ -4870,7 +4870,7 @@ (memory 1 1) (func (export "test") (memory.copy (i32.const 0x20000) (i32.const 0x7000) (i32.const 0)))) -(assert_trap (invoke "test") "out of bounds") +(assert_trap (invoke "test") "out of bounds memory access") (module (memory 1 1) @@ -4882,7 +4882,7 @@ (memory 1 1) (func (export "test") (memory.copy (i32.const 0x9000) (i32.const 0x20000) (i32.const 0)))) -(assert_trap (invoke "test") "out of bounds") +(assert_trap (invoke "test") "out of bounds memory access") (module (memory 1 1) @@ -4894,7 +4894,7 @@ (memory 1 1) (func (export "test") (memory.copy (i32.const 0x20000) (i32.const 0x20000) (i32.const 0)))) -(assert_trap (invoke "test") "out of bounds") +(assert_trap (invoke "test") "out of bounds memory access") (module (memory 1 1) diff --git a/test/core/memory_fill.wast b/test/core/memory_fill.wast index 99fd63ddde..98374a1586 100644 --- a/test/core/memory_fill.wast +++ b/test/core/memory_fill.wast @@ -115,7 +115,7 @@ (func (export "test") (memory.fill (i32.const 0x20000) (i32.const 0x55) (i32.const 0)))) -(assert_trap (invoke "test") "out of bounds") +(assert_trap (invoke "test") "out of bounds memory access") (module (memory 1 1) @@ -636,7 +636,7 @@ (memory.fill (local.get $offs) (local.get $val) (local.get $len)))) (assert_trap (invoke "run" (i32.const 65280) (i32.const 37) (i32.const 512)) - "out of bounds") + "out of bounds memory access") (assert_return (invoke "checkRange" (i32.const 0) (i32.const 1) (i32.const 0)) (i32.const -1)) @@ -658,7 +658,7 @@ (memory.fill (local.get $offs) (local.get $val) (local.get $len)))) (assert_trap (invoke "run" (i32.const 65279) (i32.const 37) (i32.const 514)) - "out of bounds") + "out of bounds memory access") (assert_return (invoke "checkRange" (i32.const 0) (i32.const 1) (i32.const 0)) (i32.const -1)) @@ -680,7 +680,7 @@ (memory.fill (local.get $offs) (local.get $val) (local.get $len)))) (assert_trap (invoke "run" (i32.const 65279) (i32.const 37) (i32.const 4294967295)) - "out of bounds") + "out of bounds memory access") (assert_return (invoke "checkRange" (i32.const 0) (i32.const 1) (i32.const 0)) (i32.const -1)) diff --git a/test/core/memory_init.wast b/test/core/memory_init.wast index 259b26aa11..672b1c5013 100644 --- a/test/core/memory_init.wast +++ b/test/core/memory_init.wast @@ -214,14 +214,14 @@ (func (export "test") (data.drop 0) (memory.init 0 (i32.const 1234) (i32.const 1) (i32.const 1)))) -(assert_trap (invoke "test") "out of bounds") +(assert_trap (invoke "test") "out of bounds memory access") (module (memory 1) (data (i32.const 0) "\37") (func (export "test") (memory.init 0 (i32.const 1234) (i32.const 1) (i32.const 1)))) -(assert_trap (invoke "test") "out of bounds") +(assert_trap (invoke "test") "out of bounds memory access") (assert_invalid (module @@ -250,28 +250,28 @@ (data "\37") (func (export "test") (memory.init 0 (i32.const 1234) (i32.const 0) (i32.const 5)))) -(assert_trap (invoke "test") "out of bounds") +(assert_trap (invoke "test") "out of bounds memory access") (module (memory 1) (data "\37") (func (export "test") (memory.init 0 (i32.const 1234) (i32.const 2) (i32.const 3)))) -(assert_trap (invoke "test") "out of bounds") +(assert_trap (invoke "test") "out of bounds memory access") (module (memory 1) (data "\37") (func (export "test") (memory.init 0 (i32.const 0xFFFE) (i32.const 1) (i32.const 3)))) -(assert_trap (invoke "test") "out of bounds") +(assert_trap (invoke "test") "out of bounds memory access") (module (memory 1) (data "\37") (func (export "test") (memory.init 0 (i32.const 1234) (i32.const 4) (i32.const 0)))) -(assert_trap (invoke "test") "out of bounds") +(assert_trap (invoke "test") "out of bounds memory access") (module (memory 1) @@ -285,7 +285,7 @@ (data "\37") (func (export "test") (memory.init 0 (i32.const 0x10001) (i32.const 0) (i32.const 0)))) -(assert_trap (invoke "test") "out of bounds") +(assert_trap (invoke "test") "out of bounds memory access") (module (memory 1) @@ -306,7 +306,7 @@ (data "\37") (func (export "test") (memory.init 0 (i32.const 0x10001) (i32.const 4) (i32.const 0)))) -(assert_trap (invoke "test") "out of bounds") +(assert_trap (invoke "test") "out of bounds memory access") (assert_invalid (module @@ -831,7 +831,7 @@ (memory.init 0 (local.get $offs) (i32.const 0) (local.get $len)))) (assert_trap (invoke "run" (i32.const 65528) (i32.const 16)) - "out of bounds") + "out of bounds memory access") (assert_return (invoke "checkRange" (i32.const 0) (i32.const 1) (i32.const 0)) (i32.const -1)) @@ -854,7 +854,7 @@ (memory.init 0 (local.get $offs) (i32.const 0) (local.get $len)))) (assert_trap (invoke "run" (i32.const 65527) (i32.const 16)) - "out of bounds") + "out of bounds memory access") (assert_return (invoke "checkRange" (i32.const 0) (i32.const 1) (i32.const 0)) (i32.const -1)) @@ -877,7 +877,7 @@ (memory.init 0 (local.get $offs) (i32.const 0) (local.get $len)))) (assert_trap (invoke "run" (i32.const 65472) (i32.const 30)) - "out of bounds") + "out of bounds memory access") (assert_return (invoke "checkRange" (i32.const 0) (i32.const 1) (i32.const 0)) (i32.const -1)) @@ -900,7 +900,7 @@ (memory.init 0 (local.get $offs) (i32.const 0) (local.get $len)))) (assert_trap (invoke "run" (i32.const 65473) (i32.const 31)) - "out of bounds") + "out of bounds memory access") (assert_return (invoke "checkRange" (i32.const 0) (i32.const 1) (i32.const 0)) (i32.const -1)) @@ -923,7 +923,7 @@ (memory.init 0 (local.get $offs) (i32.const 0) (local.get $len)))) (assert_trap (invoke "run" (i32.const 65528) (i32.const 4294967040)) - "out of bounds") + "out of bounds memory access") (assert_return (invoke "checkRange" (i32.const 0) (i32.const 1) (i32.const 0)) (i32.const -1)) @@ -946,7 +946,7 @@ (memory.init 0 (local.get $offs) (i32.const 0) (local.get $len)))) (assert_trap (invoke "run" (i32.const 0) (i32.const 4294967292)) - "out of bounds") + "out of bounds memory access") (assert_return (invoke "checkRange" (i32.const 0) (i32.const 1) (i32.const 0)) (i32.const -1)) diff --git a/test/core/table_copy.wast b/test/core/table_copy.wast index 9788c3f4f4..380e84ee59 100644 --- a/test/core/table_copy.wast +++ b/test/core/table_copy.wast @@ -1691,7 +1691,7 @@ (table.copy $t0 $t0 (i32.const 28) (i32.const 1) (i32.const 3)) )) -(assert_trap (invoke "test") "out of bounds") +(assert_trap (invoke "test") "out of bounds table access") (module (table $t0 30 30 funcref) @@ -1716,7 +1716,7 @@ (table.copy $t0 $t0 (i32.const 0xFFFFFFFE) (i32.const 1) (i32.const 2)) )) -(assert_trap (invoke "test") "out of bounds") +(assert_trap (invoke "test") "out of bounds table access") (module (table $t0 30 30 funcref) @@ -1741,7 +1741,7 @@ (table.copy $t0 $t0 (i32.const 15) (i32.const 25) (i32.const 6)) )) -(assert_trap (invoke "test") "out of bounds") +(assert_trap (invoke "test") "out of bounds table access") (module (table $t0 30 30 funcref) @@ -1766,7 +1766,7 @@ (table.copy $t0 $t0 (i32.const 15) (i32.const 0xFFFFFFFE) (i32.const 2)) )) -(assert_trap (invoke "test") "out of bounds") +(assert_trap (invoke "test") "out of bounds table access") (module (table $t0 30 30 funcref) @@ -1841,7 +1841,7 @@ (table.copy $t0 $t0 (i32.const 31) (i32.const 15) (i32.const 0)) )) -(assert_trap (invoke "test") "out of bounds") +(assert_trap (invoke "test") "out of bounds table access") (module (table $t0 30 30 funcref) @@ -1891,7 +1891,7 @@ (table.copy $t0 $t0 (i32.const 15) (i32.const 31) (i32.const 0)) )) -(assert_trap (invoke "test") "out of bounds") +(assert_trap (invoke "test") "out of bounds table access") (module (table $t0 30 30 funcref) @@ -1941,7 +1941,7 @@ (table.copy $t0 $t0 (i32.const 31) (i32.const 31) (i32.const 0)) )) -(assert_trap (invoke "test") "out of bounds") +(assert_trap (invoke "test") "out of bounds table access") (module (table $t0 30 30 funcref) @@ -1966,7 +1966,7 @@ (table.copy $t1 $t0 (i32.const 28) (i32.const 1) (i32.const 3)) )) -(assert_trap (invoke "test") "out of bounds") +(assert_trap (invoke "test") "out of bounds table access") (module (table $t0 30 30 funcref) @@ -1991,7 +1991,7 @@ (table.copy $t1 $t0 (i32.const 0xFFFFFFFE) (i32.const 1) (i32.const 2)) )) -(assert_trap (invoke "test") "out of bounds") +(assert_trap (invoke "test") "out of bounds table access") (module (table $t0 30 30 funcref) @@ -2016,7 +2016,7 @@ (table.copy $t1 $t0 (i32.const 15) (i32.const 25) (i32.const 6)) )) -(assert_trap (invoke "test") "out of bounds") +(assert_trap (invoke "test") "out of bounds table access") (module (table $t0 30 30 funcref) @@ -2041,7 +2041,7 @@ (table.copy $t1 $t0 (i32.const 15) (i32.const 0xFFFFFFFE) (i32.const 2)) )) -(assert_trap (invoke "test") "out of bounds") +(assert_trap (invoke "test") "out of bounds table access") (module (table $t0 30 30 funcref) @@ -2116,7 +2116,7 @@ (table.copy $t1 $t0 (i32.const 31) (i32.const 15) (i32.const 0)) )) -(assert_trap (invoke "test") "out of bounds") +(assert_trap (invoke "test") "out of bounds table access") (module (table $t0 30 30 funcref) @@ -2166,7 +2166,7 @@ (table.copy $t1 $t0 (i32.const 15) (i32.const 31) (i32.const 0)) )) -(assert_trap (invoke "test") "out of bounds") +(assert_trap (invoke "test") "out of bounds table access") (module (table $t0 30 30 funcref) @@ -2216,7 +2216,7 @@ (table.copy $t1 $t0 (i32.const 31) (i32.const 31) (i32.const 0)) )) -(assert_trap (invoke "test") "out of bounds") +(assert_trap (invoke "test") "out of bounds table access") (module (type (func (result i32))) @@ -2245,7 +2245,7 @@ (table.copy (local.get $targetOffs) (local.get $srcOffs) (local.get $len)))) (assert_trap (invoke "run" (i32.const 24) (i32.const 0) (i32.const 16)) - "out of bounds") + "out of bounds table access") (assert_return (invoke "test" (i32.const 0)) (i32.const 0)) (assert_return (invoke "test" (i32.const 1)) (i32.const 1)) (assert_return (invoke "test" (i32.const 2)) (i32.const 2)) @@ -2306,7 +2306,7 @@ (table.copy (local.get $targetOffs) (local.get $srcOffs) (local.get $len)))) (assert_trap (invoke "run" (i32.const 23) (i32.const 0) (i32.const 15)) - "out of bounds") + "out of bounds table access") (assert_return (invoke "test" (i32.const 0)) (i32.const 0)) (assert_return (invoke "test" (i32.const 1)) (i32.const 1)) (assert_return (invoke "test" (i32.const 2)) (i32.const 2)) @@ -2367,7 +2367,7 @@ (table.copy (local.get $targetOffs) (local.get $srcOffs) (local.get $len)))) (assert_trap (invoke "run" (i32.const 0) (i32.const 24) (i32.const 16)) - "out of bounds") + "out of bounds table access") (assert_trap (invoke "test" (i32.const 0)) "uninitialized element") (assert_trap (invoke "test" (i32.const 1)) "uninitialized element") (assert_trap (invoke "test" (i32.const 2)) "uninitialized element") @@ -2428,7 +2428,7 @@ (table.copy (local.get $targetOffs) (local.get $srcOffs) (local.get $len)))) (assert_trap (invoke "run" (i32.const 0) (i32.const 23) (i32.const 15)) - "out of bounds") + "out of bounds table access") (assert_trap (invoke "test" (i32.const 0)) "uninitialized element") (assert_trap (invoke "test" (i32.const 1)) "uninitialized element") (assert_trap (invoke "test" (i32.const 2)) "uninitialized element") @@ -2489,7 +2489,7 @@ (table.copy (local.get $targetOffs) (local.get $srcOffs) (local.get $len)))) (assert_trap (invoke "run" (i32.const 24) (i32.const 11) (i32.const 16)) - "out of bounds") + "out of bounds table access") (assert_trap (invoke "test" (i32.const 0)) "uninitialized element") (assert_trap (invoke "test" (i32.const 1)) "uninitialized element") (assert_trap (invoke "test" (i32.const 2)) "uninitialized element") @@ -2550,7 +2550,7 @@ (table.copy (local.get $targetOffs) (local.get $srcOffs) (local.get $len)))) (assert_trap (invoke "run" (i32.const 11) (i32.const 24) (i32.const 16)) - "out of bounds") + "out of bounds table access") (assert_trap (invoke "test" (i32.const 0)) "uninitialized element") (assert_trap (invoke "test" (i32.const 1)) "uninitialized element") (assert_trap (invoke "test" (i32.const 2)) "uninitialized element") @@ -2611,7 +2611,7 @@ (table.copy (local.get $targetOffs) (local.get $srcOffs) (local.get $len)))) (assert_trap (invoke "run" (i32.const 24) (i32.const 21) (i32.const 16)) - "out of bounds") + "out of bounds table access") (assert_trap (invoke "test" (i32.const 0)) "uninitialized element") (assert_trap (invoke "test" (i32.const 1)) "uninitialized element") (assert_trap (invoke "test" (i32.const 2)) "uninitialized element") @@ -2672,7 +2672,7 @@ (table.copy (local.get $targetOffs) (local.get $srcOffs) (local.get $len)))) (assert_trap (invoke "run" (i32.const 21) (i32.const 24) (i32.const 16)) - "out of bounds") + "out of bounds table access") (assert_trap (invoke "test" (i32.const 0)) "uninitialized element") (assert_trap (invoke "test" (i32.const 1)) "uninitialized element") (assert_trap (invoke "test" (i32.const 2)) "uninitialized element") @@ -2733,7 +2733,7 @@ (table.copy (local.get $targetOffs) (local.get $srcOffs) (local.get $len)))) (assert_trap (invoke "run" (i32.const 21) (i32.const 21) (i32.const 16)) - "out of bounds") + "out of bounds table access") (assert_trap (invoke "test" (i32.const 0)) "uninitialized element") (assert_trap (invoke "test" (i32.const 1)) "uninitialized element") (assert_trap (invoke "test" (i32.const 2)) "uninitialized element") @@ -2794,7 +2794,7 @@ (table.copy (local.get $targetOffs) (local.get $srcOffs) (local.get $len)))) (assert_trap (invoke "run" (i32.const 0) (i32.const 112) (i32.const 4294967264)) - "out of bounds") + "out of bounds table access") (assert_trap (invoke "test" (i32.const 0)) "uninitialized element") (assert_trap (invoke "test" (i32.const 1)) "uninitialized element") (assert_trap (invoke "test" (i32.const 2)) "uninitialized element") @@ -2951,7 +2951,7 @@ (table.copy (local.get $targetOffs) (local.get $srcOffs) (local.get $len)))) (assert_trap (invoke "run" (i32.const 112) (i32.const 0) (i32.const 4294967264)) - "out of bounds") + "out of bounds table access") (assert_return (invoke "test" (i32.const 0)) (i32.const 0)) (assert_return (invoke "test" (i32.const 1)) (i32.const 1)) (assert_return (invoke "test" (i32.const 2)) (i32.const 2)) diff --git a/test/core/table_fill.wast b/test/core/table_fill.wast index 29c556db94..3df64da1ab 100644 --- a/test/core/table_fill.wast +++ b/test/core/table_fill.wast @@ -48,7 +48,7 @@ (assert_trap (invoke "fill" (i32.const 8) (ref.extern 6) (i32.const 3)) - "out of bounds" + "out of bounds table access" ) (assert_return (invoke "get" (i32.const 7)) (ref.null extern)) (assert_return (invoke "get" (i32.const 8)) (ref.extern 4)) @@ -56,12 +56,12 @@ (assert_trap (invoke "fill" (i32.const 11) (ref.null extern) (i32.const 0)) - "out of bounds" + "out of bounds table access" ) (assert_trap (invoke "fill" (i32.const 11) (ref.null extern) (i32.const 10)) - "out of bounds" + "out of bounds table access" ) diff --git a/test/core/table_get.wast b/test/core/table_get.wast index 0cb0c3c4a7..5d57c31983 100644 --- a/test/core/table_get.wast +++ b/test/core/table_get.wast @@ -30,10 +30,10 @@ (assert_return (invoke "is_null-funcref" (i32.const 1)) (i32.const 0)) (assert_return (invoke "is_null-funcref" (i32.const 2)) (i32.const 0)) -(assert_trap (invoke "get-externref" (i32.const 2)) "out of bounds") -(assert_trap (invoke "get-funcref" (i32.const 3)) "out of bounds") -(assert_trap (invoke "get-externref" (i32.const -1)) "out of bounds") -(assert_trap (invoke "get-funcref" (i32.const -1)) "out of bounds") +(assert_trap (invoke "get-externref" (i32.const 2)) "out of bounds table access") +(assert_trap (invoke "get-funcref" (i32.const 3)) "out of bounds table access") +(assert_trap (invoke "get-externref" (i32.const -1)) "out of bounds table access") +(assert_trap (invoke "get-funcref" (i32.const -1)) "out of bounds table access") ;; Type errors diff --git a/test/core/table_init.wast b/test/core/table_init.wast index 371bddd43c..0b2d26f772 100644 --- a/test/core/table_init.wast +++ b/test/core/table_init.wast @@ -450,7 +450,7 @@ (func (export "test") (table.init 2 (i32.const 12) (i32.const 1) (i32.const 1)) )) -(assert_trap (invoke "test") "out of bounds") +(assert_trap (invoke "test") "out of bounds table access") (module (table $t0 30 30 funcref) @@ -522,7 +522,7 @@ (func (export "test") (elem.drop 1) (table.init 1 (i32.const 12) (i32.const 1) (i32.const 1)))) -(assert_trap (invoke "test") "out of bounds") +(assert_trap (invoke "test") "out of bounds table access") (module (table $t0 30 30 funcref) @@ -546,7 +546,7 @@ (func (export "test") (table.init 1 (i32.const 12) (i32.const 0) (i32.const 5)) )) -(assert_trap (invoke "test") "out of bounds") +(assert_trap (invoke "test") "out of bounds table access") (module (table $t0 30 30 funcref) @@ -570,7 +570,7 @@ (func (export "test") (table.init 1 (i32.const 12) (i32.const 2) (i32.const 3)) )) -(assert_trap (invoke "test") "out of bounds") +(assert_trap (invoke "test") "out of bounds table access") (module (table $t0 30 30 funcref) @@ -594,7 +594,7 @@ (func (export "test") (table.init $t0 1 (i32.const 28) (i32.const 1) (i32.const 3)) )) -(assert_trap (invoke "test") "out of bounds") +(assert_trap (invoke "test") "out of bounds table access") (module (table $t0 30 30 funcref) @@ -642,7 +642,7 @@ (func (export "test") (table.init $t0 1 (i32.const 12) (i32.const 5) (i32.const 0)) )) -(assert_trap (invoke "test") "out of bounds") +(assert_trap (invoke "test") "out of bounds table access") (module (table $t0 30 30 funcref) @@ -690,7 +690,7 @@ (func (export "test") (table.init $t0 1 (i32.const 31) (i32.const 2) (i32.const 0)) )) -(assert_trap (invoke "test") "out of bounds") +(assert_trap (invoke "test") "out of bounds table access") (module (table $t0 30 30 funcref) @@ -738,7 +738,7 @@ (func (export "test") (table.init $t0 1 (i32.const 31) (i32.const 5) (i32.const 0)) )) -(assert_trap (invoke "test") "out of bounds") +(assert_trap (invoke "test") "out of bounds table access") (module (table $t0 30 30 funcref) @@ -762,7 +762,7 @@ (func (export "test") (table.init $t1 1 (i32.const 26) (i32.const 1) (i32.const 3)) )) -(assert_trap (invoke "test") "out of bounds") +(assert_trap (invoke "test") "out of bounds table access") (module (table $t0 30 30 funcref) @@ -810,7 +810,7 @@ (func (export "test") (table.init $t1 1 (i32.const 12) (i32.const 5) (i32.const 0)) )) -(assert_trap (invoke "test") "out of bounds") +(assert_trap (invoke "test") "out of bounds table access") (module (table $t0 30 30 funcref) @@ -858,7 +858,7 @@ (func (export "test") (table.init $t1 1 (i32.const 29) (i32.const 2) (i32.const 0)) )) -(assert_trap (invoke "test") "out of bounds") +(assert_trap (invoke "test") "out of bounds table access") (module (table $t0 30 30 funcref) @@ -906,7 +906,7 @@ (func (export "test") (table.init $t1 1 (i32.const 29) (i32.const 5) (i32.const 0)) )) -(assert_trap (invoke "test") "out of bounds") +(assert_trap (invoke "test") "out of bounds table access") (assert_invalid (module @@ -1503,7 +1503,7 @@ (call_indirect (type 0) (local.get $n))) (func (export "run") (param $offs i32) (param $len i32) (table.init 0 (local.get $offs) (i32.const 0) (local.get $len)))) -(assert_trap (invoke "run" (i32.const 24) (i32.const 16)) "out of bounds") +(assert_trap (invoke "run" (i32.const 24) (i32.const 16)) "out of bounds table access") (assert_trap (invoke "test" (i32.const 0)) "uninitialized element") (assert_trap (invoke "test" (i32.const 1)) "uninitialized element") (assert_trap (invoke "test" (i32.const 2)) "uninitialized element") @@ -1565,7 +1565,7 @@ (call_indirect (type 0) (local.get $n))) (func (export "run") (param $offs i32) (param $len i32) (table.init 0 (local.get $offs) (i32.const 0) (local.get $len)))) -(assert_trap (invoke "run" (i32.const 25) (i32.const 16)) "out of bounds") +(assert_trap (invoke "run" (i32.const 25) (i32.const 16)) "out of bounds table access") (assert_trap (invoke "test" (i32.const 0)) "uninitialized element") (assert_trap (invoke "test" (i32.const 1)) "uninitialized element") (assert_trap (invoke "test" (i32.const 2)) "uninitialized element") @@ -1627,7 +1627,7 @@ (call_indirect (type 0) (local.get $n))) (func (export "run") (param $offs i32) (param $len i32) (table.init 0 (local.get $offs) (i32.const 0) (local.get $len)))) -(assert_trap (invoke "run" (i32.const 96) (i32.const 32)) "out of bounds") +(assert_trap (invoke "run" (i32.const 96) (i32.const 32)) "out of bounds table access") (assert_trap (invoke "test" (i32.const 0)) "uninitialized element") (assert_trap (invoke "test" (i32.const 1)) "uninitialized element") (assert_trap (invoke "test" (i32.const 2)) "uninitialized element") @@ -1817,7 +1817,7 @@ (call_indirect (type 0) (local.get $n))) (func (export "run") (param $offs i32) (param $len i32) (table.init 0 (local.get $offs) (i32.const 0) (local.get $len)))) -(assert_trap (invoke "run" (i32.const 97) (i32.const 31)) "out of bounds") +(assert_trap (invoke "run" (i32.const 97) (i32.const 31)) "out of bounds table access") (assert_trap (invoke "test" (i32.const 0)) "uninitialized element") (assert_trap (invoke "test" (i32.const 1)) "uninitialized element") (assert_trap (invoke "test" (i32.const 2)) "uninitialized element") @@ -2007,7 +2007,7 @@ (call_indirect (type 0) (local.get $n))) (func (export "run") (param $offs i32) (param $len i32) (table.init 0 (local.get $offs) (i32.const 0) (local.get $len)))) -(assert_trap (invoke "run" (i32.const 48) (i32.const 4294967280)) "out of bounds") +(assert_trap (invoke "run" (i32.const 48) (i32.const 4294967280)) "out of bounds table access") (assert_trap (invoke "test" (i32.const 0)) "uninitialized element") (assert_trap (invoke "test" (i32.const 1)) "uninitialized element") (assert_trap (invoke "test" (i32.const 2)) "uninitialized element") @@ -2101,7 +2101,7 @@ (call_indirect (type 0) (local.get $n))) (func (export "run") (param $offs i32) (param $len i32) (table.init 0 (local.get $offs) (i32.const 8) (local.get $len)))) -(assert_trap (invoke "run" (i32.const 0) (i32.const 4294967292)) "out of bounds") +(assert_trap (invoke "run" (i32.const 0) (i32.const 4294967292)) "out of bounds table access") (assert_trap (invoke "test" (i32.const 0)) "uninitialized element") (assert_trap (invoke "test" (i32.const 1)) "uninitialized element") (assert_trap (invoke "test" (i32.const 2)) "uninitialized element") diff --git a/test/core/table_set.wast b/test/core/table_set.wast index f37ef14d6c..5a9cfa3715 100644 --- a/test/core/table_set.wast +++ b/test/core/table_set.wast @@ -38,15 +38,15 @@ (assert_return (invoke "set-funcref" (i32.const 0) (ref.null func))) (assert_return (invoke "get-funcref" (i32.const 0)) (ref.null func)) -(assert_trap (invoke "set-externref" (i32.const 2) (ref.null extern)) "out of bounds") -(assert_trap (invoke "set-funcref" (i32.const 3) (ref.null func)) "out of bounds") -(assert_trap (invoke "set-externref" (i32.const -1) (ref.null extern)) "out of bounds") -(assert_trap (invoke "set-funcref" (i32.const -1) (ref.null func)) "out of bounds") +(assert_trap (invoke "set-externref" (i32.const 2) (ref.null extern)) "out of bounds table access") +(assert_trap (invoke "set-funcref" (i32.const 3) (ref.null func)) "out of bounds table access") +(assert_trap (invoke "set-externref" (i32.const -1) (ref.null extern)) "out of bounds table access") +(assert_trap (invoke "set-funcref" (i32.const -1) (ref.null func)) "out of bounds table access") -(assert_trap (invoke "set-externref" (i32.const 2) (ref.extern 0)) "out of bounds") -(assert_trap (invoke "set-funcref-from" (i32.const 3) (i32.const 1)) "out of bounds") -(assert_trap (invoke "set-externref" (i32.const -1) (ref.extern 0)) "out of bounds") -(assert_trap (invoke "set-funcref-from" (i32.const -1) (i32.const 1)) "out of bounds") +(assert_trap (invoke "set-externref" (i32.const 2) (ref.extern 0)) "out of bounds table access") +(assert_trap (invoke "set-funcref-from" (i32.const 3) (i32.const 1)) "out of bounds table access") +(assert_trap (invoke "set-externref" (i32.const -1) (ref.extern 0)) "out of bounds table access") +(assert_trap (invoke "set-funcref-from" (i32.const -1) (i32.const 1)) "out of bounds table access") ;; Type errors From 2ccd487dae350e790a90ac05a89adaaa369213ef Mon Sep 17 00:00:00 2001 From: Andreas Rossberg Date: Wed, 30 Sep 2020 17:44:17 +0200 Subject: [PATCH 184/199] [spec/interpreter/test] Reintroduce bottom type (#116) --- document/core/appendix/algorithm.rst | 19 +++++---- document/core/appendix/index-rules.rst | 4 +- document/core/util/macros.def | 3 ++ document/core/valid/instructions.rst | 55 ++++++++++++++++++++------ interpreter/valid/valid.ml | 9 +++-- test/core/br_table.wast | 12 ++++++ test/core/select.wast | 13 ++++++ test/core/unreached-invalid.wast | 15 ------- 8 files changed, 91 insertions(+), 39 deletions(-) diff --git a/document/core/appendix/algorithm.rst b/document/core/appendix/algorithm.rst index be20a53587..fcfe0ad410 100644 --- a/document/core/appendix/algorithm.rst +++ b/document/core/appendix/algorithm.rst @@ -27,11 +27,11 @@ Types are representable as an enumeration. type val_type = I32 | I64 | F32 | F64 | Funcref | Externref - func is_num(t : val_type) : bool = - return t = I32 || t = I64 || t = F32 || t = F64 + func is_num(t : val_type | Unknown) : bool = + return t = I32 || t = I64 || t = F32 || t = F64 || t = Unknown - func is_ref(t : val_type) : bool = - return t = Funcref || t = Externref + func is_ref(t : val_type | Unknown) : bool = + return t = Funcref || t = Externref || t = Unknown The algorithm uses two separate stacks: the *value stack* and the *control stack*. The former tracks the :ref:`types ` of operand values on the :ref:`stack `, @@ -52,7 +52,6 @@ the latter surrounding :ref:`structured control instructions `, or :code:`Unknown` when the type is not known. - For each entered block, the control stack records a *control frame* with the originating opcode, the types on the top of the operand stack at the start and end of the block (used to check its result as well as branches), the height of the operand stack at the start of the block (used to check that operands do not underflow the current block), and a flag recording whether the remainder of the block is unreachable (used to handle :ref:`stack-polymorphic ` typing after branches). For the purpose of presenting the algorithm, the operand and control stacks are simply maintained as global variables: @@ -222,13 +221,17 @@ Other instructions are checked in a similar manner.       push_vals(label_types(ctrls[n]))    case (br_table n* m) + pop_val(I32)       error_if(ctrls.size() < m) + let arity = label_types(ctrls[m]).size()       foreach (n in n*) -         error_if(ctrls.size() < n || label_types(ctrls[n]) =/= label_types(ctrls[m])) - pop_val(I32) -       pop_vals(label_types(ctrls[m])) +         error_if(ctrls.size() < n) +         error_if(label_types(ctrls[n]).size() =/= arity) + push_vals(pop_vals(label_types(ctrls[n]))) + pop_vals(label_types(ctrls[m]))       unreachable() + .. note:: It is an invariant under the current WebAssembly instruction set that an operand of :code:`Unknown` type is never duplicated on the stack. This would change if the language were extended with stack instructions like :code:`dup`. diff --git a/document/core/appendix/index-rules.rst b/document/core/appendix/index-rules.rst index dde34900e8..0da084123c 100644 --- a/document/core/appendix/index-rules.rst +++ b/document/core/appendix/index-rules.rst @@ -20,8 +20,8 @@ Construct Judgement :ref:`Memory type ` :math:`\vdashmemtype \memtype \ok` :ref:`Global type ` :math:`\vdashglobaltype \globaltype \ok` :ref:`External type ` :math:`\vdashexterntype \externtype \ok` -:ref:`Instruction ` :math:`S;C \vdashinstr \instr : \functype` -:ref:`Instruction sequence ` :math:`S;C \vdashinstrseq \instr^\ast : \functype` +:ref:`Instruction ` :math:`S;C \vdashinstr \instr : \stacktype` +:ref:`Instruction sequence ` :math:`S;C \vdashinstrseq \instr^\ast : \stacktype` :ref:`Expression ` :math:`C \vdashexpr \expr : \resulttype` :ref:`Function ` :math:`C \vdashfunc \func : \functype` :ref:`Table ` :math:`C \vdashtable \table : \tabletype` diff --git a/document/core/util/macros.def b/document/core/util/macros.def index 360b9d84ca..66dbd61838 100644 --- a/document/core/util/macros.def +++ b/document/core/util/macros.def @@ -209,6 +209,9 @@ .. |externtype| mathdef:: \xref{syntax/types}{syntax-externtype}{\X{externtype}} +.. |stacktype| mathdef:: \xref{syntax/types}{syntax-stacktype}{\X{stacktype}} +.. |opdtype| mathdef:: \xref{syntax/types}{syntax-opdtype}{\X{opdtype}} + .. Types, meta functions diff --git a/document/core/valid/instructions.rst b/document/core/valid/instructions.rst index 5dbf44f4e1..61744233a3 100644 --- a/document/core/valid/instructions.rst +++ b/document/core/valid/instructions.rst @@ -1,13 +1,39 @@ .. index:: instruction, function type, context, value, operand stack, ! polymorphism .. _valid-instr: +.. _syntax-stacktype: +.. _syntax-opdtype: Instructions ------------ -:ref:`Instructions ` are classified by :ref:`function types ` :math:`[t_1^\ast] \to [t_2^\ast]` -that describe how they manipulate the :ref:`operand stack `. -The types describe the required input stack with argument values of types :math:`t_1^\ast` that an instruction pops off +:ref:`Instructions ` are classified by *stack types* :math:`[t_1^\ast] \to [t_2^\ast]` that describe how instructions manipulate the :ref:`operand stack `. + +.. math:: + \begin{array}{llll} + \production{stack type} & \stacktype &::=& + [\opdtype^\ast] \to [\opdtype^\ast] \\ + \production{operand type} & \opdtype &::=& + \valtype ~|~ \bot \\ + \end{array} + +The types describe the required input stack with *operand types* :math:`t_1^\ast` that an instruction pops off and the provided output stack with result values of types :math:`t_2^\ast` that it pushes back. +Stack types are akin to :ref:`function types `, +except that they allow individual operands to be classified as :math:`\bot`, indicating that the type is unconstrained. +As an auxiliary notion, an operand type :math:`t_1` *matches* another operand type :math:`t_2`, if :math:`t_1` is either :math:`\bot` or equal to :math:`t_2`. + +.. _match-opdtype: + +.. math:: + \frac{ + }{ + \vdash t \leq t + } + \qquad + \frac{ + }{ + \vdash \bot \leq t + } .. note:: For example, the instruction :math:`\I32.\ADD` has type :math:`[\I32~\I32] \to [\I32]`, @@ -254,7 +280,7 @@ Parametric Instructions * Else: - * The instruction is valid with type :math:`[t~t~\I32] \to [t]`, for any :ref:`number type ` :math:`t`. + * The instruction is valid with type :math:`[t~t~\I32] \to [t]`, for any :ref:`operand type ` :math:`t` that :ref:`matches ` some :ref:`number type `. .. math:: \frac{ @@ -263,7 +289,7 @@ Parametric Instructions } \qquad \frac{ - t = \numtype + \vdash t \leq \numtype }{ C \vdashinstr \SELECT : [t~t~\I32] \to [t] } @@ -1033,7 +1059,7 @@ Empty Instruction Sequence: :math:`\epsilon` ............................................ * The empty instruction sequence is valid with type :math:`[t^\ast] \to [t^\ast]`, - for any sequence of :ref:`value types ` :math:`t^\ast`. + for any sequence of :ref:`operand types ` :math:`t^\ast`. .. math:: \frac{ @@ -1052,13 +1078,17 @@ Non-empty Instruction Sequence: :math:`\instr^\ast~\instr_N` for some sequences of :ref:`value types ` :math:`t^\ast` and :math:`t_3^\ast`. * There must be a sequence of :ref:`value types ` :math:`t_0^\ast`, - such that :math:`t_2^\ast = t_0^\ast~t^\ast`. + such that :math:`t_2^\ast = t_0^\ast~{t'}^\ast` where the type sequence :math:`{t'}^\ast` is as long as :math:`t^\ast`. + +* For each :ref:`operand type ` :math:`t'_i` in :math:`{t'}^\ast` and corresponding type :math:`t_i` in :math:`t^\ast`, :math:`t'_i` :ref:`matches ` :math:`t_i`. * Then the combined instruction sequence is valid with type :math:`[t_1^\ast] \to [t_0^\ast~t_3^\ast]`. .. math:: \frac{ - C \vdashinstrseq \instr^\ast : [t_1^\ast] \to [t_0^\ast~t^\ast] + C \vdashinstrseq \instr^\ast : [t_1^\ast] \to [t_0^\ast~{t'}^\ast] + \qquad + (\vdash t' \leq t)^\ast \qquad C \vdashinstr \instr_N : [t^\ast] \to [t_3^\ast] }{ @@ -1081,14 +1111,17 @@ Expressions :math:`\expr` are classified by :ref:`result types ` with type :math:`[] \to [t^\ast]`, - for some :ref:`result type ` :math:`[t^\ast]`. +* The instruction sequence :math:`\instr^\ast` must be :ref:`valid ` with some :ref:`stack type ` :math:`[] \to [t'^\ast]`. + +* For each :ref:`operand type ` :math:`t'_i` in :math:`{t'}^\ast` and corresponding :ref:`value type ` type :math:`t_i` in :math:`t^\ast`, :math:`t'_i` :ref:`matches ` :math:`t_i`. * Then the expression is valid with :ref:`result type ` :math:`[t^\ast]`. .. math:: \frac{ - C \vdashinstrseq \instr^\ast : [] \to [t^\ast] + C \vdashinstrseq \instr^\ast : [] \to [{t'}^\ast] + \qquad + (\vdash t' \leq t)^\ast }{ C \vdashexpr \instr^\ast~\END : [t^\ast] } diff --git a/interpreter/valid/valid.ml b/interpreter/valid/valid.ml index aff90b0c30..be8097ea8b 100644 --- a/interpreter/valid/valid.ml +++ b/interpreter/valid/valid.ml @@ -77,6 +77,7 @@ let known = List.map (fun t -> Some t) let stack ts = (NoEllipses, known ts) let (-~>) ts1 ts2 = {ins = NoEllipses, ts1; outs = NoEllipses, ts2} let (-->) ts1 ts2 = {ins = NoEllipses, known ts1; outs = NoEllipses, known ts2} +let (-~>...) ts1 ts2 = {ins = Ellipses, ts1; outs = Ellipses, ts2} let (-->...) ts1 ts2 = {ins = Ellipses, known ts1; outs = Ellipses, known ts2} let string_of_infer_type t = @@ -247,9 +248,11 @@ let rec check_instr (c : context) (e : instr) (s : infer_stack_type) : op_type = (label c x @ [NumType I32Type]) --> label c x | BrTable (xs, x) -> - let ts = label c x in - List.iter (fun x' -> check_stack (known ts) (known (label c x')) x'.at) xs; - (ts @ [NumType I32Type]) -->... [] + let n = List.length (label c x) in + let ts = Lib.List.table n (fun i -> peek (n - i) s) in + check_stack ts (known (label c x)) x.at; + List.iter (fun x' -> check_stack ts (known (label c x')) x'.at) xs; + (ts @ [Some (NumType I32Type)]) -~>... [] | Return -> c.results -->... [] diff --git a/test/core/br_table.wast b/test/core/br_table.wast index fc84e2f01e..a9649645b7 100644 --- a/test/core/br_table.wast +++ b/test/core/br_table.wast @@ -1250,6 +1250,18 @@ ) ) ) + + (func (export "meet-bottom") + (block (result f64) + (block (result f32) + (unreachable) + (br_table 0 1 1 (i32.const 1)) + ) + (drop) + (f64.const 0) + ) + (drop) + ) ) (assert_return (invoke "type-i32")) diff --git a/test/core/select.wast b/test/core/select.wast index 61edfd9ee5..b2098ffcc6 100644 --- a/test/core/select.wast +++ b/test/core/select.wast @@ -195,6 +195,19 @@ (i32.wrap_i64 (select (i64.const 1) (i64.const 0) (local.get 0))) ) ) + + (func (export "unreachable-num") + (unreachable) + (select) + (i32.eqz) + (drop) + ) + (func (export "unreachable-ref") + (unreachable) + (select) + (ref.is_null) + (drop) + ) ) (assert_return (invoke "select-i32" (i32.const 1) (i32.const 2) (i32.const 1)) (i32.const 1)) diff --git a/test/core/unreached-invalid.wast b/test/core/unreached-invalid.wast index aeecf28c2f..3ddd77385f 100644 --- a/test/core/unreached-invalid.wast +++ b/test/core/unreached-invalid.wast @@ -536,21 +536,6 @@ "type mismatch" ) -(assert_invalid - (module (func $type-br_table-label-num-vs-label-num-after-unreachable - (block (result f64) - (block (result f32) - (unreachable) - (br_table 0 1 1 (i32.const 1)) - ) - (drop) - (f64.const 0) - ) - (drop) - )) - "type mismatch" -) - (assert_invalid (module (func $type-block-value-nested-unreachable-num-vs-void (block (i32.const 3) (block (unreachable))) From 736bda27f3673869726889773e525e6bb68118cd Mon Sep 17 00:00:00 2001 From: gahaas Date: Mon, 12 Oct 2020 09:25:47 +0200 Subject: [PATCH 185/199] [test] Fix table index encoding (#154) The encoding of the table index in binary-leb128.wast is incorrect with the bulk-memory extensions, see https://github.com/WebAssembly/bulk-memory-operations/issues/153. I saw and fixed the issue first in the reference types proposal (see https://github.com/WebAssembly/reference-types/pull/95), but apparently it also exists here. --- test/core/binary-leb128.wast | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/test/core/binary-leb128.wast b/test/core/binary-leb128.wast index cd39a5d2c9..6e015e3d00 100644 --- a/test/core/binary-leb128.wast +++ b/test/core/binary-leb128.wast @@ -33,9 +33,10 @@ "\00asm" "\01\00\00\00" "\04\04\01" ;; Table section with 1 entry "\70\00\00" ;; no max, minimum 0, funcref - "\09\07\01" ;; Element section with 1 entry + "\09\09\01" ;; Element section with 1 entry + "\02" ;; Element with explicit table index "\80\00" ;; Table index 0, encoded with 2 bytes - "\41\00\0b\00" ;; (i32.const 0) with no elements + "\41\00\0b\00\00" ;; (i32.const 0) with no elements ) (module binary "\00asm" "\01\00\00\00" From 27993294bd38b3a4ca0703110bb22f84e8f7c5d8 Mon Sep 17 00:00:00 2001 From: Andreas Rossberg Date: Wed, 14 Oct 2020 08:31:18 +0200 Subject: [PATCH 186/199] [spec] Fix xref --- document/core/syntax/types.rst | 2 +- document/core/valid/instructions.rst | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/document/core/syntax/types.rst b/document/core/syntax/types.rst index 5a6c3d92ba..e354ee9d15 100644 --- a/document/core/syntax/types.rst +++ b/document/core/syntax/types.rst @@ -65,7 +65,7 @@ Reference types are *opaque*, meaning that neither their size nor their bit patt Values of reference type can be stored in :ref:`tables `. -.. index:: ! value type, number type, reference type, ! bottom type +.. index:: ! value type, number type, reference type pair: abstract syntax; value type pair: value; type .. _syntax-valtype: diff --git a/document/core/valid/instructions.rst b/document/core/valid/instructions.rst index 61744233a3..b2ebfab6ff 100644 --- a/document/core/valid/instructions.rst +++ b/document/core/valid/instructions.rst @@ -1,4 +1,4 @@ -.. index:: instruction, function type, context, value, operand stack, ! polymorphism +.. index:: instruction, function type, context, value, operand stack, ! polymorphism, ! bottom type .. _valid-instr: .. _syntax-stacktype: .. _syntax-opdtype: From 28c3a5b25c9e480f2c642f70ce8a861ac657fbeb Mon Sep 17 00:00:00 2001 From: Andreas Rossberg Date: Wed, 14 Oct 2020 08:33:43 +0200 Subject: [PATCH 187/199] [spec] Fix xref --- document/core/valid/instructions.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/document/core/valid/instructions.rst b/document/core/valid/instructions.rst index b2ebfab6ff..dac9c72903 100644 --- a/document/core/valid/instructions.rst +++ b/document/core/valid/instructions.rst @@ -19,7 +19,7 @@ Instructions The types describe the required input stack with *operand types* :math:`t_1^\ast` that an instruction pops off and the provided output stack with result values of types :math:`t_2^\ast` that it pushes back. Stack types are akin to :ref:`function types `, -except that they allow individual operands to be classified as :math:`\bot`, indicating that the type is unconstrained. +except that they allow individual operands to be classified as :math:`\bot` (*bottom*), indicating that the type is unconstrained. As an auxiliary notion, an operand type :math:`t_1` *matches* another operand type :math:`t_2`, if :math:`t_1` is either :math:`\bot` or equal to :math:`t_2`. .. _match-opdtype: From 9ad83c317258c2dc9ed6ecbd209fa98d6577ce8f Mon Sep 17 00:00:00 2001 From: Ms2ger Date: Mon, 19 Oct 2020 12:00:21 +0200 Subject: [PATCH 188/199] Fix formatting in 'Table Instructions'. (#119) --- document/core/syntax/instructions.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/document/core/syntax/instructions.rst b/document/core/syntax/instructions.rst index a967474288..0f777256b2 100644 --- a/document/core/syntax/instructions.rst +++ b/document/core/syntax/instructions.rst @@ -266,7 +266,7 @@ Instructions in this group are concerned with tables :ref:`table ` \TABLESET~\tableidx \\&&|& \TABLESIZE~\tableidx \\&&|& \TABLEGROW~\tableidx \\&&|& - \TABLEFILL~\tableidx \\ + \TABLEFILL~\tableidx \\&&|& \TABLECOPY \\&&|& \TABLEINIT~\elemidx \\&&|& \ELEMDROP~\elemidx \\ From 173ea330550608ad85ff7a079c5f12428b945ea5 Mon Sep 17 00:00:00 2001 From: Andy Wingo Date: Tue, 3 Nov 2020 10:41:40 +0100 Subject: [PATCH 189/199] Rename "refedtype" to "heaptype" (#124) --- document/core/text/instructions.rst | 2 +- document/core/text/types.rst | 4 ++-- document/core/util/macros.def | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/document/core/text/instructions.rst b/document/core/text/instructions.rst index 4c28acf1d7..c248bc0fa9 100644 --- a/document/core/text/instructions.rst +++ b/document/core/text/instructions.rst @@ -158,7 +158,7 @@ Reference Instructions .. math:: \begin{array}{llclll} \production{instruction} & \Tplaininstr_I &::=& \dots \\ &&|& - \text{ref.null}~~t{:}\Trefedtype &\Rightarrow& \REFNULL~t \\ &&|& + \text{ref.null}~~t{:}\Theaptype &\Rightarrow& \REFNULL~t \\ &&|& \text{ref.is\_null} &\Rightarrow& \REFISNULL \\ &&|& \text{ref.func}~~x{:}\Tfuncidx &\Rightarrow& \REFFUNC~x \\ &&|& \end{array} diff --git a/document/core/text/types.rst b/document/core/text/types.rst index bfeb2b82b4..6d4ee37582 100644 --- a/document/core/text/types.rst +++ b/document/core/text/types.rst @@ -25,7 +25,7 @@ Number Types .. index:: reference type pair: text format; reference type .. _text-reftype: -.. _text-refedtype: +.. _text-heaptype: Reference Types ~~~~~~~~~~~~~~~ @@ -35,7 +35,7 @@ Reference Types \production{reference type} & \Treftype &::=& \text{funcref} &\Rightarrow& \FUNCREF \\ &&|& \text{externref} &\Rightarrow& \EXTERNREF \\ - \production{referenced type} & \Trefedtype &::=& + \production{heap type} & \Theaptype &::=& \text{func} &\Rightarrow& \FUNCREF \\ &&|& \text{extern} &\Rightarrow& \EXTERNREF \\ \end{array} diff --git a/document/core/util/macros.def b/document/core/util/macros.def index 3379555da0..4e5b534c09 100644 --- a/document/core/util/macros.def +++ b/document/core/util/macros.def @@ -663,7 +663,7 @@ .. |Tnumtype| mathdef:: \xref{text/types}{text-numtype}{\T{numtype}} .. |Treftype| mathdef:: \xref{text/types}{text-reftype}{\T{reftype}} -.. |Trefedtype| mathdef:: \xref{text/types}{text-refedtype}{\T{refedtype}} +.. |Theaptype| mathdef:: \xref{text/types}{text-heaptype}{\T{heaptype}} .. |Tvaltype| mathdef:: \xref{text/types}{text-valtype}{\T{valtype}} .. |Tfunctype| mathdef:: \xref{text/types}{text-functype}{\T{functype}} From d6046b88c78928a8e48baedd61a2bf3cae16044a Mon Sep 17 00:00:00 2001 From: Andreas Rossberg Date: Wed, 4 Nov 2020 08:05:58 +0100 Subject: [PATCH 190/199] [spec] Fix instantiation to handle ref.func in initializers (#115) --- document/core/exec/modules.rst | 53 +++++++++++++++------------------- 1 file changed, 23 insertions(+), 30 deletions(-) diff --git a/document/core/exec/modules.rst b/document/core/exec/modules.rst index 35df503de5..48d6b03fc8 100644 --- a/document/core/exec/modules.rst +++ b/document/core/exec/modules.rst @@ -614,49 +614,41 @@ It is up to the :ref:`embedder ` to define how such conditions are rep .. _exec-initvals: -5. Let :math:`\val^\ast` be the vector of :ref:`global ` initialization :ref:`values ` determined by :math:`\module` and :math:`\externval^n`. These may be calculated as follows. +5. Let :math:`\moduleinst_{\F{init}}` be the auxiliary module :ref:`instance ` :math:`\{\MIGLOBALS~\evglobals(\externval^n), \MIFUNCS~\moduleinst.\MIFUNCS\}` that only consists of the imported globals and the imported and allocated functions from the final module instance :math:`\moduleinst`, defined below. - a. Let :math:`\moduleinst_{\F{im}}` be the auxiliary module :ref:`instance ` :math:`\{\MIGLOBALS~\evglobals(\externval^n)\}` that only consists of the imported globals. +6. Let :math:`F_{\F{init}}` be the auxiliary :ref:`frame ` :math:`\{ \AMODULE~\moduleinst_{\F{init}}, \ALOCALS~\epsilon \}`. - b. Let :math:`F_{\F{im}}` be the auxiliary :ref:`frame ` :math:`\{ \AMODULE~\moduleinst_{\F{im}}, \ALOCALS~\epsilon \}`. +7. Push the frame :math:`F_{\F{init}}` to the stack. - c. Push the frame :math:`F_{\F{im}}` to the stack. +8. Let :math:`\val^\ast` be the vector of :ref:`global ` initialization :ref:`values ` determined by :math:`\module` and :math:`\externval^n`. These may be calculated as follows. - d. For each :ref:`global ` :math:`\global_i` in :math:`\module.\MGLOBALS`, do: + a. For each :ref:`global ` :math:`\global_i` in :math:`\module.\MGLOBALS`, do: i. Let :math:`\val_i` be the result of :ref:`evaluating ` the initializer expression :math:`\global_i.\GINIT`. - e. Assert: due to :ref:`validation `, the frame :math:`F_{\F{im}}` is now on the top of the stack. + b. Assert: due to :ref:`validation `, the frame :math:`F_{\F{init}}` is now on the top of the stack. - f. Pop the frame :math:`F_{\F{im}}` from the stack. + c. Let :math:`\val^\ast` be the conatenation of :math:`\val_i` in index order. - g. Let :math:`\val^\ast` be the conatenation of :math:`\val_i` in index order. +9. Let :math:`(\reff^\ast)^\ast` be the list of :ref:`reference ` vectors determined by the :ref:`element segments ` in :math:`\module`. These may be calculated as follows. -6. Let :math:`(\reff^\ast)^\ast` be the list of :ref:`reference ` vectors determined by the :ref:`element segments ` in :math:`\module`. These may be calculated as follows. - - a. Let :math:`\moduleinst_{\F{im}}` be the auxiliary module :ref:`instance ` :math:`\{\MIGLOBALS~\evglobals(\externval^n)\}` that only consists of the imported globals. - - b. Let :math:`F_{\F{im}}` be the auxiliary :ref:`frame ` :math:`\{ \AMODULE~\moduleinst_{\F{im}}, \ALOCALS~\epsilon \}`. - - c. Push the frame :math:`F_{\F{im}}` to the stack. - - d. For each :ref:`element segment ` :math:`\elem_i` in :math:`\module.\MELEMS`, and for each element :ref:`expression ` :math:`\expr_{ij}` in :math:`\elem_i.\EINIT`, do: + a. For each :ref:`element segment ` :math:`\elem_i` in :math:`\module.\MELEMS`, and for each element :ref:`expression ` :math:`\expr_{ij}` in :math:`\elem_i.\EINIT`, do: i. Let :math:`\reff_{ij}` be the result of :ref:`evaluating ` the initializer expression :math:`\expr_{ij}`. - e. Pop the frame :math:`F_{\F{im}}` from the stack. + b. Let :math:`\reff^\ast_i` be the concatenation of function elements :math:`\reff_{ij}` in order of index :math:`j`. - f. Let :math:`\reff^\ast_i` be the concatenation of function elements :math:`\reff_{ij}` in order of index :math:`j`. + c. Let :math:`(\reff^\ast)^\ast` be the concatenation of function element vectors :math:`\reff^\ast_i` in order of index :math:`i`. - g. Let :math:`(\reff^\ast)^\ast` be the concatenation of function element vectors :math:`\reff^\ast_i` in order of index :math:`i`. +10. Pop the frame :math:`F_{\F{init}}` from the stack. -7. Let :math:`\moduleinst` be a new module instance :ref:`allocated ` from :math:`\module` in store :math:`S` with imports :math:`\externval^n`, global initializer values :math:`\val^\ast`, and element segment contents :math:`(\reff^\ast)^\ast`, and let :math:`S'` be the extended store produced by module allocation. +11. Let :math:`\moduleinst` be a new module instance :ref:`allocated ` from :math:`\module` in store :math:`S` with imports :math:`\externval^n`, global initializer values :math:`\val^\ast`, and element segment contents :math:`(\reff^\ast)^\ast`, and let :math:`S'` be the extended store produced by module allocation. -8. Let :math:`F` be the auxiliary :ref:`frame ` :math:`\{ \AMODULE~\moduleinst, \ALOCALS~\epsilon \}`. +12. Let :math:`F` be the auxiliary :ref:`frame ` :math:`\{ \AMODULE~\moduleinst, \ALOCALS~\epsilon \}`. -9. Push the frame :math:`F` to the stack. +13. Push the frame :math:`F` to the stack. -10. For each :ref:`element segment ` :math:`\elem_i` in :math:`\module.\MELEMS` whose :ref:`mode ` is of the form :math:`\EACTIVE~\{ \ETABLE~\tableidx_i, \EOFFSET~\X{einstr}^\ast_i~\END \}`, do: +14. For each :ref:`element segment ` :math:`\elem_i` in :math:`\module.\MELEMS` whose :ref:`mode ` is of the form :math:`\EACTIVE~\{ \ETABLE~\tableidx_i, \EOFFSET~\X{einstr}^\ast_i~\END \}`, do: a. Assert: :math:`\tableidx_i` is :math:`0`. @@ -672,7 +664,7 @@ It is up to the :ref:`embedder ` to define how such conditions are rep g. :ref:`Execute ` the instruction :math:`\ELEMDROP~i`. -11. For each :ref:`data segment ` :math:`\data_i` in :math:`\module.\MDATAS` whose :ref:`mode ` is of the form :math:`\DACTIVE~\{ \DMEM~\memidx_i, \DOFFSET~\X{dinstr}^\ast_i~\END \}`, do: +15. For each :ref:`data segment ` :math:`\data_i` in :math:`\module.\MDATAS` whose :ref:`mode ` is of the form :math:`\DACTIVE~\{ \DMEM~\memidx_i, \DOFFSET~\X{dinstr}^\ast_i~\END \}`, do: a. Assert: :math:`\memidx_i` is :math:`0`. @@ -688,15 +680,15 @@ It is up to the :ref:`embedder ` to define how such conditions are rep g. :ref:`Execute ` the instruction :math:`\DATADROP~i`. -12. If the :ref:`start function ` :math:`\module.\MSTART` is not empty, then: +16. If the :ref:`start function ` :math:`\module.\MSTART` is not empty, then: a. Let :math:`\start` be the :ref:`start function ` :math:`\module.\MSTART`. b. :ref:`Execute ` the instruction :math:`\CALL~\start.\SFUNC`. -13. Assert: due to :ref:`validation `, the frame :math:`F` is now on the top of the stack. +17. Assert: due to :ref:`validation `, the frame :math:`F` is now on the top of the stack. -14. Pop the frame :math:`F` from the stack. +18. Pop the frame :math:`F` from the stack. .. math:: @@ -742,9 +734,10 @@ where: \end{array} .. note:: - Module :ref:`allocation ` and the :ref:`evaluation ` of :ref:`global ` initializers are mutually recursive because the global initialization :ref:`values ` :math:`\val^\ast` are passed to the module allocator but depend on the store :math:`S'` and module instance :math:`\moduleinst` returned by allocation. + Module :ref:`allocation ` and the :ref:`evaluation ` of :ref:`global ` initializers and :ref:`element segments ` are mutually recursive because the global initialization :ref:`values ` :math:`\val^\ast` and element segment contents :math:`(\reff^\ast)^\ast` are passed to the module allocator while depending on the module instance :math:`\moduleinst` and store :math:`S'` returned by allocation. However, this recursion is just a specification device. - Due to :ref:`validation `, the initialization values can easily :ref:`be determined ` from a simple pre-pass that evaluates global initializers in the initial store. + In practice, the initialization values can :ref:`be determined ` beforehand by staging module allocation such that first, the module's own :math:`function instances ` are pre-allocated in the store, then the initializer expressions are evaluated, then the rest of the module instance is allocated, and finally the new function instances' :math:`\AMODULE` fields are set to that module instance. + This is possible because :ref:`validation ` ensures that initialization expressions cannot actually call a function, only take their reference. All failure conditions are checked before any observable mutation of the store takes place. Store mutation is not atomic; From c19b709d368310b5e4f34862de30b066b2fa7b9d Mon Sep 17 00:00:00 2001 From: Sergey Rubanov Date: Thu, 14 Jan 2021 11:02:26 +0300 Subject: [PATCH 191/199] Fix indentation (#126) --- document/core/binary/instructions.rst | 2 +- document/core/text/instructions.rst | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/document/core/binary/instructions.rst b/document/core/binary/instructions.rst index 29ed86851a..17aa5f439f 100644 --- a/document/core/binary/instructions.rst +++ b/document/core/binary/instructions.rst @@ -170,7 +170,7 @@ Table Instructions \hex{26}~~x{:}\Btableidx &\Rightarrow& \TABLESET~x \\ &&|& \hex{FC}~~12{:}\Bu32~~y{:}\Belemidx~~x{:}\Btableidx &\Rightarrow& \TABLEINIT~x~y \\ &&|& \hex{FC}~~13{:}\Bu32~~x{:}\Belemidx &\Rightarrow& \ELEMDROP~x \\ &&|& - \hex{FC}~~14{:}\Bu32~~x{:}\Btableidx~~y{:}\Btableidx &\Rightarrow& \TABLECOPY~x~y \\ + \hex{FC}~~14{:}\Bu32~~x{:}\Btableidx~~y{:}\Btableidx &\Rightarrow& \TABLECOPY~x~y \\ &&|& \hex{FC}~~15{:}\Bu32~~x{:}\Btableidx &\Rightarrow& \TABLEGROW~x \\ &&|& \hex{FC}~~16{:}\Bu32~~x{:}\Btableidx &\Rightarrow& \TABLESIZE~x \\ &&|& \hex{FC}~~17{:}\Bu32~~x{:}\Btableidx &\Rightarrow& \TABLEFILL~x \\ diff --git a/document/core/text/instructions.rst b/document/core/text/instructions.rst index c248bc0fa9..89a2758243 100644 --- a/document/core/text/instructions.rst +++ b/document/core/text/instructions.rst @@ -229,7 +229,7 @@ Table Instructions \text{table.set}~~x{:}\Ttableidx_I &\Rightarrow& \TABLESET~x \\ &&|& \text{table.size}~~x{:}\Ttableidx_I &\Rightarrow& \TABLESIZE~x \\ &&|& \text{table.grow}~~x{:}\Ttableidx_I &\Rightarrow& \TABLEGROW~x \\ &&|& - \text{table.fill}~~x{:}\Ttableidx_I &\Rightarrow& \TABLEFILL~x \\ + \text{table.fill}~~x{:}\Ttableidx_I &\Rightarrow& \TABLEFILL~x \\ &&|& \text{table.copy}~~x{:}\Ttableidx_I~~y{:}\Ttableidx_I &\Rightarrow& \TABLECOPY~x~y \\ &&|& \text{table.init}~~x{:}\Ttableidx_I~~y{:}\Telemidx_I &\Rightarrow& \TABLEINIT~x~y \\ &&|& \text{elem.drop}~~x{:}\Telemidx_I &\Rightarrow& \ELEMDROP~x \\ From 7c7bd2a9ed7554aba30563c8012ff7efda05cece Mon Sep 17 00:00:00 2001 From: Ms2ger Date: Thu, 14 Jan 2021 10:54:28 +0100 Subject: [PATCH 192/199] Fix some js-api bugs. (#128) --- document/js-api/index.bs | 37 +++++++++++++++---------------------- 1 file changed, 15 insertions(+), 22 deletions(-) diff --git a/document/js-api/index.bs b/document/js-api/index.bs index 35a591fc2e..79ccedfb17 100644 --- a/document/js-api/index.bs +++ b/document/js-api/index.bs @@ -740,14 +740,9 @@ interface Table { }; -
    -A {{Table}} object represents a single [=table instance=] -which can be simultaneously referenced by multiple {{Instance}} objects. -Each {{Table}} object has the following internal slots: - - * \[[Table]] : a [=table address=] - * \[[Values]] : a [=list=] whose elements depend on the element type of \[[Table]]'s [=table type=]. -
    +A {{Table}} object represents a single [=table instance=] which can be simultaneously referenced by +multiple {{Instance}} objects. +Each {{Table}} object has a \[[Table]] internal slot, which is a [=table address=].
    To initialize a table object |table| from a [=table address=] |tableaddr|, perform the following steps: @@ -770,7 +765,7 @@ Each {{Table}} object has the following internal slots:
    The Table(|descriptor|, |value|) constructor, when invoked, performs the following steps: 1. Let |elementType| be [=ToValueType=](|descriptor|["element"]). - 1. let |initial| be |descriptor|["initial"]. + 1. Let |initial| be |descriptor|["initial"]. 1. If |descriptor|["maximum"] [=map/exists=], let |maximum| be |descriptor|["maximum"]; otherwise, let |maximum| be empty. 1. If |maximum| is not empty and |maximum| < |initial|, throw a {{RangeError}} exception. 1. If |value| is missing, @@ -782,8 +777,6 @@ Each {{Table}} object has the following internal slots: 1. Let (|store|, |tableaddr|) be [=table_alloc=](|store|, |type|, |ref|). 1. Set the [=surrounding agent=]'s [=associated store=] to |store|. 1. [=initialize a table object|Initialize=] **this** from |tableaddr|. - 1. [=list/Empty=] **this**.\[[Values]]. - 1. [=list/Append=] |value| to **this**.\[[Values]] |initial| times.
    @@ -802,7 +795,6 @@ Each {{Table}} object has the following internal slots: Note: The above exception can happen due to either insufficient memory or an invalid size parameter. 1. Set the [=surrounding agent=]'s [=associated store=] to |result|. - 1. [=list/Append=] |value| to **this**.\[[Values]] |delta| times. 1. Return |initialSize|.
    @@ -819,14 +811,12 @@ Each {{Table}} object has the following internal slots: 1. Let |store| be the [=surrounding agent=]'s [=associated store=]. 1. Let |result| be [=table_read=](|store|, |tableaddr|, |index|). 1. If |result| is [=error=], throw a {{RangeError}} exception. - 1. Let |function| be the result of creating [=a new Exported Function=] from |result|. - 1. Return |function|. + 1. Return [=ToJSValue=](|result|).
    The set(|index|, |value|) method, when invoked, performs the following steps: 1. Let |tableaddr| be **this**.\[[Table]]. - 1. Let |values| be **this**.\[[Values]]. 1. Let (limits, |elementType|) be [=table_type=](|tableaddr|). 1. If |value| is missing, 1. Let |ref| be [=DefaultValue=](|elementType|). @@ -897,7 +887,7 @@ which can be simultaneously referenced by multiple {{Instance}} objects. Each 1. If |s| equals "i64", return [=i64=]. 1. If |s| equals "f32", return [=f32=]. 1. If |s| equals "f64", return [=f64=]. - 1. If |s| equals "funcref", return [=funcref=]. + 1. If |s| equals "anyfunc", return [=funcref=]. 1. If |s| equals "externref", return [=externref=]. 1. Assert: This step is not reached.
    @@ -908,6 +898,7 @@ which can be simultaneously referenced by multiple {{Instance}} objects. Each 1. If |valuetype| equals [=i64=], return [=i64.const=] 0. 1. If |valuetype| equals [=f32=], return [=f32.const=] 0. 1. If |valuetype| equals [=f64=], return [=f64.const=] 0. + 1. If |valuetype| equals [=funcref=], return [=ref.null=] [=funcref=]. 1. If |valuetype| equals [=externref=], return [=ToWebAssemblyValue=](undefined, |valuetype|). 1. Assert: This step is not reached.
    @@ -917,7 +908,7 @@ which can be simultaneously referenced by multiple {{Instance}} objects. Each 1. Let |mutable| be |descriptor|["mutable"]. 1. Let |valuetype| be [=ToValueType=](|descriptor|["value"]). 1. If |v| is missing, - 1. let |value| be [=DefaultValue=](|valuetype|). + 1. Let |value| be [=DefaultValue=](|valuetype|). 1. Otherwise, 1. Let |value| be [=ToWebAssemblyValue=](|v|, |valuetype|). 1. If |mutable| is true, let |globaltype| be [=var=] |valuetype|; otherwise, let |globaltype| be [=const=] |valuetype|. @@ -1088,10 +1079,13 @@ Note: Number values which are equal to NaN may have various observable NaN paylo
    - For retrieving an extern value from a [=extern address=] |externaddr|, perform the following steps: - 1. Let |map| be the [=surrounding agent=]'s associated [=extern value cache=]. - 1. Assert: |map|[|externaddr|] [=map/exists=]. - 1. Return |map|[|externaddr|]. + +For retrieving an extern value from an [=extern address=] |externaddr|, perform the following steps: + +1. Let |map| be the [=surrounding agent=]'s associated [=extern value cache=]. +1. Assert: |map|[|externaddr|] [=map/exists=]. +1. Return |map|[|externaddr|]. +
    @@ -1129,7 +1123,6 @@ The algorithm ToWebAssemblyValue(|v|, |type|) coerces a JavaScript va
    -

    Error Objects

    WebAssembly defines the following Error classes: CompileError, LinkError, and RuntimeError. From dd924229529b3cd5f511a7440f6c33bd37202515 Mon Sep 17 00:00:00 2001 From: Ms2ger Date: Thu, 14 Jan 2021 12:09:14 +0100 Subject: [PATCH 193/199] [js-api] Explicitly disallow creating Tables with non-reftypes. (#129) --- document/js-api/index.bs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/document/js-api/index.bs b/document/js-api/index.bs index 79ccedfb17..1e4aa51d37 100644 --- a/document/js-api/index.bs +++ b/document/js-api/index.bs @@ -155,6 +155,7 @@ urlPrefix: https://webassembly.github.io/reference-types/core/; spec: WebAssembl text: f32 text: f64 url: syntax/types.html#syntax-reftype + text: reftype text: funcref text: externref text: function element; url: exec/runtime.html#syntax-funcelem @@ -765,6 +766,8 @@ Each {{Table}} object has a \[[Table]] internal slot, which is a [=table address
    The Table(|descriptor|, |value|) constructor, when invoked, performs the following steps: 1. Let |elementType| be [=ToValueType=](|descriptor|["element"]). + 1. If |elementType| is not a [=reftype=], + 1. [=Throw=] a {{TypeError}} exception. 1. Let |initial| be |descriptor|["initial"]. 1. If |descriptor|["maximum"] [=map/exists=], let |maximum| be |descriptor|["maximum"]; otherwise, let |maximum| be empty. 1. If |maximum| is not empty and |maximum| < |initial|, throw a {{RangeError}} exception. From 44b626beab73c265bcff798856a9153dda0a6919 Mon Sep 17 00:00:00 2001 From: Andreas Rossberg Date: Wed, 10 Feb 2021 11:07:56 +0100 Subject: [PATCH 194/199] [spec] Add missing immediates --- document/core/syntax/instructions.rst | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/document/core/syntax/instructions.rst b/document/core/syntax/instructions.rst index 7432a247ee..039d4cfb2f 100644 --- a/document/core/syntax/instructions.rst +++ b/document/core/syntax/instructions.rst @@ -268,8 +268,8 @@ Instructions in this group are concerned with tables :ref:`table ` \TABLESIZE~\tableidx \\&&|& \TABLEGROW~\tableidx \\&&|& \TABLEFILL~\tableidx \\&&|& - \TABLECOPY \\&&|& - \TABLEINIT~\elemidx \\&&|& + \TABLECOPY~\tableidx~\tableidx \\&&|& + \TABLEINIT~\tableidx~\elemidx \\&&|& \ELEMDROP~\elemidx \\ \end{array} @@ -281,7 +281,7 @@ It also takes an initialization value for the newly allocated entries. The |TABLEFILL| instruction sets all entries in a range to a given value. -The |TABLECOPY| instruction copies elements from a source table region to a possibly overlapping destination region. +The |TABLECOPY| instruction copies elements from a source table region to a possibly overlapping destination region; the first index denotes the destination. The |TABLEINIT| instruction copies elements from a :ref:`passive element segment ` into a table. The |ELEMDROP| instruction prevents further use of a passive element segment. This instruction is intended to be used as an optimization hint. After an element segment is dropped its elements can no longer be retrieved, so the memory used by this segment may be freed. From 8546739cc7b95238828a75ec16cdca8c8b7790b5 Mon Sep 17 00:00:00 2001 From: Andreas Rossberg Date: Thu, 11 Feb 2021 16:01:19 +0100 Subject: [PATCH 195/199] Merge upstream (#157) --- document/README.md | 2 +- document/core/Makefile | 8 +- .../core/appendix/gen-index-instructions.py | 346 +++++++++++++ document/core/appendix/index-instructions.rst | 482 ++++++++++-------- document/core/exec/instructions.rst | 4 +- document/core/exec/numerics.rst | 2 +- document/core/text/instructions.rst | 16 +- document/js-api/index.bs | 3 +- document/web-api/index.bs | 22 +- interpreter/Makefile | 28 +- interpreter/README.md | 30 ++ interpreter/exec/int.ml | 2 +- interpreter/host/spectest.ml | 6 +- test/core/binary-leb128.wast | 2 +- test/core/binary.wast | 73 ++- test/core/br_table.wast | 35 ++ test/core/data.wast | 123 +++++ test/core/elem.wast | 61 +++ test/core/exports.wast | 32 ++ test/core/global.wast | 92 ++++ test/core/imports.wast | 51 ++ test/core/local_get.wast | 12 +- test/core/local_tee.wast | 38 +- test/core/select.wast | 81 ++- 24 files changed, 1270 insertions(+), 281 deletions(-) create mode 100755 document/core/appendix/gen-index-instructions.py diff --git a/document/README.md b/document/README.md index 05624181c4..326fc9a38a 100644 --- a/document/README.md +++ b/document/README.md @@ -88,7 +88,7 @@ You will also need `npm` and `yarn` for all the LaTeX goodness. `npm` might alre ``` npm install -g yarn -cd document/core +cd document make -C core bikeshed ``` diff --git a/document/core/Makefile b/document/core/Makefile index aaa01b4f99..3ff1a87cbb 100644 --- a/document/core/Makefile +++ b/document/core/Makefile @@ -89,8 +89,12 @@ bikeshed-keep: echo Downloaded Bikeshed. +.PHONY: index +index: + (cd appendix; ./gen-index-instructions.py) + .PHONY: pdf -pdf: latexpdf +pdf: index latexpdf mkdir -p $(BUILDDIR)/html/$(DOWNLOADDIR) ln -f $(BUILDDIR)/latex/$(NAME).pdf $(BUILDDIR)/html/$(DOWNLOADDIR)/$(NAME).pdf @@ -101,7 +105,7 @@ clean: rm -rf $(STATICDIR) .PHONY: html -html: +html: index $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html for file in `ls $(BUILDDIR)/html/*.html`; \ do \ diff --git a/document/core/appendix/gen-index-instructions.py b/document/core/appendix/gen-index-instructions.py new file mode 100755 index 0000000000..bc1b9e23e9 --- /dev/null +++ b/document/core/appendix/gen-index-instructions.py @@ -0,0 +1,346 @@ +#!/usr/bin/env python3 + +# This script generates the `index-instructions.rst` file. The table in that +# file is particularly annoying to update by hand, since the Restructured Text +# format requires the header and columns to line up properly. This is +# especially tedious when merging changes from the upstream spec, or merging a +# proposal back to the spec when it is standardized. + +import os + +SCRIPT_DIR = os.path.dirname(os.path.abspath(__file__)) +INDEX_INSTRUCTIONS_RST = os.path.join(SCRIPT_DIR, 'index-instructions.rst') + +HEADER = """\ +.. DO NOT EDIT: This file is auto-generated by the gen-index-instructions.py script. + +.. index:: instruction +.. _index-instr: + +Index of Instructions +--------------------- +""" + +COLUMNS = [ + 'Instruction', + 'Binary Opcode', + 'Type', + 'Validation', + 'Execution', +] + + +def MathWrap(s, default=''): + if s is None: + return default + else: + return f':math:`{s}`' + + +def RefWrap(s, kind): + if s is None: + return '' + else: + return f':ref:`{kind} <{s}>`' + + +def Instruction(name, opcode, type=None, validation=None, execution=None, operator=None): + if operator: + execution_str = ', '.join([RefWrap(execution, 'execution'), + RefWrap(operator, 'operator')]) + else: + execution_str = RefWrap(execution, 'execution') + + return ( + MathWrap(name, '(reserved)'), + MathWrap(opcode), + MathWrap(type), + RefWrap(validation, 'validation'), + execution_str + ) + + +INSTRUCTIONS = [ + Instruction(r'\UNREACHABLE', r'\hex{00}', r'[t_1^\ast] \to [t_2^\ast]', r'valid-unreachable', r'exec-unreachable'), + Instruction(r'\NOP', r'\hex{01}', r'[] \to []', r'valid-nop', r'exec-nop'), + Instruction(r'\BLOCK~\X{bt}', r'\hex{02}', r'[t_1^\ast] \to [t_2^\ast]', r'valid-block', r'exec-block'), + Instruction(r'\LOOP~\X{bt}', r'\hex{03}', r'[t_1^\ast] \to [t_2^\ast]', r'valid-loop', r'exec-loop'), + Instruction(r'\IF~\X{bt}', r'\hex{04}', r'[t_1^\ast] \to [t_2^\ast]', r'valid-if', r'exec-if'), + Instruction(r'\ELSE', r'\hex{05}'), + Instruction(None, r'\hex{06}'), + Instruction(None, r'\hex{07}'), + Instruction(None, r'\hex{08}'), + Instruction(None, r'\hex{09}'), + Instruction(None, r'\hex{0A}'), + Instruction(r'\END', r'\hex{0B}'), + Instruction(r'\BR~l', r'\hex{0C}', r'[t_1^\ast~t^\ast] \to [t_2^\ast]', r'valid-br', r'exec-br'), + Instruction(r'\BRIF~l', r'\hex{0D}', r'[t^\ast~\I32] \to [t^\ast]', r'valid-br_if', r'exec-br_if'), + Instruction(r'\BRTABLE~l^\ast~l', r'\hex{0E}', r'[t_1^\ast~t^\ast~\I32] \to [t_2^\ast]', r'valid-br_table', r'exec-br_table'), + Instruction(r'\RETURN', r'\hex{0F}', r'[t_1^\ast~t^\ast] \to [t_2^\ast]', r'valid-return', r'exec-return'), + Instruction(r'\CALL~x', r'\hex{10}', r'[t_1^\ast] \to [t_2^\ast]', r'valid-call', r'exec-call'), + Instruction(r'\CALLINDIRECT~x', r'\hex{11}', r'[t_1^\ast~\I32] \to [t_2^\ast]', r'valid-call_indirect', r'exec-call_indirect'), + Instruction(None, r'\hex{12}'), + Instruction(None, r'\hex{13}'), + Instruction(None, r'\hex{14}'), + Instruction(None, r'\hex{15}'), + Instruction(None, r'\hex{16}'), + Instruction(None, r'\hex{17}'), + Instruction(None, r'\hex{18}'), + Instruction(None, r'\hex{19}'), + Instruction(r'\DROP', r'\hex{1A}', r'[t] \to []', r'valid-drop', r'exec-drop'), + Instruction(r'\SELECT', r'\hex{1B}', r'[t~t~\I32] \to [t]', r'valid-select', r'exec-select'), + Instruction(None, r'\hex{1C}'), + Instruction(None, r'\hex{1D}'), + Instruction(None, r'\hex{1E}'), + Instruction(None, r'\hex{1F}'), + Instruction(r'\LOCALGET~x', r'\hex{20}', r'[] \to [t]', r'valid-local.get', r'exec-local.get'), + Instruction(r'\LOCALSET~x', r'\hex{21}', r'[t] \to []', r'valid-local.set', r'exec-local.set'), + Instruction(r'\LOCALTEE~x', r'\hex{22}', r'[t] \to [t]', r'valid-local.tee', r'exec-local.tee'), + Instruction(r'\GLOBALGET~x', r'\hex{23}', r'[] \to [t]', r'valid-global.get', r'exec-global.get'), + Instruction(r'\GLOBALSET~x', r'\hex{24}', r'[t] \to []', r'valid-global.set', r'exec-global.set'), + Instruction(None, r'\hex{25}'), + Instruction(None, r'\hex{26}'), + Instruction(None, r'\hex{27}'), + Instruction(r'\I32.\LOAD~\memarg', r'\hex{28}', r'[\I32] \to [\I32]', r'valid-load', r'exec-load'), + Instruction(r'\I64.\LOAD~\memarg', r'\hex{29}', r'[\I32] \to [\I64]', r'valid-load', r'exec-load'), + Instruction(r'\F32.\LOAD~\memarg', r'\hex{2A}', r'[\I32] \to [\F32]', r'valid-load', r'exec-load'), + Instruction(r'\F64.\LOAD~\memarg', r'\hex{2B}', r'[\I32] \to [\F64]', r'valid-load', r'exec-load'), + Instruction(r'\I32.\LOAD\K{8\_s}~\memarg', r'\hex{2C}', r'[\I32] \to [\I32]', r'valid-loadn', r'exec-loadn'), + Instruction(r'\I32.\LOAD\K{8\_u}~\memarg', r'\hex{2D}', r'[\I32] \to [\I32]', r'valid-loadn', r'exec-loadn'), + Instruction(r'\I32.\LOAD\K{16\_s}~\memarg', r'\hex{2E}', r'[\I32] \to [\I32]', r'valid-loadn', r'exec-loadn'), + Instruction(r'\I32.\LOAD\K{16\_u}~\memarg', r'\hex{2F}', r'[\I32] \to [\I32]', r'valid-loadn', r'exec-loadn'), + Instruction(r'\I64.\LOAD\K{8\_s}~\memarg', r'\hex{30}', r'[\I32] \to [\I64]', r'valid-loadn', r'exec-loadn'), + Instruction(r'\I64.\LOAD\K{8\_u}~\memarg', r'\hex{31}', r'[\I32] \to [\I64]', r'valid-loadn', r'exec-loadn'), + Instruction(r'\I64.\LOAD\K{16\_s}~\memarg', r'\hex{32}', r'[\I32] \to [\I64]', r'valid-loadn', r'exec-loadn'), + Instruction(r'\I64.\LOAD\K{16\_u}~\memarg', r'\hex{33}', r'[\I32] \to [\I64]', r'valid-loadn', r'exec-loadn'), + Instruction(r'\I64.\LOAD\K{32\_s}~\memarg', r'\hex{34}', r'[\I32] \to [\I64]', r'valid-loadn', r'exec-loadn'), + Instruction(r'\I64.\LOAD\K{32\_u}~\memarg', r'\hex{35}', r'[\I32] \to [\I64]', r'valid-loadn', r'exec-loadn'), + Instruction(r'\I32.\STORE~\memarg', r'\hex{36}', r'[\I32~\I32] \to []', r'valid-store', r'exec-store'), + Instruction(r'\I64.\STORE~\memarg', r'\hex{37}', r'[\I32~\I64] \to []', r'valid-store', r'exec-store'), + Instruction(r'\F32.\STORE~\memarg', r'\hex{38}', r'[\I32~\F32] \to []', r'valid-store', r'exec-store'), + Instruction(r'\F64.\STORE~\memarg', r'\hex{39}', r'[\I32~\F64] \to []', r'valid-store', r'exec-store'), + Instruction(r'\I32.\STORE\K{8}~\memarg', r'\hex{3A}', r'[\I32~\I32] \to []', r'valid-storen', r'exec-storen'), + Instruction(r'\I32.\STORE\K{16}~\memarg', r'\hex{3B}', r'[\I32~\I32] \to []', r'valid-storen', r'exec-storen'), + Instruction(r'\I64.\STORE\K{8}~\memarg', r'\hex{3C}', r'[\I32~\I64] \to []', r'valid-storen', r'exec-storen'), + Instruction(r'\I64.\STORE\K{16}~\memarg', r'\hex{3D}', r'[\I32~\I64] \to []', r'valid-storen', r'exec-storen'), + Instruction(r'\I64.\STORE\K{32}~\memarg', r'\hex{3E}', r'[\I32~\I64] \to []', r'valid-storen', r'exec-storen'), + Instruction(r'\MEMORYSIZE', r'\hex{3F}', r'[] \to [\I32]', r'valid-memory.size', r'exec-memory.size'), + Instruction(r'\MEMORYGROW', r'\hex{40}', r'[\I32] \to [\I32]', r'valid-memory.grow', r'exec-memory.grow'), + Instruction(r'\I32.\CONST~\i32', r'\hex{41}', r'[] \to [\I32]', r'valid-const', r'exec-const'), + Instruction(r'\I64.\CONST~\i64', r'\hex{42}', r'[] \to [\I64]', r'valid-const', r'exec-const'), + Instruction(r'\F32.\CONST~\f32', r'\hex{43}', r'[] \to [\F32]', r'valid-const', r'exec-const'), + Instruction(r'\F64.\CONST~\f64', r'\hex{44}', r'[] \to [\F64]', r'valid-const', r'exec-const'), + Instruction(r'\I32.\EQZ', r'\hex{45}', r'[\I32] \to [\I32]', r'valid-testop', r'exec-testop', r'op-ieqz'), + Instruction(r'\I32.\EQ', r'\hex{46}', r'[\I32~\I32] \to [\I32]', r'valid-relop', r'exec-relop', r'op-ieq'), + Instruction(r'\I32.\NE', r'\hex{47}', r'[\I32~\I32] \to [\I32]', r'valid-relop', r'exec-relop', r'op-ine'), + Instruction(r'\I32.\LT\K{\_s}', r'\hex{48}', r'[\I32~\I32] \to [\I32]', r'valid-relop', r'exec-relop', r'op-ilt_s'), + Instruction(r'\I32.\LT\K{\_u}', r'\hex{49}', r'[\I32~\I32] \to [\I32]', r'valid-relop', r'exec-relop', r'op-ilt_u'), + Instruction(r'\I32.\GT\K{\_s}', r'\hex{4A}', r'[\I32~\I32] \to [\I32]', r'valid-relop', r'exec-relop', r'op-igt_s'), + Instruction(r'\I32.\GT\K{\_u}', r'\hex{4B}', r'[\I32~\I32] \to [\I32]', r'valid-relop', r'exec-relop', r'op-igt_u'), + Instruction(r'\I32.\LE\K{\_s}', r'\hex{4C}', r'[\I32~\I32] \to [\I32]', r'valid-relop', r'exec-relop', r'op-ile_s'), + Instruction(r'\I32.\LE\K{\_u}', r'\hex{4D}', r'[\I32~\I32] \to [\I32]', r'valid-relop', r'exec-relop', r'op-ile_u'), + Instruction(r'\I32.\GE\K{\_s}', r'\hex{4E}', r'[\I32~\I32] \to [\I32]', r'valid-relop', r'exec-relop', r'op-ige_s'), + Instruction(r'\I32.\GE\K{\_u}', r'\hex{4F}', r'[\I32~\I32] \to [\I32]', r'valid-relop', r'exec-relop', r'op-ige_u'), + Instruction(r'\I64.\EQZ', r'\hex{50}', r'[\I64] \to [\I32]', r'valid-testop', r'exec-testop', r'op-ieqz'), + Instruction(r'\I64.\EQ', r'\hex{51}', r'[\I64~\I64] \to [\I32]', r'valid-relop', r'exec-relop', r'op-ieq'), + Instruction(r'\I64.\NE', r'\hex{52}', r'[\I64~\I64] \to [\I32]', r'valid-relop', r'exec-relop', r'op-ine'), + Instruction(r'\I64.\LT\K{\_s}', r'\hex{53}', r'[\I64~\I64] \to [\I32]', r'valid-relop', r'exec-relop', r'op-ilt_s'), + Instruction(r'\I64.\LT\K{\_u}', r'\hex{54}', r'[\I64~\I64] \to [\I32]', r'valid-relop', r'exec-relop', r'op-ilt_u'), + Instruction(r'\I64.\GT\K{\_s}', r'\hex{55}', r'[\I64~\I64] \to [\I32]', r'valid-relop', r'exec-relop', r'op-igt_s'), + Instruction(r'\I64.\GT\K{\_u}', r'\hex{56}', r'[\I64~\I64] \to [\I32]', r'valid-relop', r'exec-relop', r'op-igt_u'), + Instruction(r'\I64.\LE\K{\_s}', r'\hex{57}', r'[\I64~\I64] \to [\I32]', r'valid-relop', r'exec-relop', r'op-ile_s'), + Instruction(r'\I64.\LE\K{\_u}', r'\hex{58}', r'[\I64~\I64] \to [\I32]', r'valid-relop', r'exec-relop', r'op-ile_u'), + Instruction(r'\I64.\GE\K{\_s}', r'\hex{59}', r'[\I64~\I64] \to [\I32]', r'valid-relop', r'exec-relop', r'op-ige_s'), + Instruction(r'\I64.\GE\K{\_u}', r'\hex{5A}', r'[\I64~\I64] \to [\I32]', r'valid-relop', r'exec-relop', r'op-ige_u'), + Instruction(r'\F32.\EQ', r'\hex{5B}', r'[\F32~\F32] \to [\I32]', r'valid-relop', r'exec-relop', r'op-feq'), + Instruction(r'\F32.\NE', r'\hex{5C}', r'[\F32~\F32] \to [\I32]', r'valid-relop', r'exec-relop', r'op-fne'), + Instruction(r'\F32.\LT', r'\hex{5D}', r'[\F32~\F32] \to [\I32]', r'valid-relop', r'exec-relop', r'op-flt'), + Instruction(r'\F32.\GT', r'\hex{5E}', r'[\F32~\F32] \to [\I32]', r'valid-relop', r'exec-relop', r'op-fgt'), + Instruction(r'\F32.\LE', r'\hex{5F}', r'[\F32~\F32] \to [\I32]', r'valid-relop', r'exec-relop', r'op-fle'), + Instruction(r'\F32.\GE', r'\hex{60}', r'[\F32~\F32] \to [\I32]', r'valid-relop', r'exec-relop', r'op-fge'), + Instruction(r'\F64.\EQ', r'\hex{61}', r'[\F64~\F64] \to [\I32]', r'valid-relop', r'exec-relop', r'op-feq'), + Instruction(r'\F64.\NE', r'\hex{62}', r'[\F64~\F64] \to [\I32]', r'valid-relop', r'exec-relop', r'op-fne'), + Instruction(r'\F64.\LT', r'\hex{63}', r'[\F64~\F64] \to [\I32]', r'valid-relop', r'exec-relop', r'op-flt'), + Instruction(r'\F64.\GT', r'\hex{64}', r'[\F64~\F64] \to [\I32]', r'valid-relop', r'exec-relop', r'op-fgt'), + Instruction(r'\F64.\LE', r'\hex{65}', r'[\F64~\F64] \to [\I32]', r'valid-relop', r'exec-relop', r'op-fle'), + Instruction(r'\F64.\GE', r'\hex{66}', r'[\F64~\F64] \to [\I32]', r'valid-relop', r'exec-relop', r'op-fge'), + Instruction(r'\I32.\CLZ', r'\hex{67}', r'[\I32] \to [\I32]', r'valid-unop', r'exec-unop', r'op-iclz'), + Instruction(r'\I32.\CTZ', r'\hex{68}', r'[\I32] \to [\I32]', r'valid-unop', r'exec-unop', r'op-ictz'), + Instruction(r'\I32.\POPCNT', r'\hex{69}', r'[\I32] \to [\I32]', r'valid-unop', r'exec-unop', r'op-ipopcnt'), + Instruction(r'\I32.\ADD', r'\hex{6A}', r'[\I32~\I32] \to [\I32]', r'valid-binop', r'exec-binop', r'op-iadd'), + Instruction(r'\I32.\SUB', r'\hex{6B}', r'[\I32~\I32] \to [\I32]', r'valid-binop', r'exec-binop', r'op-isub'), + Instruction(r'\I32.\MUL', r'\hex{6C}', r'[\I32~\I32] \to [\I32]', r'valid-binop', r'exec-binop', r'op-imul'), + Instruction(r'\I32.\DIV\K{\_s}', r'\hex{6D}', r'[\I32~\I32] \to [\I32]', r'valid-binop', r'exec-binop', r'op-idiv_s'), + Instruction(r'\I32.\DIV\K{\_u}', r'\hex{6E}', r'[\I32~\I32] \to [\I32]', r'valid-binop', r'exec-binop', r'op-idiv_u'), + Instruction(r'\I32.\REM\K{\_s}', r'\hex{6F}', r'[\I32~\I32] \to [\I32]', r'valid-binop', r'exec-binop', r'op-irem_s'), + Instruction(r'\I32.\REM\K{\_u}', r'\hex{70}', r'[\I32~\I32] \to [\I32]', r'valid-binop', r'exec-binop', r'op-irem_u'), + Instruction(r'\I32.\AND', r'\hex{71}', r'[\I32~\I32] \to [\I32]', r'valid-binop', r'exec-binop', r'op-iand'), + Instruction(r'\I32.\OR', r'\hex{72}', r'[\I32~\I32] \to [\I32]', r'valid-binop', r'exec-binop', r'op-ior'), + Instruction(r'\I32.\XOR', r'\hex{73}', r'[\I32~\I32] \to [\I32]', r'valid-binop', r'exec-binop', r'op-ixor'), + Instruction(r'\I32.\SHL', r'\hex{74}', r'[\I32~\I32] \to [\I32]', r'valid-binop', r'exec-binop', r'op-ishl'), + Instruction(r'\I32.\SHR\K{\_s}', r'\hex{75}', r'[\I32~\I32] \to [\I32]', r'valid-binop', r'exec-binop', r'op-ishr_s'), + Instruction(r'\I32.\SHR\K{\_u}', r'\hex{76}', r'[\I32~\I32] \to [\I32]', r'valid-binop', r'exec-binop', r'op-ishr_u'), + Instruction(r'\I32.\ROTL', r'\hex{77}', r'[\I32~\I32] \to [\I32]', r'valid-binop', r'exec-binop', r'op-irotl'), + Instruction(r'\I32.\ROTR', r'\hex{78}', r'[\I32~\I32] \to [\I32]', r'valid-binop', r'exec-binop', r'op-irotr'), + Instruction(r'\I64.\CLZ', r'\hex{79}', r'[\I64] \to [\I64]', r'valid-unop', r'exec-unop', r'op-iclz'), + Instruction(r'\I64.\CTZ', r'\hex{7A}', r'[\I64] \to [\I64]', r'valid-unop', r'exec-unop', r'op-ictz'), + Instruction(r'\I64.\POPCNT', r'\hex{7B}', r'[\I64] \to [\I64]', r'valid-unop', r'exec-unop', r'op-ipopcnt'), + Instruction(r'\I64.\ADD', r'\hex{7C}', r'[\I64~\I64] \to [\I64]', r'valid-binop', r'exec-binop', r'op-iadd'), + Instruction(r'\I64.\SUB', r'\hex{7D}', r'[\I64~\I64] \to [\I64]', r'valid-binop', r'exec-binop', r'op-isub'), + Instruction(r'\I64.\MUL', r'\hex{7E}', r'[\I64~\I64] \to [\I64]', r'valid-binop', r'exec-binop', r'op-imul'), + Instruction(r'\I64.\DIV\K{\_s}', r'\hex{7F}', r'[\I64~\I64] \to [\I64]', r'valid-binop', r'exec-binop', r'op-idiv_s'), + Instruction(r'\I64.\DIV\K{\_u}', r'\hex{80}', r'[\I64~\I64] \to [\I64]', r'valid-binop', r'exec-binop', r'op-idiv_u'), + Instruction(r'\I64.\REM\K{\_s}', r'\hex{81}', r'[\I64~\I64] \to [\I64]', r'valid-binop', r'exec-binop', r'op-irem_s'), + Instruction(r'\I64.\REM\K{\_u}', r'\hex{82}', r'[\I64~\I64] \to [\I64]', r'valid-binop', r'exec-binop', r'op-irem_u'), + Instruction(r'\I64.\AND', r'\hex{83}', r'[\I64~\I64] \to [\I64]', r'valid-binop', r'exec-binop', r'op-iand'), + Instruction(r'\I64.\OR', r'\hex{84}', r'[\I64~\I64] \to [\I64]', r'valid-binop', r'exec-binop', r'op-ior'), + Instruction(r'\I64.\XOR', r'\hex{85}', r'[\I64~\I64] \to [\I64]', r'valid-binop', r'exec-binop', r'op-ixor'), + Instruction(r'\I64.\SHL', r'\hex{86}', r'[\I64~\I64] \to [\I64]', r'valid-binop', r'exec-binop', r'op-ishl'), + Instruction(r'\I64.\SHR\K{\_s}', r'\hex{87}', r'[\I64~\I64] \to [\I64]', r'valid-binop', r'exec-binop', r'op-ishr_s'), + Instruction(r'\I64.\SHR\K{\_u}', r'\hex{88}', r'[\I64~\I64] \to [\I64]', r'valid-binop', r'exec-binop', r'op-ishr_u'), + Instruction(r'\I64.\ROTL', r'\hex{89}', r'[\I64~\I64] \to [\I64]', r'valid-binop', r'exec-binop', r'op-irotl'), + Instruction(r'\I64.\ROTR', r'\hex{8A}', r'[\I64~\I64] \to [\I64]', r'valid-binop', r'exec-binop', r'op-irotr'), + Instruction(r'\F32.\ABS', r'\hex{8B}', r'[\F32] \to [\F32]', r'valid-unop', r'exec-unop', r'op-fabs'), + Instruction(r'\F32.\NEG', r'\hex{8C}', r'[\F32] \to [\F32]', r'valid-unop', r'exec-unop', r'op-fneg'), + Instruction(r'\F32.\CEIL', r'\hex{8D}', r'[\F32] \to [\F32]', r'valid-unop', r'exec-unop', r'op-fceil'), + Instruction(r'\F32.\FLOOR', r'\hex{8E}', r'[\F32] \to [\F32]', r'valid-unop', r'exec-unop', r'op-ffloor'), + Instruction(r'\F32.\TRUNC', r'\hex{8F}', r'[\F32] \to [\F32]', r'valid-unop', r'exec-unop', r'op-ftrunc'), + Instruction(r'\F32.\NEAREST', r'\hex{90}', r'[\F32] \to [\F32]', r'valid-unop', r'exec-unop', r'op-fnearest'), + Instruction(r'\F32.\SQRT', r'\hex{91}', r'[\F32] \to [\F32]', r'valid-unop', r'exec-unop', r'op-fsqrt'), + Instruction(r'\F32.\ADD', r'\hex{92}', r'[\F32~\F32] \to [\F32]', r'valid-binop', r'exec-binop', r'op-fadd'), + Instruction(r'\F32.\SUB', r'\hex{93}', r'[\F32~\F32] \to [\F32]', r'valid-binop', r'exec-binop', r'op-fsub'), + Instruction(r'\F32.\MUL', r'\hex{94}', r'[\F32~\F32] \to [\F32]', r'valid-binop', r'exec-binop', r'op-fmul'), + Instruction(r'\F32.\DIV', r'\hex{95}', r'[\F32~\F32] \to [\F32]', r'valid-binop', r'exec-binop', r'op-fdiv'), + Instruction(r'\F32.\FMIN', r'\hex{96}', r'[\F32~\F32] \to [\F32]', r'valid-binop', r'exec-binop', r'op-fmin'), + Instruction(r'\F32.\FMAX', r'\hex{97}', r'[\F32~\F32] \to [\F32]', r'valid-binop', r'exec-binop', r'op-fmax'), + Instruction(r'\F32.\COPYSIGN', r'\hex{98}', r'[\F32~\F32] \to [\F32]', r'valid-binop', r'exec-binop', r'op-fcopysign'), + Instruction(r'\F64.\ABS', r'\hex{99}', r'[\F64] \to [\F64]', r'valid-unop', r'exec-unop', r'op-fabs'), + Instruction(r'\F64.\NEG', r'\hex{9A}', r'[\F64] \to [\F64]', r'valid-unop', r'exec-unop', r'op-fneg'), + Instruction(r'\F64.\CEIL', r'\hex{9B}', r'[\F64] \to [\F64]', r'valid-unop', r'exec-unop', r'op-fceil'), + Instruction(r'\F64.\FLOOR', r'\hex{9C}', r'[\F64] \to [\F64]', r'valid-unop', r'exec-unop', r'op-ffloor'), + Instruction(r'\F64.\TRUNC', r'\hex{9D}', r'[\F64] \to [\F64]', r'valid-unop', r'exec-unop', r'op-ftrunc'), + Instruction(r'\F64.\NEAREST', r'\hex{9E}', r'[\F64] \to [\F64]', r'valid-unop', r'exec-unop', r'op-fnearest'), + Instruction(r'\F64.\SQRT', r'\hex{9F}', r'[\F64] \to [\F64]', r'valid-unop', r'exec-unop', r'op-fsqrt'), + Instruction(r'\F64.\ADD', r'\hex{A0}', r'[\F64~\F64] \to [\F64]', r'valid-binop', r'exec-binop', r'op-fadd'), + Instruction(r'\F64.\SUB', r'\hex{A1}', r'[\F64~\F64] \to [\F64]', r'valid-binop', r'exec-binop', r'op-fsub'), + Instruction(r'\F64.\MUL', r'\hex{A2}', r'[\F64~\F64] \to [\F64]', r'valid-binop', r'exec-binop', r'op-fmul'), + Instruction(r'\F64.\DIV', r'\hex{A3}', r'[\F64~\F64] \to [\F64]', r'valid-binop', r'exec-binop', r'op-fdiv'), + Instruction(r'\F64.\FMIN', r'\hex{A4}', r'[\F64~\F64] \to [\F64]', r'valid-binop', r'exec-binop', r'op-fmin'), + Instruction(r'\F64.\FMAX', r'\hex{A5}', r'[\F64~\F64] \to [\F64]', r'valid-binop', r'exec-binop', r'op-fmax'), + Instruction(r'\F64.\COPYSIGN', r'\hex{A6}', r'[\F64~\F64] \to [\F64]', r'valid-binop', r'exec-binop', r'op-fcopysign'), + Instruction(r'\I32.\WRAP\K{\_}\I64', r'\hex{A7}', r'[\I64] \to [\I32]', r'valid-cvtop', r'exec-cvtop', r'op-wrap'), + Instruction(r'\I32.\TRUNC\K{\_}\F32\K{\_s}', r'\hex{A8}', r'[\F32] \to [\I32]', r'valid-cvtop', r'exec-cvtop', r'op-trunc_s'), + Instruction(r'\I32.\TRUNC\K{\_}\F32\K{\_u}', r'\hex{A9}', r'[\F32] \to [\I32]', r'valid-cvtop', r'exec-cvtop', r'op-trunc_u'), + Instruction(r'\I32.\TRUNC\K{\_}\F64\K{\_s}', r'\hex{AA}', r'[\F64] \to [\I32]', r'valid-cvtop', r'exec-cvtop', r'op-trunc_s'), + Instruction(r'\I32.\TRUNC\K{\_}\F64\K{\_u}', r'\hex{AB}', r'[\F64] \to [\I32]', r'valid-cvtop', r'exec-cvtop', r'op-trunc_u'), + Instruction(r'\I64.\EXTEND\K{\_}\I32\K{\_s}', r'\hex{AC}', r'[\I32] \to [\I64]', r'valid-cvtop', r'exec-cvtop', r'op-extend_s'), + Instruction(r'\I64.\EXTEND\K{\_}\I32\K{\_u}', r'\hex{AD}', r'[\I32] \to [\I64]', r'valid-cvtop', r'exec-cvtop', r'op-extend_u'), + Instruction(r'\I64.\TRUNC\K{\_}\F32\K{\_s}', r'\hex{AE}', r'[\F32] \to [\I64]', r'valid-cvtop', r'exec-cvtop', r'op-trunc_s'), + Instruction(r'\I64.\TRUNC\K{\_}\F32\K{\_u}', r'\hex{AF}', r'[\F32] \to [\I64]', r'valid-cvtop', r'exec-cvtop', r'op-trunc_u'), + Instruction(r'\I64.\TRUNC\K{\_}\F64\K{\_s}', r'\hex{B0}', r'[\F64] \to [\I64]', r'valid-cvtop', r'exec-cvtop', r'op-trunc_s'), + Instruction(r'\I64.\TRUNC\K{\_}\F64\K{\_u}', r'\hex{B1}', r'[\F64] \to [\I64]', r'valid-cvtop', r'exec-cvtop', r'op-trunc_u'), + Instruction(r'\F32.\CONVERT\K{\_}\I32\K{\_s}', r'\hex{B2}', r'[\I32] \to [\F32]', r'valid-cvtop', r'exec-cvtop', r'op-convert_s'), + Instruction(r'\F32.\CONVERT\K{\_}\I32\K{\_u}', r'\hex{B3}', r'[\I32] \to [\F32]', r'valid-cvtop', r'exec-cvtop', r'op-convert_u'), + Instruction(r'\F32.\CONVERT\K{\_}\I64\K{\_s}', r'\hex{B4}', r'[\I64] \to [\F32]', r'valid-cvtop', r'exec-cvtop', r'op-convert_s'), + Instruction(r'\F32.\CONVERT\K{\_}\I64\K{\_u}', r'\hex{B5}', r'[\I64] \to [\F32]', r'valid-cvtop', r'exec-cvtop', r'op-convert_u'), + Instruction(r'\F32.\DEMOTE\K{\_}\F64', r'\hex{B6}', r'[\F64] \to [\F32]', r'valid-cvtop', r'exec-cvtop', r'op-demote'), + Instruction(r'\F64.\CONVERT\K{\_}\I32\K{\_s}', r'\hex{B7}', r'[\I32] \to [\F64]', r'valid-cvtop', r'exec-cvtop', r'op-convert_s'), + Instruction(r'\F64.\CONVERT\K{\_}\I32\K{\_u}', r'\hex{B8}', r'[\I32] \to [\F64]', r'valid-cvtop', r'exec-cvtop', r'op-convert_u'), + Instruction(r'\F64.\CONVERT\K{\_}\I64\K{\_s}', r'\hex{B9}', r'[\I64] \to [\F64]', r'valid-cvtop', r'exec-cvtop', r'op-convert_s'), + Instruction(r'\F64.\CONVERT\K{\_}\I64\K{\_u}', r'\hex{BA}', r'[\I64] \to [\F64]', r'valid-cvtop', r'exec-cvtop', r'op-convert_u'), + Instruction(r'\F64.\PROMOTE\K{\_}\F32', r'\hex{BB}', r'[\F32] \to [\F64]', r'valid-cvtop', r'exec-cvtop', r'op-promote'), + Instruction(r'\I32.\REINTERPRET\K{\_}\F32', r'\hex{BC}', r'[\F32] \to [\I32]', r'valid-cvtop', r'exec-cvtop', r'op-reinterpret'), + Instruction(r'\I64.\REINTERPRET\K{\_}\F64', r'\hex{BD}', r'[\F64] \to [\I64]', r'valid-cvtop', r'exec-cvtop', r'op-reinterpret'), + Instruction(r'\F32.\REINTERPRET\K{\_}\I32', r'\hex{BE}', r'[\I32] \to [\F32]', r'valid-cvtop', r'exec-cvtop', r'op-reinterpret'), + Instruction(r'\F64.\REINTERPRET\K{\_}\I64', r'\hex{BF}', r'[\I64] \to [\F64]', r'valid-cvtop', r'exec-cvtop', r'op-reinterpret'), + Instruction(r'\I32.\EXTEND\K{8\_s}', r'\hex{C0}', r'[\I32] \to [\I32]', r'valid-unop', r'exec-unop', r'op-iextendn_s'), + Instruction(r'\I32.\EXTEND\K{16\_s}', r'\hex{C1}', r'[\I32] \to [\I32]', r'valid-unop', r'exec-unop', r'op-iextendn_s'), + Instruction(r'\I64.\EXTEND\K{8\_s}', r'\hex{C2}', r'[\I64] \to [\I64]', r'valid-unop', r'exec-unop', r'op-iextendn_s'), + Instruction(r'\I64.\EXTEND\K{16\_s}', r'\hex{C3}', r'[\I64] \to [\I64]', r'valid-unop', r'exec-unop', r'op-iextendn_s'), + Instruction(r'\I64.\EXTEND\K{32\_s}', r'\hex{C4}', r'[\I64] \to [\I64]', r'valid-unop', r'exec-unop', r'op-iextendn_s'), + Instruction(None, r'\hex{C5}'), + Instruction(None, r'\hex{C6}'), + Instruction(None, r'\hex{C7}'), + Instruction(None, r'\hex{C8}'), + Instruction(None, r'\hex{C9}'), + Instruction(None, r'\hex{CA}'), + Instruction(None, r'\hex{CB}'), + Instruction(None, r'\hex{CC}'), + Instruction(None, r'\hex{CD}'), + Instruction(None, r'\hex{CE}'), + Instruction(None, r'\hex{CF}'), + Instruction(None, r'\hex{D0}'), + Instruction(None, r'\hex{D1}'), + Instruction(None, r'\hex{D2}'), + Instruction(None, r'\hex{D3}'), + Instruction(None, r'\hex{D4}'), + Instruction(None, r'\hex{D5}'), + Instruction(None, r'\hex{D6}'), + Instruction(None, r'\hex{D7}'), + Instruction(None, r'\hex{D8}'), + Instruction(None, r'\hex{D9}'), + Instruction(None, r'\hex{DA}'), + Instruction(None, r'\hex{DB}'), + Instruction(None, r'\hex{DC}'), + Instruction(None, r'\hex{DD}'), + Instruction(None, r'\hex{DE}'), + Instruction(None, r'\hex{DF}'), + Instruction(None, r'\hex{E0}'), + Instruction(None, r'\hex{E1}'), + Instruction(None, r'\hex{E2}'), + Instruction(None, r'\hex{E3}'), + Instruction(None, r'\hex{E4}'), + Instruction(None, r'\hex{E5}'), + Instruction(None, r'\hex{E6}'), + Instruction(None, r'\hex{E7}'), + Instruction(None, r'\hex{E8}'), + Instruction(None, r'\hex{E9}'), + Instruction(None, r'\hex{EA}'), + Instruction(None, r'\hex{EB}'), + Instruction(None, r'\hex{EC}'), + Instruction(None, r'\hex{ED}'), + Instruction(None, r'\hex{EE}'), + Instruction(None, r'\hex{EF}'), + Instruction(None, r'\hex{F0}'), + Instruction(None, r'\hex{F1}'), + Instruction(None, r'\hex{F2}'), + Instruction(None, r'\hex{F3}'), + Instruction(None, r'\hex{F4}'), + Instruction(None, r'\hex{F5}'), + Instruction(None, r'\hex{F6}'), + Instruction(None, r'\hex{F7}'), + Instruction(None, r'\hex{F8}'), + Instruction(None, r'\hex{F9}'), + Instruction(None, r'\hex{FA}'), + Instruction(None, r'\hex{FB}'), + Instruction(r'\I32.\TRUNC\K{\_sat\_}\F32\K{\_s}', r'\hex{FC}~~0', r'[\F32] \to [\I32]', r'valid-cvtop', r'exec-cvtop', r'op-trunc_sat_s'), + Instruction(r'\I32.\TRUNC\K{\_sat\_}\F32\K{\_u}', r'\hex{FC}~~1', r'[\F32] \to [\I32]', r'valid-cvtop', r'exec-cvtop', r'op-trunc_sat_u'), + Instruction(r'\I32.\TRUNC\K{\_sat\_}\F64\K{\_s}', r'\hex{FC}~~2', r'[\F64] \to [\I32]', r'valid-cvtop', r'exec-cvtop', r'op-trunc_sat_s'), + Instruction(r'\I32.\TRUNC\K{\_sat\_}\F64\K{\_u}', r'\hex{FC}~~3', r'[\F64] \to [\I32]', r'valid-cvtop', r'exec-cvtop', r'op-trunc_sat_u'), + Instruction(r'\I64.\TRUNC\K{\_sat\_}\F32\K{\_s}', r'\hex{FC}~~4', r'[\F32] \to [\I64]', r'valid-cvtop', r'exec-cvtop', r'op-trunc_sat_s'), + Instruction(r'\I64.\TRUNC\K{\_sat\_}\F32\K{\_u}', r'\hex{FC}~~5', r'[\F32] \to [\I64]', r'valid-cvtop', r'exec-cvtop', r'op-trunc_sat_u'), + Instruction(r'\I64.\TRUNC\K{\_sat}\_\F64\K{\_s}', r'\hex{FC}~~6', r'[\F64] \to [\I64]', r'valid-cvtop', r'exec-cvtop', r'op-trunc_sat_s'), + Instruction(r'\I64.\TRUNC\K{\_sat\_}\F64\K{\_u}', r'\hex{FC}~~7', r'[\F64] \to [\I64]', r'valid-cvtop', r'exec-cvtop', r'op-trunc_sat_u'), +] + +def ColumnWidth(n): + return max([len(instr[n]) for instr in INSTRUCTIONS]) + +COLUMN_WIDTHS = [ColumnWidth(i) for i in range(len(COLUMNS))] +DIVIDER = ' '.join('=' * width for width in COLUMN_WIDTHS) + +def Row(columns): + return ' '.join(('{:%d}' % COLUMN_WIDTHS[i]).format(column) + for i, column in enumerate(columns)) + +if __name__ == '__main__': + with open(INDEX_INSTRUCTIONS_RST, 'w') as f: + print(HEADER, file=f) + print(DIVIDER, file=f) + print(Row(COLUMNS), file=f) + print(DIVIDER, file=f) + + for instr in INSTRUCTIONS: + print(Row(instr), file=f) + + print(DIVIDER, file=f) diff --git a/document/core/appendix/index-instructions.rst b/document/core/appendix/index-instructions.rst index 535549484c..cb988b288e 100644 --- a/document/core/appendix/index-instructions.rst +++ b/document/core/appendix/index-instructions.rst @@ -1,222 +1,272 @@ +.. DO NOT EDIT: This file is auto-generated by the gen-index-instructions.py script. + .. index:: instruction .. _index-instr: Index of Instructions --------------------- -========================================= ==================== ============================================= ======================================= =============================================================== -Instruction Binary Opcode Type Validation Execution -========================================= ==================== ============================================= ======================================= =============================================================== -:math:`\UNREACHABLE` :math:`\hex{00}` :math:`[t_1^\ast] \to [t_2^\ast]` :ref:`validation ` :ref:`execution ` -:math:`\NOP` :math:`\hex{01}` :math:`[] \to []` :ref:`validation ` :ref:`execution ` -:math:`\BLOCK~\X{bt}` :math:`\hex{02}` :math:`[t_1^\ast] \to [t_2^\ast]` :ref:`validation ` :ref:`execution ` -:math:`\LOOP~\X{bt}` :math:`\hex{03}` :math:`[t_1^\ast] \to [t_2^\ast]` :ref:`validation ` :ref:`execution ` -:math:`\IF~\X{bt}` :math:`\hex{04}` :math:`[t_1^\ast] \to [t_2^\ast]` :ref:`validation ` :ref:`execution ` -:math:`\ELSE` :math:`\hex{05}` -(reserved) :math:`\hex{06}` -(reserved) :math:`\hex{07}` -(reserved) :math:`\hex{08}` -(reserved) :math:`\hex{09}` -(reserved) :math:`\hex{0A}` -:math:`\END` :math:`\hex{0B}` -:math:`\BR~l` :math:`\hex{0C}` :math:`[t_1^\ast~t^\ast] \to [t_2^\ast]` :ref:`validation ` :ref:`execution ` -:math:`\BRIF~l` :math:`\hex{0D}` :math:`[t^\ast~\I32] \to [t^\ast]` :ref:`validation ` :ref:`execution ` -:math:`\BRTABLE~l^\ast~l` :math:`\hex{0E}` :math:`[t_1^\ast~t^\ast~\I32] \to [t_2^\ast]` :ref:`validation ` :ref:`execution ` -:math:`\RETURN` :math:`\hex{0F}` :math:`[t_1^\ast~t^\ast] \to [t_2^\ast]` :ref:`validation ` :ref:`execution ` -:math:`\CALL~x` :math:`\hex{10}` :math:`[t_1^\ast] \to [t_2^\ast]` :ref:`validation ` :ref:`execution ` -:math:`\CALLINDIRECT~x` :math:`\hex{11}` :math:`[t_1^\ast~\I32] \to [t_2^\ast]` :ref:`validation ` :ref:`execution ` -(reserved) :math:`\hex{12}` -(reserved) :math:`\hex{13}` -(reserved) :math:`\hex{14}` -(reserved) :math:`\hex{15}` -(reserved) :math:`\hex{16}` -(reserved) :math:`\hex{17}` -(reserved) :math:`\hex{18}` -(reserved) :math:`\hex{19}` -:math:`\DROP` :math:`\hex{1A}` :math:`[t] \to []` :ref:`validation ` :ref:`execution ` -:math:`\SELECT` :math:`\hex{1B}` :math:`[t~t~\I32] \to [t]` :ref:`validation ` :ref:`execution ` -(reserved) :math:`\hex{1C}` -(reserved) :math:`\hex{1D}` -(reserved) :math:`\hex{1E}` -(reserved) :math:`\hex{1F}` -:math:`\LOCALGET~x` :math:`\hex{20}` :math:`[] \to [t]` :ref:`validation ` :ref:`execution ` -:math:`\LOCALSET~x` :math:`\hex{21}` :math:`[t] \to []` :ref:`validation ` :ref:`execution ` -:math:`\LOCALTEE~x` :math:`\hex{22}` :math:`[t] \to [t]` :ref:`validation ` :ref:`execution ` -:math:`\GLOBALGET~x` :math:`\hex{23}` :math:`[] \to [t]` :ref:`validation ` :ref:`execution ` -:math:`\GLOBALSET~x` :math:`\hex{24}` :math:`[t] \to []` :ref:`validation ` :ref:`execution ` -(reserved) :math:`\hex{25}` -(reserved) :math:`\hex{26}` -(reserved) :math:`\hex{27}` -:math:`\I32.\LOAD~\memarg` :math:`\hex{28}` :math:`[\I32] \to [\I32]` :ref:`validation ` :ref:`execution ` -:math:`\I64.\LOAD~\memarg` :math:`\hex{29}` :math:`[\I32] \to [\I64]` :ref:`validation ` :ref:`execution ` -:math:`\F32.\LOAD~\memarg` :math:`\hex{2A}` :math:`[\I32] \to [\F32]` :ref:`validation ` :ref:`execution ` -:math:`\F64.\LOAD~\memarg` :math:`\hex{2B}` :math:`[\I32] \to [\F64]` :ref:`validation ` :ref:`execution ` -:math:`\I32.\LOAD\K{8\_s}~\memarg` :math:`\hex{2C}` :math:`[\I32] \to [\I32]` :ref:`validation ` :ref:`execution ` -:math:`\I32.\LOAD\K{8\_u}~\memarg` :math:`\hex{2D}` :math:`[\I32] \to [\I32]` :ref:`validation ` :ref:`execution ` -:math:`\I32.\LOAD\K{16\_s}~\memarg` :math:`\hex{2E}` :math:`[\I32] \to [\I32]` :ref:`validation ` :ref:`execution ` -:math:`\I32.\LOAD\K{16\_u}~\memarg` :math:`\hex{2F}` :math:`[\I32] \to [\I32]` :ref:`validation ` :ref:`execution ` -:math:`\I64.\LOAD\K{8\_s}~\memarg` :math:`\hex{30}` :math:`[\I32] \to [\I64]` :ref:`validation ` :ref:`execution ` -:math:`\I64.\LOAD\K{8\_u}~\memarg` :math:`\hex{31}` :math:`[\I32] \to [\I64]` :ref:`validation ` :ref:`execution ` -:math:`\I64.\LOAD\K{16\_s}~\memarg` :math:`\hex{32}` :math:`[\I32] \to [\I64]` :ref:`validation ` :ref:`execution ` -:math:`\I64.\LOAD\K{16\_u}~\memarg` :math:`\hex{33}` :math:`[\I32] \to [\I64]` :ref:`validation ` :ref:`execution ` -:math:`\I64.\LOAD\K{32\_s}~\memarg` :math:`\hex{34}` :math:`[\I32] \to [\I64]` :ref:`validation ` :ref:`execution ` -:math:`\I64.\LOAD\K{32\_u}~\memarg` :math:`\hex{35}` :math:`[\I32] \to [\I64]` :ref:`validation ` :ref:`execution ` -:math:`\I32.\STORE~\memarg` :math:`\hex{36}` :math:`[\I32~\I32] \to []` :ref:`validation ` :ref:`execution ` -:math:`\I64.\STORE~\memarg` :math:`\hex{37}` :math:`[\I32~\I64] \to []` :ref:`validation ` :ref:`execution ` -:math:`\F32.\STORE~\memarg` :math:`\hex{38}` :math:`[\I32~\F32] \to []` :ref:`validation ` :ref:`execution ` -:math:`\F64.\STORE~\memarg` :math:`\hex{39}` :math:`[\I32~\F64] \to []` :ref:`validation ` :ref:`execution ` -:math:`\I32.\STORE\K{8}~\memarg` :math:`\hex{3A}` :math:`[\I32~\I32] \to []` :ref:`validation ` :ref:`execution ` -:math:`\I32.\STORE\K{16}~\memarg` :math:`\hex{3B}` :math:`[\I32~\I32] \to []` :ref:`validation ` :ref:`execution ` -:math:`\I64.\STORE\K{8}~\memarg` :math:`\hex{3C}` :math:`[\I32~\I64] \to []` :ref:`validation ` :ref:`execution ` -:math:`\I64.\STORE\K{16}~\memarg` :math:`\hex{3D}` :math:`[\I32~\I64] \to []` :ref:`validation ` :ref:`execution ` -:math:`\I64.\STORE\K{32}~\memarg` :math:`\hex{3E}` :math:`[\I32~\I64] \to []` :ref:`validation ` :ref:`execution ` -:math:`\MEMORYSIZE` :math:`\hex{3F}` :math:`[] \to [\I32]` :ref:`validation ` :ref:`execution ` -:math:`\MEMORYGROW` :math:`\hex{40}` :math:`[\I32] \to [\I32]` :ref:`validation ` :ref:`execution ` -:math:`\I32.\CONST~\i32` :math:`\hex{41}` :math:`[] \to [\I32]` :ref:`validation ` :ref:`execution ` -:math:`\I64.\CONST~\i64` :math:`\hex{42}` :math:`[] \to [\I64]` :ref:`validation ` :ref:`execution ` -:math:`\F32.\CONST~\f32` :math:`\hex{43}` :math:`[] \to [\F32]` :ref:`validation ` :ref:`execution ` -:math:`\F64.\CONST~\f64` :math:`\hex{44}` :math:`[] \to [\F64]` :ref:`validation ` :ref:`execution ` -:math:`\I32.\EQZ` :math:`\hex{45}` :math:`[\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I32.\EQ` :math:`\hex{46}` :math:`[\I32~\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I32.\NE` :math:`\hex{47}` :math:`[\I32~\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I32.\LT\K{\_s}` :math:`\hex{48}` :math:`[\I32~\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I32.\LT\K{\_u}` :math:`\hex{49}` :math:`[\I32~\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I32.\GT\K{\_s}` :math:`\hex{4A}` :math:`[\I32~\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I32.\GT\K{\_u}` :math:`\hex{4B}` :math:`[\I32~\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I32.\LE\K{\_s}` :math:`\hex{4C}` :math:`[\I32~\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I32.\LE\K{\_u}` :math:`\hex{4D}` :math:`[\I32~\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I32.\GE\K{\_s}` :math:`\hex{4E}` :math:`[\I32~\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I32.\GE\K{\_u}` :math:`\hex{4F}` :math:`[\I32~\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I64.\EQZ` :math:`\hex{50}` :math:`[\I64] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I64.\EQ` :math:`\hex{51}` :math:`[\I64~\I64] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I64.\NE` :math:`\hex{52}` :math:`[\I64~\I64] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I64.\LT\K{\_s}` :math:`\hex{53}` :math:`[\I64~\I64] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I64.\LT\K{\_u}` :math:`\hex{54}` :math:`[\I64~\I64] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I64.\GT\K{\_s}` :math:`\hex{55}` :math:`[\I64~\I64] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I64.\GT\K{\_u}` :math:`\hex{56}` :math:`[\I64~\I64] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I64.\LE\K{\_s}` :math:`\hex{57}` :math:`[\I64~\I64] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I64.\LE\K{\_u}` :math:`\hex{58}` :math:`[\I64~\I64] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I64.\GE\K{\_s}` :math:`\hex{59}` :math:`[\I64~\I64] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I64.\GE\K{\_u}` :math:`\hex{5A}` :math:`[\I64~\I64] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F32.\EQ` :math:`\hex{5B}` :math:`[\F32~\F32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F32.\NE` :math:`\hex{5C}` :math:`[\F32~\F32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F32.\LT` :math:`\hex{5D}` :math:`[\F32~\F32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F32.\GT` :math:`\hex{5E}` :math:`[\F32~\F32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F32.\LE` :math:`\hex{5F}` :math:`[\F32~\F32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F32.\GE` :math:`\hex{60}` :math:`[\F32~\F32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F64.\EQ` :math:`\hex{61}` :math:`[\F64~\F64] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F64.\NE` :math:`\hex{62}` :math:`[\F64~\F64] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F64.\LT` :math:`\hex{63}` :math:`[\F64~\F64] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F64.\GT` :math:`\hex{64}` :math:`[\F64~\F64] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F64.\LE` :math:`\hex{65}` :math:`[\F64~\F64] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F64.\GE` :math:`\hex{66}` :math:`[\F64~\F64] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I32.\CLZ` :math:`\hex{67}` :math:`[\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I32.\CTZ` :math:`\hex{68}` :math:`[\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I32.\POPCNT` :math:`\hex{69}` :math:`[\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I32.\ADD` :math:`\hex{6A}` :math:`[\I32~\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I32.\SUB` :math:`\hex{6B}` :math:`[\I32~\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I32.\MUL` :math:`\hex{6C}` :math:`[\I32~\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I32.\DIV\K{\_s}` :math:`\hex{6D}` :math:`[\I32~\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I32.\DIV\K{\_u}` :math:`\hex{6E}` :math:`[\I32~\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I32.\REM\K{\_s}` :math:`\hex{6F}` :math:`[\I32~\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I32.\REM\K{\_u}` :math:`\hex{70}` :math:`[\I32~\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I32.\AND` :math:`\hex{71}` :math:`[\I32~\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I32.\OR` :math:`\hex{72}` :math:`[\I32~\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I32.\XOR` :math:`\hex{73}` :math:`[\I32~\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I32.\SHL` :math:`\hex{74}` :math:`[\I32~\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I32.\SHR\K{\_s}` :math:`\hex{75}` :math:`[\I32~\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I32.\SHR\K{\_u}` :math:`\hex{76}` :math:`[\I32~\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I32.\ROTL` :math:`\hex{77}` :math:`[\I32~\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I32.\ROTR` :math:`\hex{78}` :math:`[\I32~\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I64.\CLZ` :math:`\hex{79}` :math:`[\I64] \to [\I64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I64.\CTZ` :math:`\hex{7A}` :math:`[\I64] \to [\I64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I64.\POPCNT` :math:`\hex{7B}` :math:`[\I64] \to [\I64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I64.\ADD` :math:`\hex{7C}` :math:`[\I64~\I64] \to [\I64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I64.\SUB` :math:`\hex{7D}` :math:`[\I64~\I64] \to [\I64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I64.\MUL` :math:`\hex{7E}` :math:`[\I64~\I64] \to [\I64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I64.\DIV\K{\_s}` :math:`\hex{7F}` :math:`[\I64~\I64] \to [\I64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I64.\DIV\K{\_u}` :math:`\hex{80}` :math:`[\I64~\I64] \to [\I64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I64.\REM\K{\_s}` :math:`\hex{81}` :math:`[\I64~\I64] \to [\I64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I64.\REM\K{\_u}` :math:`\hex{82}` :math:`[\I64~\I64] \to [\I64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I64.\AND` :math:`\hex{83}` :math:`[\I64~\I64] \to [\I64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I64.\OR` :math:`\hex{84}` :math:`[\I64~\I64] \to [\I64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I64.\XOR` :math:`\hex{85}` :math:`[\I64~\I64] \to [\I64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I64.\SHL` :math:`\hex{86}` :math:`[\I64~\I64] \to [\I64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I64.\SHR\K{\_s}` :math:`\hex{87}` :math:`[\I64~\I64] \to [\I64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I64.\SHR\K{\_u}` :math:`\hex{88}` :math:`[\I64~\I64] \to [\I64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I64.\ROTL` :math:`\hex{89}` :math:`[\I64~\I64] \to [\I64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I64.\ROTR` :math:`\hex{8A}` :math:`[\I64~\I64] \to [\I64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F32.\ABS` :math:`\hex{8B}` :math:`[\F32] \to [\F32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F32.\NEG` :math:`\hex{8C}` :math:`[\F32] \to [\F32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F32.\CEIL` :math:`\hex{8D}` :math:`[\F32] \to [\F32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F32.\FLOOR` :math:`\hex{8E}` :math:`[\F32] \to [\F32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F32.\TRUNC` :math:`\hex{8F}` :math:`[\F32] \to [\F32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F32.\NEAREST` :math:`\hex{90}` :math:`[\F32] \to [\F32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F32.\SQRT` :math:`\hex{91}` :math:`[\F32] \to [\F32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F32.\ADD` :math:`\hex{92}` :math:`[\F32~\F32] \to [\F32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F32.\SUB` :math:`\hex{93}` :math:`[\F32~\F32] \to [\F32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F32.\MUL` :math:`\hex{94}` :math:`[\F32~\F32] \to [\F32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F32.\DIV` :math:`\hex{95}` :math:`[\F32~\F32] \to [\F32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F32.\FMIN` :math:`\hex{96}` :math:`[\F32~\F32] \to [\F32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F32.\FMAX` :math:`\hex{97}` :math:`[\F32~\F32] \to [\F32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F32.\COPYSIGN` :math:`\hex{98}` :math:`[\F32~\F32] \to [\F32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F64.\ABS` :math:`\hex{99}` :math:`[\F64] \to [\F64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F64.\NEG` :math:`\hex{9A}` :math:`[\F64] \to [\F64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F64.\CEIL` :math:`\hex{9B}` :math:`[\F64] \to [\F64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F64.\FLOOR` :math:`\hex{9C}` :math:`[\F64] \to [\F64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F64.\TRUNC` :math:`\hex{9D}` :math:`[\F64] \to [\F64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F64.\NEAREST` :math:`\hex{9E}` :math:`[\F64] \to [\F64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F64.\SQRT` :math:`\hex{9F}` :math:`[\F64] \to [\F64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F64.\ADD` :math:`\hex{A0}` :math:`[\F64~\F64] \to [\F64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F64.\SUB` :math:`\hex{A1}` :math:`[\F64~\F64] \to [\F64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F64.\MUL` :math:`\hex{A2}` :math:`[\F64~\F64] \to [\F64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F64.\DIV` :math:`\hex{A3}` :math:`[\F64~\F64] \to [\F64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F64.\FMIN` :math:`\hex{A4}` :math:`[\F64~\F64] \to [\F64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F64.\FMAX` :math:`\hex{A5}` :math:`[\F64~\F64] \to [\F64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F64.\COPYSIGN` :math:`\hex{A6}` :math:`[\F64~\F64] \to [\F64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I32.\WRAP\K{\_}\I64` :math:`\hex{A7}` :math:`[\I64] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I32.\TRUNC\K{\_}\F32\K{\_s}` :math:`\hex{A8}` :math:`[\F32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I32.\TRUNC\K{\_}\F32\K{\_u}` :math:`\hex{A9}` :math:`[\F32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I32.\TRUNC\K{\_}\F64\K{\_s}` :math:`\hex{AA}` :math:`[\F64] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I32.\TRUNC\K{\_}\F64\K{\_u}` :math:`\hex{AB}` :math:`[\F64] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I64.\EXTEND\K{\_}\I32\K{\_s}` :math:`\hex{AC}` :math:`[\I32] \to [\I64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I64.\EXTEND\K{\_}\I32\K{\_u}` :math:`\hex{AD}` :math:`[\I32] \to [\I64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I64.\TRUNC\K{\_}\F32\K{\_s}` :math:`\hex{AE}` :math:`[\F32] \to [\I64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I64.\TRUNC\K{\_}\F32\K{\_u}` :math:`\hex{AF}` :math:`[\F32] \to [\I64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I64.\TRUNC\K{\_}\F64\K{\_s}` :math:`\hex{B0}` :math:`[\F64] \to [\I64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I64.\TRUNC\K{\_}\F64\K{\_u}` :math:`\hex{B1}` :math:`[\F64] \to [\I64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F32.\CONVERT\K{\_}\I32\K{\_s}` :math:`\hex{B2}` :math:`[\I32] \to [\F32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F32.\CONVERT\K{\_}\I32\K{\_u}` :math:`\hex{B3}` :math:`[\I32] \to [\F32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F32.\CONVERT\K{\_}\I64\K{\_s}` :math:`\hex{B4}` :math:`[\I64] \to [\F32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F32.\CONVERT\K{\_}\I64\K{\_u}` :math:`\hex{B5}` :math:`[\I64] \to [\F32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F32.\DEMOTE\K{\_}\F64` :math:`\hex{B6}` :math:`[\F64] \to [\F32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F64.\CONVERT\K{\_}\I32\K{\_s}` :math:`\hex{B7}` :math:`[\I32] \to [\F64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F64.\CONVERT\K{\_}\I32\K{\_u}` :math:`\hex{B8}` :math:`[\I32] \to [\F64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F64.\CONVERT\K{\_}\I64\K{\_s}` :math:`\hex{B9}` :math:`[\I64] \to [\F64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F64.\CONVERT\K{\_}\I64\K{\_u}` :math:`\hex{BA}` :math:`[\I64] \to [\F64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F64.\PROMOTE\K{\_}\F32` :math:`\hex{BB}` :math:`[\F32] \to [\F64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I32.\REINTERPRET\K{\_}\F32` :math:`\hex{BC}` :math:`[\F32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I64.\REINTERPRET\K{\_}\F64` :math:`\hex{BD}` :math:`[\F64] \to [\I64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F32.\REINTERPRET\K{\_}\I32` :math:`\hex{BE}` :math:`[\I32] \to [\F32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\F64.\REINTERPRET\K{\_}\I64` :math:`\hex{BF}` :math:`[\I64] \to [\F64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I32.\EXTEND\K{8\_s}` :math:`\hex{C0}` :math:`[\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I32.\EXTEND\K{16\_s}` :math:`\hex{C1}` :math:`[\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I64.\EXTEND\K{8\_s}` :math:`\hex{C2}` :math:`[\I64] \to [\I64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I64.\EXTEND\K{16\_s}` :math:`\hex{C3}` :math:`[\I64] \to [\I64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I64.\EXTEND\K{32\_s}` :math:`\hex{C4}` :math:`[\I64] \to [\I64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I32.\TRUNC\K{\_sat\_}\F32\K{\_s}` :math:`\hex{FC}~~0` :math:`[\F32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I32.\TRUNC\K{\_sat\_}\F32\K{\_u}` :math:`\hex{FC}~~1` :math:`[\F32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I32.\TRUNC\K{\_sat\_}\F64\K{\_s}` :math:`\hex{FC}~~2` :math:`[\F64] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I32.\TRUNC\K{\_sat\_}\F64\K{\_u}` :math:`\hex{FC}~~3` :math:`[\F64] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I64.\TRUNC\K{\_sat\_}\F32\K{\_s}` :math:`\hex{FC}~~4` :math:`[\F32] \to [\I64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I64.\TRUNC\K{\_sat\_}\F32\K{\_u}` :math:`\hex{FC}~~5` :math:`[\F32] \to [\I64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I64.\TRUNC\K{\_sat}\_\F64\K{\_s}` :math:`\hex{FC}~~6` :math:`[\F64] \to [\I64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\I64.\TRUNC\K{\_sat\_}\F64\K{\_u}` :math:`\hex{FC}~~7` :math:`[\F64] \to [\I64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` -:math:`\MEMORYINIT` :math:`\hex{FC}~~8` :math:`[\I32~\I32~\I32] \to []` :ref:`validation ` :ref:`execution ` -:math:`\DATADROP` :math:`\hex{FC}~~9` :math:`[] \to []` :ref:`validation ` :ref:`execution ` -:math:`\MEMORYCOPY` :math:`\hex{FC}~~10` :math:`[\I32~\I32~\I32] \to []` :ref:`validation ` :ref:`execution ` -:math:`\MEMORYFILL` :math:`\hex{FC}~~11` :math:`[\I32~\I32~\I32] \to []` :ref:`validation ` :ref:`execution ` -:math:`\TABLEINIT` :math:`\hex{FC}~~12` :math:`[\I32~\I32~\I32] \to []` :ref:`validation ` :ref:`execution ` -:math:`\ELEMDROP` :math:`\hex{FC}~~13` :math:`[] \to []` :ref:`validation ` :ref:`execution ` -:math:`\TABLECOPY` :math:`\hex{FC}~~14` :math:`[\I32~\I32~\I32] \to []` :ref:`validation ` :ref:`execution ` -========================================= ==================== ============================================= ======================================= =============================================================== +========================================= =================== ============================================= ======================================= =============================================================== +Instruction Binary Opcode Type Validation Execution +========================================= =================== ============================================= ======================================= =============================================================== +:math:`\UNREACHABLE` :math:`\hex{00}` :math:`[t_1^\ast] \to [t_2^\ast]` :ref:`validation ` :ref:`execution ` +:math:`\NOP` :math:`\hex{01}` :math:`[] \to []` :ref:`validation ` :ref:`execution ` +:math:`\BLOCK~\X{bt}` :math:`\hex{02}` :math:`[t_1^\ast] \to [t_2^\ast]` :ref:`validation ` :ref:`execution ` +:math:`\LOOP~\X{bt}` :math:`\hex{03}` :math:`[t_1^\ast] \to [t_2^\ast]` :ref:`validation ` :ref:`execution ` +:math:`\IF~\X{bt}` :math:`\hex{04}` :math:`[t_1^\ast] \to [t_2^\ast]` :ref:`validation ` :ref:`execution ` +:math:`\ELSE` :math:`\hex{05}` +(reserved) :math:`\hex{06}` +(reserved) :math:`\hex{07}` +(reserved) :math:`\hex{08}` +(reserved) :math:`\hex{09}` +(reserved) :math:`\hex{0A}` +:math:`\END` :math:`\hex{0B}` +:math:`\BR~l` :math:`\hex{0C}` :math:`[t_1^\ast~t^\ast] \to [t_2^\ast]` :ref:`validation ` :ref:`execution ` +:math:`\BRIF~l` :math:`\hex{0D}` :math:`[t^\ast~\I32] \to [t^\ast]` :ref:`validation ` :ref:`execution ` +:math:`\BRTABLE~l^\ast~l` :math:`\hex{0E}` :math:`[t_1^\ast~t^\ast~\I32] \to [t_2^\ast]` :ref:`validation ` :ref:`execution ` +:math:`\RETURN` :math:`\hex{0F}` :math:`[t_1^\ast~t^\ast] \to [t_2^\ast]` :ref:`validation ` :ref:`execution ` +:math:`\CALL~x` :math:`\hex{10}` :math:`[t_1^\ast] \to [t_2^\ast]` :ref:`validation ` :ref:`execution ` +:math:`\CALLINDIRECT~x` :math:`\hex{11}` :math:`[t_1^\ast~\I32] \to [t_2^\ast]` :ref:`validation ` :ref:`execution ` +(reserved) :math:`\hex{12}` +(reserved) :math:`\hex{13}` +(reserved) :math:`\hex{14}` +(reserved) :math:`\hex{15}` +(reserved) :math:`\hex{16}` +(reserved) :math:`\hex{17}` +(reserved) :math:`\hex{18}` +(reserved) :math:`\hex{19}` +:math:`\DROP` :math:`\hex{1A}` :math:`[t] \to []` :ref:`validation ` :ref:`execution ` +:math:`\SELECT` :math:`\hex{1B}` :math:`[t~t~\I32] \to [t]` :ref:`validation ` :ref:`execution ` +(reserved) :math:`\hex{1C}` +(reserved) :math:`\hex{1D}` +(reserved) :math:`\hex{1E}` +(reserved) :math:`\hex{1F}` +:math:`\LOCALGET~x` :math:`\hex{20}` :math:`[] \to [t]` :ref:`validation ` :ref:`execution ` +:math:`\LOCALSET~x` :math:`\hex{21}` :math:`[t] \to []` :ref:`validation ` :ref:`execution ` +:math:`\LOCALTEE~x` :math:`\hex{22}` :math:`[t] \to [t]` :ref:`validation ` :ref:`execution ` +:math:`\GLOBALGET~x` :math:`\hex{23}` :math:`[] \to [t]` :ref:`validation ` :ref:`execution ` +:math:`\GLOBALSET~x` :math:`\hex{24}` :math:`[t] \to []` :ref:`validation ` :ref:`execution ` +(reserved) :math:`\hex{25}` +(reserved) :math:`\hex{26}` +(reserved) :math:`\hex{27}` +:math:`\I32.\LOAD~\memarg` :math:`\hex{28}` :math:`[\I32] \to [\I32]` :ref:`validation ` :ref:`execution ` +:math:`\I64.\LOAD~\memarg` :math:`\hex{29}` :math:`[\I32] \to [\I64]` :ref:`validation ` :ref:`execution ` +:math:`\F32.\LOAD~\memarg` :math:`\hex{2A}` :math:`[\I32] \to [\F32]` :ref:`validation ` :ref:`execution ` +:math:`\F64.\LOAD~\memarg` :math:`\hex{2B}` :math:`[\I32] \to [\F64]` :ref:`validation ` :ref:`execution ` +:math:`\I32.\LOAD\K{8\_s}~\memarg` :math:`\hex{2C}` :math:`[\I32] \to [\I32]` :ref:`validation ` :ref:`execution ` +:math:`\I32.\LOAD\K{8\_u}~\memarg` :math:`\hex{2D}` :math:`[\I32] \to [\I32]` :ref:`validation ` :ref:`execution ` +:math:`\I32.\LOAD\K{16\_s}~\memarg` :math:`\hex{2E}` :math:`[\I32] \to [\I32]` :ref:`validation ` :ref:`execution ` +:math:`\I32.\LOAD\K{16\_u}~\memarg` :math:`\hex{2F}` :math:`[\I32] \to [\I32]` :ref:`validation ` :ref:`execution ` +:math:`\I64.\LOAD\K{8\_s}~\memarg` :math:`\hex{30}` :math:`[\I32] \to [\I64]` :ref:`validation ` :ref:`execution ` +:math:`\I64.\LOAD\K{8\_u}~\memarg` :math:`\hex{31}` :math:`[\I32] \to [\I64]` :ref:`validation ` :ref:`execution ` +:math:`\I64.\LOAD\K{16\_s}~\memarg` :math:`\hex{32}` :math:`[\I32] \to [\I64]` :ref:`validation ` :ref:`execution ` +:math:`\I64.\LOAD\K{16\_u}~\memarg` :math:`\hex{33}` :math:`[\I32] \to [\I64]` :ref:`validation ` :ref:`execution ` +:math:`\I64.\LOAD\K{32\_s}~\memarg` :math:`\hex{34}` :math:`[\I32] \to [\I64]` :ref:`validation ` :ref:`execution ` +:math:`\I64.\LOAD\K{32\_u}~\memarg` :math:`\hex{35}` :math:`[\I32] \to [\I64]` :ref:`validation ` :ref:`execution ` +:math:`\I32.\STORE~\memarg` :math:`\hex{36}` :math:`[\I32~\I32] \to []` :ref:`validation ` :ref:`execution ` +:math:`\I64.\STORE~\memarg` :math:`\hex{37}` :math:`[\I32~\I64] \to []` :ref:`validation ` :ref:`execution ` +:math:`\F32.\STORE~\memarg` :math:`\hex{38}` :math:`[\I32~\F32] \to []` :ref:`validation ` :ref:`execution ` +:math:`\F64.\STORE~\memarg` :math:`\hex{39}` :math:`[\I32~\F64] \to []` :ref:`validation ` :ref:`execution ` +:math:`\I32.\STORE\K{8}~\memarg` :math:`\hex{3A}` :math:`[\I32~\I32] \to []` :ref:`validation ` :ref:`execution ` +:math:`\I32.\STORE\K{16}~\memarg` :math:`\hex{3B}` :math:`[\I32~\I32] \to []` :ref:`validation ` :ref:`execution ` +:math:`\I64.\STORE\K{8}~\memarg` :math:`\hex{3C}` :math:`[\I32~\I64] \to []` :ref:`validation ` :ref:`execution ` +:math:`\I64.\STORE\K{16}~\memarg` :math:`\hex{3D}` :math:`[\I32~\I64] \to []` :ref:`validation ` :ref:`execution ` +:math:`\I64.\STORE\K{32}~\memarg` :math:`\hex{3E}` :math:`[\I32~\I64] \to []` :ref:`validation ` :ref:`execution ` +:math:`\MEMORYSIZE` :math:`\hex{3F}` :math:`[] \to [\I32]` :ref:`validation ` :ref:`execution ` +:math:`\MEMORYGROW` :math:`\hex{40}` :math:`[\I32] \to [\I32]` :ref:`validation ` :ref:`execution ` +:math:`\I32.\CONST~\i32` :math:`\hex{41}` :math:`[] \to [\I32]` :ref:`validation ` :ref:`execution ` +:math:`\I64.\CONST~\i64` :math:`\hex{42}` :math:`[] \to [\I64]` :ref:`validation ` :ref:`execution ` +:math:`\F32.\CONST~\f32` :math:`\hex{43}` :math:`[] \to [\F32]` :ref:`validation ` :ref:`execution ` +:math:`\F64.\CONST~\f64` :math:`\hex{44}` :math:`[] \to [\F64]` :ref:`validation ` :ref:`execution ` +:math:`\I32.\EQZ` :math:`\hex{45}` :math:`[\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I32.\EQ` :math:`\hex{46}` :math:`[\I32~\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I32.\NE` :math:`\hex{47}` :math:`[\I32~\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I32.\LT\K{\_s}` :math:`\hex{48}` :math:`[\I32~\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I32.\LT\K{\_u}` :math:`\hex{49}` :math:`[\I32~\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I32.\GT\K{\_s}` :math:`\hex{4A}` :math:`[\I32~\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I32.\GT\K{\_u}` :math:`\hex{4B}` :math:`[\I32~\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I32.\LE\K{\_s}` :math:`\hex{4C}` :math:`[\I32~\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I32.\LE\K{\_u}` :math:`\hex{4D}` :math:`[\I32~\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I32.\GE\K{\_s}` :math:`\hex{4E}` :math:`[\I32~\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I32.\GE\K{\_u}` :math:`\hex{4F}` :math:`[\I32~\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I64.\EQZ` :math:`\hex{50}` :math:`[\I64] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I64.\EQ` :math:`\hex{51}` :math:`[\I64~\I64] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I64.\NE` :math:`\hex{52}` :math:`[\I64~\I64] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I64.\LT\K{\_s}` :math:`\hex{53}` :math:`[\I64~\I64] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I64.\LT\K{\_u}` :math:`\hex{54}` :math:`[\I64~\I64] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I64.\GT\K{\_s}` :math:`\hex{55}` :math:`[\I64~\I64] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I64.\GT\K{\_u}` :math:`\hex{56}` :math:`[\I64~\I64] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I64.\LE\K{\_s}` :math:`\hex{57}` :math:`[\I64~\I64] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I64.\LE\K{\_u}` :math:`\hex{58}` :math:`[\I64~\I64] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I64.\GE\K{\_s}` :math:`\hex{59}` :math:`[\I64~\I64] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I64.\GE\K{\_u}` :math:`\hex{5A}` :math:`[\I64~\I64] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\F32.\EQ` :math:`\hex{5B}` :math:`[\F32~\F32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\F32.\NE` :math:`\hex{5C}` :math:`[\F32~\F32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\F32.\LT` :math:`\hex{5D}` :math:`[\F32~\F32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\F32.\GT` :math:`\hex{5E}` :math:`[\F32~\F32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\F32.\LE` :math:`\hex{5F}` :math:`[\F32~\F32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\F32.\GE` :math:`\hex{60}` :math:`[\F32~\F32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\F64.\EQ` :math:`\hex{61}` :math:`[\F64~\F64] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\F64.\NE` :math:`\hex{62}` :math:`[\F64~\F64] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\F64.\LT` :math:`\hex{63}` :math:`[\F64~\F64] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\F64.\GT` :math:`\hex{64}` :math:`[\F64~\F64] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\F64.\LE` :math:`\hex{65}` :math:`[\F64~\F64] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\F64.\GE` :math:`\hex{66}` :math:`[\F64~\F64] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I32.\CLZ` :math:`\hex{67}` :math:`[\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I32.\CTZ` :math:`\hex{68}` :math:`[\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I32.\POPCNT` :math:`\hex{69}` :math:`[\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I32.\ADD` :math:`\hex{6A}` :math:`[\I32~\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I32.\SUB` :math:`\hex{6B}` :math:`[\I32~\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I32.\MUL` :math:`\hex{6C}` :math:`[\I32~\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I32.\DIV\K{\_s}` :math:`\hex{6D}` :math:`[\I32~\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I32.\DIV\K{\_u}` :math:`\hex{6E}` :math:`[\I32~\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I32.\REM\K{\_s}` :math:`\hex{6F}` :math:`[\I32~\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I32.\REM\K{\_u}` :math:`\hex{70}` :math:`[\I32~\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I32.\AND` :math:`\hex{71}` :math:`[\I32~\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I32.\OR` :math:`\hex{72}` :math:`[\I32~\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I32.\XOR` :math:`\hex{73}` :math:`[\I32~\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I32.\SHL` :math:`\hex{74}` :math:`[\I32~\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I32.\SHR\K{\_s}` :math:`\hex{75}` :math:`[\I32~\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I32.\SHR\K{\_u}` :math:`\hex{76}` :math:`[\I32~\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I32.\ROTL` :math:`\hex{77}` :math:`[\I32~\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I32.\ROTR` :math:`\hex{78}` :math:`[\I32~\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I64.\CLZ` :math:`\hex{79}` :math:`[\I64] \to [\I64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I64.\CTZ` :math:`\hex{7A}` :math:`[\I64] \to [\I64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I64.\POPCNT` :math:`\hex{7B}` :math:`[\I64] \to [\I64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I64.\ADD` :math:`\hex{7C}` :math:`[\I64~\I64] \to [\I64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I64.\SUB` :math:`\hex{7D}` :math:`[\I64~\I64] \to [\I64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I64.\MUL` :math:`\hex{7E}` :math:`[\I64~\I64] \to [\I64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I64.\DIV\K{\_s}` :math:`\hex{7F}` :math:`[\I64~\I64] \to [\I64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I64.\DIV\K{\_u}` :math:`\hex{80}` :math:`[\I64~\I64] \to [\I64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I64.\REM\K{\_s}` :math:`\hex{81}` :math:`[\I64~\I64] \to [\I64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I64.\REM\K{\_u}` :math:`\hex{82}` :math:`[\I64~\I64] \to [\I64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I64.\AND` :math:`\hex{83}` :math:`[\I64~\I64] \to [\I64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I64.\OR` :math:`\hex{84}` :math:`[\I64~\I64] \to [\I64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I64.\XOR` :math:`\hex{85}` :math:`[\I64~\I64] \to [\I64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I64.\SHL` :math:`\hex{86}` :math:`[\I64~\I64] \to [\I64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I64.\SHR\K{\_s}` :math:`\hex{87}` :math:`[\I64~\I64] \to [\I64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I64.\SHR\K{\_u}` :math:`\hex{88}` :math:`[\I64~\I64] \to [\I64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I64.\ROTL` :math:`\hex{89}` :math:`[\I64~\I64] \to [\I64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I64.\ROTR` :math:`\hex{8A}` :math:`[\I64~\I64] \to [\I64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\F32.\ABS` :math:`\hex{8B}` :math:`[\F32] \to [\F32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\F32.\NEG` :math:`\hex{8C}` :math:`[\F32] \to [\F32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\F32.\CEIL` :math:`\hex{8D}` :math:`[\F32] \to [\F32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\F32.\FLOOR` :math:`\hex{8E}` :math:`[\F32] \to [\F32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\F32.\TRUNC` :math:`\hex{8F}` :math:`[\F32] \to [\F32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\F32.\NEAREST` :math:`\hex{90}` :math:`[\F32] \to [\F32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\F32.\SQRT` :math:`\hex{91}` :math:`[\F32] \to [\F32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\F32.\ADD` :math:`\hex{92}` :math:`[\F32~\F32] \to [\F32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\F32.\SUB` :math:`\hex{93}` :math:`[\F32~\F32] \to [\F32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\F32.\MUL` :math:`\hex{94}` :math:`[\F32~\F32] \to [\F32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\F32.\DIV` :math:`\hex{95}` :math:`[\F32~\F32] \to [\F32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\F32.\FMIN` :math:`\hex{96}` :math:`[\F32~\F32] \to [\F32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\F32.\FMAX` :math:`\hex{97}` :math:`[\F32~\F32] \to [\F32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\F32.\COPYSIGN` :math:`\hex{98}` :math:`[\F32~\F32] \to [\F32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\F64.\ABS` :math:`\hex{99}` :math:`[\F64] \to [\F64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\F64.\NEG` :math:`\hex{9A}` :math:`[\F64] \to [\F64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\F64.\CEIL` :math:`\hex{9B}` :math:`[\F64] \to [\F64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\F64.\FLOOR` :math:`\hex{9C}` :math:`[\F64] \to [\F64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\F64.\TRUNC` :math:`\hex{9D}` :math:`[\F64] \to [\F64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\F64.\NEAREST` :math:`\hex{9E}` :math:`[\F64] \to [\F64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\F64.\SQRT` :math:`\hex{9F}` :math:`[\F64] \to [\F64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\F64.\ADD` :math:`\hex{A0}` :math:`[\F64~\F64] \to [\F64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\F64.\SUB` :math:`\hex{A1}` :math:`[\F64~\F64] \to [\F64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\F64.\MUL` :math:`\hex{A2}` :math:`[\F64~\F64] \to [\F64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\F64.\DIV` :math:`\hex{A3}` :math:`[\F64~\F64] \to [\F64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\F64.\FMIN` :math:`\hex{A4}` :math:`[\F64~\F64] \to [\F64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\F64.\FMAX` :math:`\hex{A5}` :math:`[\F64~\F64] \to [\F64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\F64.\COPYSIGN` :math:`\hex{A6}` :math:`[\F64~\F64] \to [\F64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I32.\WRAP\K{\_}\I64` :math:`\hex{A7}` :math:`[\I64] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I32.\TRUNC\K{\_}\F32\K{\_s}` :math:`\hex{A8}` :math:`[\F32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I32.\TRUNC\K{\_}\F32\K{\_u}` :math:`\hex{A9}` :math:`[\F32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I32.\TRUNC\K{\_}\F64\K{\_s}` :math:`\hex{AA}` :math:`[\F64] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I32.\TRUNC\K{\_}\F64\K{\_u}` :math:`\hex{AB}` :math:`[\F64] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I64.\EXTEND\K{\_}\I32\K{\_s}` :math:`\hex{AC}` :math:`[\I32] \to [\I64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I64.\EXTEND\K{\_}\I32\K{\_u}` :math:`\hex{AD}` :math:`[\I32] \to [\I64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I64.\TRUNC\K{\_}\F32\K{\_s}` :math:`\hex{AE}` :math:`[\F32] \to [\I64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I64.\TRUNC\K{\_}\F32\K{\_u}` :math:`\hex{AF}` :math:`[\F32] \to [\I64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I64.\TRUNC\K{\_}\F64\K{\_s}` :math:`\hex{B0}` :math:`[\F64] \to [\I64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I64.\TRUNC\K{\_}\F64\K{\_u}` :math:`\hex{B1}` :math:`[\F64] \to [\I64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\F32.\CONVERT\K{\_}\I32\K{\_s}` :math:`\hex{B2}` :math:`[\I32] \to [\F32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\F32.\CONVERT\K{\_}\I32\K{\_u}` :math:`\hex{B3}` :math:`[\I32] \to [\F32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\F32.\CONVERT\K{\_}\I64\K{\_s}` :math:`\hex{B4}` :math:`[\I64] \to [\F32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\F32.\CONVERT\K{\_}\I64\K{\_u}` :math:`\hex{B5}` :math:`[\I64] \to [\F32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\F32.\DEMOTE\K{\_}\F64` :math:`\hex{B6}` :math:`[\F64] \to [\F32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\F64.\CONVERT\K{\_}\I32\K{\_s}` :math:`\hex{B7}` :math:`[\I32] \to [\F64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\F64.\CONVERT\K{\_}\I32\K{\_u}` :math:`\hex{B8}` :math:`[\I32] \to [\F64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\F64.\CONVERT\K{\_}\I64\K{\_s}` :math:`\hex{B9}` :math:`[\I64] \to [\F64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\F64.\CONVERT\K{\_}\I64\K{\_u}` :math:`\hex{BA}` :math:`[\I64] \to [\F64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\F64.\PROMOTE\K{\_}\F32` :math:`\hex{BB}` :math:`[\F32] \to [\F64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I32.\REINTERPRET\K{\_}\F32` :math:`\hex{BC}` :math:`[\F32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I64.\REINTERPRET\K{\_}\F64` :math:`\hex{BD}` :math:`[\F64] \to [\I64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\F32.\REINTERPRET\K{\_}\I32` :math:`\hex{BE}` :math:`[\I32] \to [\F32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\F64.\REINTERPRET\K{\_}\I64` :math:`\hex{BF}` :math:`[\I64] \to [\F64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I32.\EXTEND\K{8\_s}` :math:`\hex{C0}` :math:`[\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I32.\EXTEND\K{16\_s}` :math:`\hex{C1}` :math:`[\I32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I64.\EXTEND\K{8\_s}` :math:`\hex{C2}` :math:`[\I64] \to [\I64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I64.\EXTEND\K{16\_s}` :math:`\hex{C3}` :math:`[\I64] \to [\I64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I64.\EXTEND\K{32\_s}` :math:`\hex{C4}` :math:`[\I64] \to [\I64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +(reserved) :math:`\hex{C5}` +(reserved) :math:`\hex{C6}` +(reserved) :math:`\hex{C7}` +(reserved) :math:`\hex{C8}` +(reserved) :math:`\hex{C9}` +(reserved) :math:`\hex{CA}` +(reserved) :math:`\hex{CB}` +(reserved) :math:`\hex{CC}` +(reserved) :math:`\hex{CD}` +(reserved) :math:`\hex{CE}` +(reserved) :math:`\hex{CF}` +(reserved) :math:`\hex{D0}` +(reserved) :math:`\hex{D1}` +(reserved) :math:`\hex{D2}` +(reserved) :math:`\hex{D3}` +(reserved) :math:`\hex{D4}` +(reserved) :math:`\hex{D5}` +(reserved) :math:`\hex{D6}` +(reserved) :math:`\hex{D7}` +(reserved) :math:`\hex{D8}` +(reserved) :math:`\hex{D9}` +(reserved) :math:`\hex{DA}` +(reserved) :math:`\hex{DB}` +(reserved) :math:`\hex{DC}` +(reserved) :math:`\hex{DD}` +(reserved) :math:`\hex{DE}` +(reserved) :math:`\hex{DF}` +(reserved) :math:`\hex{E0}` +(reserved) :math:`\hex{E1}` +(reserved) :math:`\hex{E2}` +(reserved) :math:`\hex{E3}` +(reserved) :math:`\hex{E4}` +(reserved) :math:`\hex{E5}` +(reserved) :math:`\hex{E6}` +(reserved) :math:`\hex{E7}` +(reserved) :math:`\hex{E8}` +(reserved) :math:`\hex{E9}` +(reserved) :math:`\hex{EA}` +(reserved) :math:`\hex{EB}` +(reserved) :math:`\hex{EC}` +(reserved) :math:`\hex{ED}` +(reserved) :math:`\hex{EE}` +(reserved) :math:`\hex{EF}` +(reserved) :math:`\hex{F0}` +(reserved) :math:`\hex{F1}` +(reserved) :math:`\hex{F2}` +(reserved) :math:`\hex{F3}` +(reserved) :math:`\hex{F4}` +(reserved) :math:`\hex{F5}` +(reserved) :math:`\hex{F6}` +(reserved) :math:`\hex{F7}` +(reserved) :math:`\hex{F8}` +(reserved) :math:`\hex{F9}` +(reserved) :math:`\hex{FA}` +(reserved) :math:`\hex{FB}` +:math:`\I32.\TRUNC\K{\_sat\_}\F32\K{\_s}` :math:`\hex{FC}~~0` :math:`[\F32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I32.\TRUNC\K{\_sat\_}\F32\K{\_u}` :math:`\hex{FC}~~1` :math:`[\F32] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I32.\TRUNC\K{\_sat\_}\F64\K{\_s}` :math:`\hex{FC}~~2` :math:`[\F64] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I32.\TRUNC\K{\_sat\_}\F64\K{\_u}` :math:`\hex{FC}~~3` :math:`[\F64] \to [\I32]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I64.\TRUNC\K{\_sat\_}\F32\K{\_s}` :math:`\hex{FC}~~4` :math:`[\F32] \to [\I64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I64.\TRUNC\K{\_sat\_}\F32\K{\_u}` :math:`\hex{FC}~~5` :math:`[\F32] \to [\I64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I64.\TRUNC\K{\_sat}\_\F64\K{\_s}` :math:`\hex{FC}~~6` :math:`[\F64] \to [\I64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +:math:`\I64.\TRUNC\K{\_sat\_}\F64\K{\_u}` :math:`\hex{FC}~~7` :math:`[\F64] \to [\I64]` :ref:`validation ` :ref:`execution `, :ref:`operator ` +========================================= =================== ============================================= ======================================= =============================================================== diff --git a/document/core/exec/instructions.rst b/document/core/exec/instructions.rst index a7e8233c09..88410b7282 100644 --- a/document/core/exec/instructions.rst +++ b/document/core/exec/instructions.rst @@ -424,7 +424,7 @@ Memory Instructions a. Let :math:`n` be the integer for which :math:`\bytes_{\iN}(n) = b^\ast`. - b. Let :math:`c` be the result of computing :math:`\extend\F{\_}\sx_{N,|t|}(n)`. + b. Let :math:`c` be the result of computing :math:`\extend^{\sx}_{N,|t|}(n)`. 13. Else: @@ -447,7 +447,7 @@ Memory Instructions \\[1ex] \begin{array}{lcl@{\qquad}l} S; F; (\I32.\CONST~i)~(t.\LOAD{N}\K{\_}\sx~\memarg) &\stepto& - S; F; (t.\CONST~\extend\F{\_}\sx_{N,|t|}(n)) + S; F; (t.\CONST~\extend^{\sx}_{N,|t|}(n)) \end{array} \\ \qquad \begin{array}[t]{@{}r@{~}l@{}} diff --git a/document/core/exec/numerics.rst b/document/core/exec/numerics.rst index 04783a4424..748ca605aa 100644 --- a/document/core/exec/numerics.rst +++ b/document/core/exec/numerics.rst @@ -1603,7 +1603,7 @@ Conversions .. math:: \begin{array}{lll@{\qquad}l} - \convertu_{M,N}(i) &=& \ieee_N(\signed_M(i)) \\ + \converts_{M,N}(i) &=& \ieee_N(\signed_M(i)) \\ \end{array} diff --git a/document/core/text/instructions.rst b/document/core/text/instructions.rst index bb00e75e6d..737ebe8e5f 100644 --- a/document/core/text/instructions.rst +++ b/document/core/text/instructions.rst @@ -430,20 +430,20 @@ Numeric Instructions \text{i32.trunc\_f32\_u} &\Rightarrow& \I32.\TRUNC\K{\_}\F32\K{\_u} \\ &&|& \text{i32.trunc\_f64\_s} &\Rightarrow& \I32.\TRUNC\K{\_}\F64\K{\_s} \\ &&|& \text{i32.trunc\_f64\_u} &\Rightarrow& \I32.\TRUNC\K{\_}\F64\K{\_u} \\ &&|& - \text{i32.trunc\_sat_f32\_s} &\Rightarrow& \I32.\TRUNC\K{\_sat\_}\F32\K{\_s} \\ &&|& - \text{i32.trunc\_sat_f32\_u} &\Rightarrow& \I32.\TRUNC\K{\_sat\_}\F32\K{\_u} \\ &&|& - \text{i32.trunc\_sat_f64\_s} &\Rightarrow& \I32.\TRUNC\K{\_sat\_}\F64\K{\_s} \\ &&|& - \text{i32.trunc\_sat_f64\_u} &\Rightarrow& \I32.\TRUNC\K{\_sat\_}\F64\K{\_u} \\ &&|& + \text{i32.trunc\_sat\_f32\_s} &\Rightarrow& \I32.\TRUNC\K{\_sat\_}\F32\K{\_s} \\ &&|& + \text{i32.trunc\_sat\_f32\_u} &\Rightarrow& \I32.\TRUNC\K{\_sat\_}\F32\K{\_u} \\ &&|& + \text{i32.trunc\_sat\_f64\_s} &\Rightarrow& \I32.\TRUNC\K{\_sat\_}\F64\K{\_s} \\ &&|& + \text{i32.trunc\_sat\_f64\_u} &\Rightarrow& \I32.\TRUNC\K{\_sat\_}\F64\K{\_u} \\ &&|& \text{i64.extend\_i32\_s} &\Rightarrow& \I64.\EXTEND\K{\_}\I32\K{\_s} \\ &&|& \text{i64.extend\_i32\_u} &\Rightarrow& \I64.\EXTEND\K{\_}\I32\K{\_u} \\ &&|& \text{i64.trunc\_f32\_s} &\Rightarrow& \I64.\TRUNC\K{\_}\F32\K{\_s} \\ &&|& \text{i64.trunc\_f32\_u} &\Rightarrow& \I64.\TRUNC\K{\_}\F32\K{\_u} \\ &&|& \text{i64.trunc\_f64\_s} &\Rightarrow& \I64.\TRUNC\K{\_}\F64\K{\_s} \\ &&|& \text{i64.trunc\_f64\_u} &\Rightarrow& \I64.\TRUNC\K{\_}\F64\K{\_u} \\ &&|& - \text{i64.trunc\_sat_f32\_s} &\Rightarrow& \I64.\TRUNC\K{\_sat\_}\F32\K{\_s} \\ &&|& - \text{i64.trunc\_sat_f32\_u} &\Rightarrow& \I64.\TRUNC\K{\_sat\_}\F32\K{\_u} \\ &&|& - \text{i64.trunc\_sat_f64\_s} &\Rightarrow& \I64.\TRUNC\K{\_sat\_}\F64\K{\_s} \\ &&|& - \text{i64.trunc\_sat_f64\_u} &\Rightarrow& \I64.\TRUNC\K{\_sat\_}\F64\K{\_u} \\ &&|& + \text{i64.trunc\_sat\_f32\_s} &\Rightarrow& \I64.\TRUNC\K{\_sat\_}\F32\K{\_s} \\ &&|& + \text{i64.trunc\_sat\_f32\_u} &\Rightarrow& \I64.\TRUNC\K{\_sat\_}\F32\K{\_u} \\ &&|& + \text{i64.trunc\_sat\_f64\_s} &\Rightarrow& \I64.\TRUNC\K{\_sat\_}\F64\K{\_s} \\ &&|& + \text{i64.trunc\_sat\_f64\_u} &\Rightarrow& \I64.\TRUNC\K{\_sat\_}\F64\K{\_u} \\ &&|& \text{f32.convert\_i32\_s} &\Rightarrow& \F32.\CONVERT\K{\_}\I32\K{\_s} \\ &&|& \text{f32.convert\_i32\_u} &\Rightarrow& \F32.\CONVERT\K{\_}\I32\K{\_u} \\ &&|& \text{f32.convert\_i64\_s} &\Rightarrow& \F32.\CONVERT\K{\_}\I64\K{\_s} \\ &&|& diff --git a/document/js-api/index.bs b/document/js-api/index.bs index 9af7e69620..91fc509859 100644 --- a/document/js-api/index.bs +++ b/document/js-api/index.bs @@ -792,6 +792,7 @@ Each {{Table}} object has a \[[Table]] internal slot, which is a [=table address 1. Let |store| be the [=surrounding agent=]'s [=associated store=]. 1. Let |result| be [=table_read=](|store|, |tableaddr|, |index|). 1. If |result| is [=error=], throw a {{RangeError}} exception. + 1. If |result| is ε, return null. 1. Let |function| be the result of creating [=a new Exported Function=] from |result|. 1. Return |function|.
    @@ -799,7 +800,7 @@ Each {{Table}} object has a \[[Table]] internal slot, which is a [=table address
    The set(|index|, |value|) method, when invoked, performs the following steps: 1. Let |tableaddr| be **this**.\[[Table]]. - 1. If |value| is null, let |funcaddr| be an empty [=function element=]. + 1. If |value| is null, let |funcaddr| be ε. 1. Otherwise, 1. If |value| does not have a \[[FunctionAddress]] internal slot, throw a {{TypeError}} exception. 1. Let |funcaddr| be |value|.\[[FunctionAddress]]. diff --git a/document/web-api/index.bs b/document/web-api/index.bs index 564dd6ee0a..3cc6108201 100644 --- a/document/web-api/index.bs +++ b/document/web-api/index.bs @@ -253,17 +253,27 @@ application/wasm
    Encoding Considerations:
    binary
    Security Considerations:
    -
    See see WebAssembly Core Security Considerations
    - https://www.w3.org/TR/wasm-core/#security-considerations%E2%91%A0
    +
    +

    WebAssembly is a standard, a safe, portable, low-level code format. The + security considerations associated with executing WebAssembly code are + described in https://www.w3.org/TR/wasm-core/#security-considerations.

    +

    The WebAssembly format includes no integrity or privacy protection. If + such protection is needed it must be provided externally, e.g., through + the use of HTTPS.

    +
    Interoperability Considerations:
    -
    See see WebAssembly Core Conformance
    +
    See WebAssembly Core Conformance
    https://www.w3.org/TR/wasm-core/#conformance
    Published specification:
    - https://www.w3.org/TR/wasm-core-1/ +
    https://www.w3.org/TR/wasm-core-1/ https://www.w3.org/TR/wasm-js-api-1/ - https://www.w3.org/TR/wasm-web-api-1/ + https://www.w3.org/TR/wasm-web-api-1/
    Application Usage:
    -
    The application/wasm media type is already in use as the type used to describe WebAssembly files when sent over HTTP to be executed by browsers, which is a common scenario. Additionally, several WebAssembly runtimes that take advantage of the safety and portability while targeting efficient execution and compact representation.
    +
    The application/wasm media type is intended for use as the type used to + describe WebAssembly files when sent over HTTP to be executed by browsers, + which is a common scenario. Additionally, the type is used by several + WebAssembly runtimes that take advantage of the safety and portability + while targeting efficient execution and compact representation.
    Fragment Identifier Considerations:
    None
    Restrictions on usage:
    diff --git a/interpreter/Makefile b/interpreter/Makefile index eee4935cdf..c745311b9d 100644 --- a/interpreter/Makefile +++ b/interpreter/Makefile @@ -112,22 +112,36 @@ $(WINMAKE): clean # Executing test suite -.PHONY: test debugtest +TESTDIR = ../test/core +TESTFILES = $(shell cd $(TESTDIR); ls *.wast) +TESTS = $(TESTFILES:%.wast=%) + +.PHONY: test debugtest partest test: $(OPT) - ../test/core/run.py --wasm `pwd`/$(OPT) $(if $(JS),--js '$(JS)',) + $(TESTDIR)/run.py --wasm `pwd`/$(OPT) $(if $(JS),--js '$(JS)',) debugtest: $(UNOPT) - ../test/core/run.py --wasm `pwd`/$(UNOPT) $(if $(JS),--js '$(JS)',) + $(TESTDIR)/run.py --wasm `pwd`/$(UNOPT) $(if $(JS),--js '$(JS)',) test/%: $(OPT) - ../test/core/run.py --wasm `pwd`/$(OPT) $(if $(JS),--js '$(JS)',) $(@:test/%=../test/core/%.wast) + $(TESTDIR)/run.py --wasm `pwd`/$(OPT) $(if $(JS),--js '$(JS)',) $(TESTDIR)/$(@F).wast debugtest/%: $(UNOPT) - ../test/core/run.py --wasm `pwd`/$(UNOPT) $(if $(JS),--js '$(JS)',) $(@:debugtest/%=../test/core/%.wast) + $(TESTDIR)/run.py --wasm `pwd`/$(UNOPT) $(if $(JS),--js '$(JS)',) $(TESTDIR)/$(@F).wast run/%: $(OPT) - ./$(OPT) $(@:run/%=../test/core/%.wast) + ./$(OPT) $(TESTDIR)/$(@F).wast debug/%: $(UNOPT) - ./$(UNOPT) $(@:debug/%=../test/core/%.wast) + ./$(UNOPT) $(TESTDIR)/$(@F).wast + +partest: $(TESTS:%=quiettest/%) + @echo All tests passed. + +quiettest/%: $(OPT) + @ ( \ + $(TESTDIR)/run.py 2>$(@F).out --wasm `pwd`/$(OPT) $(if $(JS),--js '$(JS)',) $(@F:%=$(TESTDIR)/%.wast) && \ + rm $(@F).out \ + ) || \ + cat $(@F).out || rm $(@F).out || exit 1 # Miscellaneous targets diff --git a/interpreter/README.md b/interpreter/README.md index 9e210f63bf..b430f83871 100644 --- a/interpreter/README.md +++ b/interpreter/README.md @@ -370,6 +370,36 @@ The `input` and `output` meta commands determine the requested file format from The interpreter supports a "dry" mode (flag `-d`), in which modules are only validated. In this mode, all actions and assertions are ignored. It also supports an "unchecked" mode (flag `-u`), in which module definitions are not validated before use. + +### Spectest host module + +When running scripts, the interpreter predefines a simple host module named `"spectest"` that has the following module type: +``` +(module + (global (export "global_i32") i32) + (global (export "global_i64") i64) + (global (export "global_f32") f32) + (global (export "global_f64") f64) + + (table (export "table") 10 20 funcref) + + (memory (export "memory") 1 2) + + (func (export "print")) + (func (export "print_i32") (param i32)) + (func (export "print_i64") (param i64)) + (func (export "print_f32") (param f32)) + (func (export "print_f64") (param f64)) + (func (export "print_i32_f32") (param i32 f32)) + (func (export "print_f64_f64") (param f64 f64)) +) +``` +The `print` functions are assumes to print their respective argument values to stdout (followed by a newline) and can be used to produce observable output. + +Note: This module predates the `register` command and should no longer be needed for new tests. +We might remove it in the future, so consider it deprecated. + + ### Binary Scripts The grammar of binary scripts is a subset of the grammar for general scripts: diff --git a/interpreter/exec/int.ml b/interpreter/exec/int.ml index 7236c52831..ec23208d8e 100644 --- a/interpreter/exec/int.ml +++ b/interpreter/exec/int.ml @@ -199,7 +199,7 @@ struct let popcnt x = let rec loop acc i n = - if n = Rep.zero then + if i = 0 then acc else let acc' = if and_ n Rep.one = Rep.one then acc + 1 else acc in diff --git a/interpreter/host/spectest.ml b/interpreter/host/spectest.ml index 78f3e994a9..9d6ff9a434 100644 --- a/interpreter/host/spectest.ml +++ b/interpreter/host/spectest.ml @@ -34,13 +34,15 @@ let lookup name t = match Utf8.encode name, t with | "print", _ -> ExternFunc (func print (FuncType ([], []))) | "print_i32", _ -> ExternFunc (func print (FuncType ([I32Type], []))) + | "print_i64", _ -> ExternFunc (func print (FuncType ([I64Type], []))) + | "print_f32", _ -> ExternFunc (func print (FuncType ([F32Type], []))) + | "print_f64", _ -> ExternFunc (func print (FuncType ([F64Type], []))) | "print_i32_f32", _ -> ExternFunc (func print (FuncType ([I32Type; F32Type], []))) | "print_f64_f64", _ -> ExternFunc (func print (FuncType ([F64Type; F64Type], []))) - | "print_f32", _ -> ExternFunc (func print (FuncType ([F32Type], []))) - | "print_f64", _ -> ExternFunc (func print (FuncType ([F64Type], []))) | "global_i32", _ -> ExternGlobal (global (GlobalType (I32Type, Immutable))) + | "global_i64", _ -> ExternGlobal (global (GlobalType (I64Type, Immutable))) | "global_f32", _ -> ExternGlobal (global (GlobalType (F32Type, Immutable))) | "global_f64", _ -> ExternGlobal (global (GlobalType (F64Type, Immutable))) | "table", _ -> ExternTable table diff --git a/test/core/binary-leb128.wast b/test/core/binary-leb128.wast index 6e015e3d00..1d67219583 100644 --- a/test/core/binary-leb128.wast +++ b/test/core/binary-leb128.wast @@ -853,7 +853,7 @@ "\41\00" ;; i32.const 0 "\41\03" ;; i32.const 3 "\36" ;; i32.store - "\03" ;; alignment 2 + "\02" ;; alignment 2 "\82\80\80\80\10" ;; offset 2 with unused bits set "\0b" ;; end ) diff --git a/test/core/binary.wast b/test/core/binary.wast index c1ebddfce9..94c39a92ef 100644 --- a/test/core/binary.wast +++ b/test/core/binary.wast @@ -51,6 +51,21 @@ (assert_malformed (module binary "\00asm" "\01\00\00\00" "\81\00\01\00") "malformed section id") (assert_malformed (module binary "\00asm" "\01\00\00\00" "\ff\00\01\00") "malformed section id") + +;; Type section with signed LEB128 encoded type +(assert_malformed + (module binary + "\00asm" "\01\00\00\00" + "\01" ;; Type section id + "\05" ;; Type section length + "\01" ;; Types vector length + "\e0\7f" ;; Malformed functype, -0x20 in signed LEB128 encoding + "\00\00" + ) + "integer representation too long" +) + + ;; call_indirect reserved byte equal to zero. (assert_malformed (module binary @@ -335,7 +350,24 @@ "zero flag expected" ) -;; No more than 2^32 locals. +;; Local number is unsigned 32 bit +(assert_malformed + (module binary + "\00asm" "\01\00\00\00" + "\01\04\01\60\00\00" ;; Type section + "\03\02\01\00" ;; Function section + "\0a\0c\01" ;; Code section + + ;; function 0 + "\0a\02" + "\80\80\80\80\10\7f" ;; 0x100000000 i32 + "\02\7e" ;; 0x00000002 i64 + "\0b" ;; end + ) + "integer too large" +) + +;; No more than 2^32-1 locals. (assert_malformed (module binary "\00asm" "\01\00\00\00" @@ -352,6 +384,24 @@ "too many locals" ) +(assert_malformed + (module binary + "\00asm" "\01\00\00\00" + "\01\06\01\60\02\7f\7f\00" ;; Type section: (param i32 i32) + "\03\02\01\00" ;; Function section + "\0a\1c\01" ;; Code section + + ;; function 0 + "\1a\04" + "\80\80\80\80\04\7f" ;; 0x40000000 i32 + "\80\80\80\80\04\7e" ;; 0x40000000 i64 + "\80\80\80\80\04\7d" ;; 0x40000000 f32 + "\80\80\80\80\04\7c" ;; 0x40000000 f64 + "\0b" ;; end + ) + "too many locals" +) + ;; Local count can be 0. (module binary "\00asm" "\01\00\00\00" @@ -934,10 +984,25 @@ "\09\07\02" ;; elem with inconsistent segment count (2 declared, 1 given) "\00\41\00\0b\01\00" ;; elem 0 ;; "\00\41\00\0b\01\00" ;; elem 1 (missed) - "\0a\04\01" ;; code section - "\02\00\0b" ;; function body ) - "invalid elements segment kind" + "unexpected end" +) + +;; 2 elem segment declared, 1.5 given +(assert_malformed + (module binary + "\00asm" "\01\00\00\00" + "\01\04\01" ;; type section + "\60\00\00" ;; type 0 + "\03\02\01\00" ;; func section + "\04\04\01" ;; table section + "\70\00\01" ;; table 0 + "\09\07\02" ;; elem with inconsistent segment count (2 declared, 1 given) + "\00\41\00\0b\01\00" ;; elem 0 + "\00\41\00" ;; elem 1 (partial) + ;; "\0b\01\00" ;; elem 1 (missing part) + ) + "unexpected end" ) ;; 1 elem segment declared, 2 given diff --git a/test/core/br_table.wast b/test/core/br_table.wast index 58abe38a4f..d03068744e 100644 --- a/test/core/br_table.wast +++ b/test/core/br_table.wast @@ -1464,6 +1464,16 @@ )) "type mismatch" ) +(assert_invalid + (module (func + (block (result i32) + (block (result i64) + (br_table 0 1 (i32.const 0) (i32.const 0)) + ) + ) + )) + "type mismatch" +) (assert_invalid (module (func $type-index-void-vs-i32 @@ -1552,6 +1562,31 @@ "type mismatch" ) +(assert_invalid + (module + (func (param i32) (result i32) + (loop (result i32) + (block (result i32) + (br_table 0 1 (i32.const 1) (local.get 0)) + ) + ) + ) + ) + "type mismatch" +) +(assert_invalid + (module + (func (param i32) (result i32) + (block (result i32) + (loop (result i32) + (br_table 0 1 (i32.const 1) (local.get 0)) + ) + ) + ) + ) + "type mismatch" +) + (assert_invalid (module (func $unbound-label diff --git a/test/core/data.wast b/test/core/data.wast index aabe1021b2..edf640b14c 100644 --- a/test/core/data.wast +++ b/test/core/data.wast @@ -296,6 +296,69 @@ "unknown memory" ) +;; Data segment with memory index 1 (only memory 0 available) +(assert_invalid + (module binary + "\00asm" "\01\00\00\00" + "\05\03\01" ;; memory section + "\00\00" ;; memory 0 + "\0b\07\01" ;; data section + "\02\01\41\00\0b" ;; active data segment 0 for memory 1 + "\00" ;; empty vec(byte) + ) + "unknown memory 1" +) + +;; Data segment with memory index 1 (no memory section) +(assert_invalid + (module binary + "\00asm" "\01\00\00\00" + "\0b\07\01" ;; data section + "\02\01\41\00\0b" ;; active data segment 0 for memory 1 + "\00" ;; empty vec(byte) + ) + "unknown memory 1" +) + +;; Data segment with memory index 1 and vec(byte) as above, +;; only memory 0 available. +(assert_invalid + (module binary + "\00asm" "\01\00\00\00" + "\05\03\01" ;; memory section + "\00\00" ;; memory 0 + "\0b\45\01" ;; data section + "\02\01" ;; active segment, memory index + "\41\00\0b" ;; offset constant expression + "\3e" ;; vec(byte) length + "\00\01\02\03\04\05\06\07\08\09\0a\0b\0c\0d\0e\0f" + "\10\11\12\13\14\15\16\17\18\19\1a\1b\1c\1d\1e\1f" + "\20\21\22\23\24\25\26\27\28\29\2a\2b\2c\2d\2e\2f" + "\30\31\32\33\34\35\36\37\38\39\3a\3b\3c\3d" + ) + "unknown memory 1" +) + +;; Data segment with memory index 1 and specially crafted vec(byte) after. +;; This is to detect incorrect validation where memory index is interpreted +;; as a flag followed by "\41" interpreted as the size of vec(byte) +;; with the expected number of bytes following. +(assert_invalid + (module binary + "\00asm" "\01\00\00\00" + "\0b\45\01" ;; data section + "\02\01" ;; active segment, memory index + "\41\00\0b" ;; offset constant expression + "\3e" ;; vec(byte) length + "\00\01\02\03\04\05\06\07\08\09\0a\0b\0c\0d\0e\0f" + "\10\11\12\13\14\15\16\17\18\19\1a\1b\1c\1d\1e\1f" + "\20\21\22\23\24\25\26\27\28\29\2a\2b\2c\2d\2e\2f" + "\30\31\32\33\34\35\36\37\38\39\3a\3b\3c\3d" + ) + "unknown memory 1" +) + + ;; Invalid offsets (assert_invalid @@ -306,6 +369,40 @@ "type mismatch" ) +(assert_invalid + (module + (memory 1) + (data (offset (;empty instruction sequence;))) + ) + "type mismatch" +) + +(assert_invalid + (module + (memory 1) + (data (offset (i32.const 0) (i32.const 0))) + ) + "type mismatch" +) + +(assert_invalid + (module + (global (import "test" "global-i32") i32) + (memory 1) + (data (offset (global.get 0) (global.get 0))) + ) + "type mismatch" +) + +(assert_invalid + (module + (global (import "test" "global-i32") i32) + (memory 1) + (data (offset (global.get 0) (i32.const 0))) + ) + "type mismatch" +) + (assert_invalid (module (memory 1) @@ -343,3 +440,29 @@ ;; (module (memory 1) (data (global.get $g)) (global $g (mut i32) (i32.const 0))) ;; "constant expression required" ;; ) + +(assert_invalid + (module + (memory 1) + (data (global.get 0)) + ) + "unknown global 0" +) + +(assert_invalid + (module + (global (import "test" "global-i32") i32) + (memory 1) + (data (global.get 1)) + ) + "unknown global 1" +) + +(assert_invalid + (module + (global (import "test" "global-mut-i32") (mut i32)) + (memory 1) + (data (global.get 0)) + ) + "constant expression required" +) diff --git a/test/core/elem.wast b/test/core/elem.wast index a50a1a2b36..3db092f07e 100644 --- a/test/core/elem.wast +++ b/test/core/elem.wast @@ -314,6 +314,41 @@ "type mismatch" ) +(assert_invalid + (module + (table 1 funcref) + (elem (offset (;empty instruction sequence;))) + ) + "type mismatch" +) + +(assert_invalid + (module + (table 1 funcref) + (elem (offset (i32.const 0) (i32.const 0))) + ) + "type mismatch" +) + +(assert_invalid + (module + (global (import "test" "global-i32") i32) + (table 1 funcref) + (elem (offset (global.get 0) (global.get 0))) + ) + "type mismatch" +) + +(assert_invalid + (module + (global (import "test" "global-i32") i32) + (table 1 funcref) + (elem (offset (global.get 0) (i32.const 0))) + ) + "type mismatch" +) + + (assert_invalid (module (table 1 funcref) @@ -352,6 +387,32 @@ ;; "constant expression required" ;; ) +(assert_invalid + (module + (table 1 funcref) + (elem (global.get 0)) + ) + "unknown global 0" +) + +(assert_invalid + (module + (global (import "test" "global-i32") i32) + (table 1 funcref) + (elem (global.get 1)) + ) + "unknown global 1" +) + +(assert_invalid + (module + (global (import "test" "global-mut-i32") (mut i32)) + (table 1 funcref) + (elem (global.get 0)) + ) + "constant expression required" +) + ;; Two elements target the same slot (module diff --git a/test/core/exports.wast b/test/core/exports.wast index ef1c4c17eb..0c44694dbf 100644 --- a/test/core/exports.wast +++ b/test/core/exports.wast @@ -25,10 +25,18 @@ (module $Other1) (assert_return (invoke $Func "e" (i32.const 42)) (i32.const 43)) +(assert_invalid + (module (export "a" (func 0))) + "unknown function" +) (assert_invalid (module (func) (export "a" (func 1))) "unknown function" ) +(assert_invalid + (module (import "spectest" "print_i32" (func (param i32))) (export "a" (func 1))) + "unknown function" +) (assert_invalid (module (func) (export "a" (func 0)) (export "a" (func 0))) "duplicate export name" @@ -74,10 +82,18 @@ (module $Other2) (assert_return (get $Global "e") (i32.const 42)) +(assert_invalid + (module (export "a" (global 0))) + "unknown global" +) (assert_invalid (module (global i32 (i32.const 0)) (export "a" (global 1))) "unknown global" ) +(assert_invalid + (module (import "spectest" "global_i32" (global i32)) (export "a" (global 1))) + "unknown global" +) (assert_invalid (module (global i32 (i32.const 0)) (export "a" (global 0)) (export "a" (global 0))) "duplicate export name" @@ -122,10 +138,18 @@ (; TODO: access table ;) +(assert_invalid + (module (export "a" (table 0))) + "unknown table" +) (assert_invalid (module (table 0 funcref) (export "a" (table 1))) "unknown table" ) +(assert_invalid + (module (import "spectest" "table" (table 10 20 funcref)) (export "a" (table 1))) + "unknown table" +) (assert_invalid (module (table 0 funcref) (export "a" (table 0)) (export "a" (table 0))) "duplicate export name" @@ -171,10 +195,18 @@ (; TODO: access memory ;) +(assert_invalid + (module (export "a" (memory 0))) + "unknown memory" +) (assert_invalid (module (memory 0) (export "a" (memory 1))) "unknown memory" ) +(assert_invalid + (module (import "spectest" "memory" (memory 1 2)) (export "a" (memory 1))) + "unknown memory" +) (assert_invalid (module (memory 0) (export "a" (memory 0)) (export "a" (memory 0))) "duplicate export name" diff --git a/test/core/global.wast b/test/core/global.wast index ef1fccbbde..55d7447b19 100644 --- a/test/core/global.wast +++ b/test/core/global.wast @@ -244,6 +244,11 @@ "global is immutable" ) +(assert_invalid + (module (import "spectest" "global_i32" (global i32)) (func (global.set 0 (i32.const 1)))) + "global is immutable" +) + ;; mutable globals can be exported (module (global (mut f32) (f32.const 0)) (export "a" (global 0))) (module (global (export "a") (mut f32) (f32.const 0))) @@ -268,6 +273,11 @@ "constant expression required" ) +(assert_invalid + (module (global i32 (i32.ctz (i32.const 0)))) + "constant expression required" +) + (assert_invalid (module (global i32 (nop))) "constant expression required" @@ -288,6 +298,16 @@ "type mismatch" ) +(assert_invalid + (module (global (import "test" "global-i32") i32) (global i32 (global.get 0) (global.get 0))) + "type mismatch" +) + +(assert_invalid + (module (global (import "test" "global-i32") i32) (global i32 (i32.const 0) (global.get 0))) + "type mismatch" +) + (assert_invalid (module (global i32 (global.get 0))) "unknown global" @@ -298,6 +318,16 @@ "unknown global" ) +(assert_invalid + (module (global (import "test" "global-i32") i32) (global i32 (global.get 2))) + "unknown global" +) + +(assert_invalid + (module (global (import "test" "global-mut-i32") (mut i32)) (global i32 (global.get 0))) + "constant expression required" +) + (module (import "spectest" "global_i32" (global i32)) ) @@ -356,6 +386,68 @@ "malformed mutability" ) +;; global.get with invalid index +(assert_invalid + (module (func (result i32) (global.get 0))) + "unknown global" +) + +(assert_invalid + (module + (global i32 (i32.const 0)) + (func (result i32) (global.get 1)) + ) + "unknown global" +) + +(assert_invalid + (module + (import "spectest" "global_i32" (global i32)) + (func (result i32) (global.get 1)) + ) + "unknown global" +) + +(assert_invalid + (module + (import "spectest" "global_i32" (global i32)) + (global i32 (i32.const 0)) + (func (result i32) (global.get 2)) + ) + "unknown global" +) + +;; global.set with invalid index +(assert_invalid + (module (func (i32.const 0) (global.set 0))) + "unknown global" +) + +(assert_invalid + (module + (global i32 (i32.const 0)) + (func (i32.const 0) (global.set 1)) + ) + "unknown global" +) + +(assert_invalid + (module + (import "spectest" "global_i32" (global i32)) + (func (i32.const 0) (global.set 1)) + ) + "unknown global" +) + +(assert_invalid + (module + (import "spectest" "global_i32" (global i32)) + (global i32 (i32.const 0)) + (func (i32.const 0) (global.set 2)) + ) + "unknown global" +) + (assert_invalid (module diff --git a/test/core/imports.wast b/test/core/imports.wast index d987775ecb..733e63e34f 100644 --- a/test/core/imports.wast +++ b/test/core/imports.wast @@ -10,6 +10,7 @@ (func (export "func-i64->i64") (param i64) (result i64) (local.get 0)) (global (export "global-i32") i32 (i32.const 55)) (global (export "global-f32") f32 (f32.const 44)) + (global (export "global-mut-i64") (mut i64) (i64.const 66)) (table (export "table-10-inf") 10 funcref) ;; (table (export "table-10-20") 10 20 funcref) (memory (export "memory-2-inf") 2) @@ -230,6 +231,7 @@ (module (import "test" "global-i32" (global i32))) (module (import "test" "global-f32" (global f32))) +(module (import "test" "global-mut-i64" (global (mut i64)))) (assert_unlinkable (module (import "test" "unknown" (global i32))) @@ -240,6 +242,55 @@ "unknown import" ) +(assert_unlinkable + (module (import "test" "global-i32" (global i64))) + "incompatible import type" +) +(assert_unlinkable + (module (import "test" "global-i32" (global f32))) + "incompatible import type" +) +(assert_unlinkable + (module (import "test" "global-i32" (global f64))) + "incompatible import type" +) +(assert_unlinkable + (module (import "test" "global-i32" (global (mut i32)))) + "incompatible import type" +) +(assert_unlinkable + (module (import "test" "global-f32" (global i32))) + "incompatible import type" +) +(assert_unlinkable + (module (import "test" "global-f32" (global i64))) + "incompatible import type" +) +(assert_unlinkable + (module (import "test" "global-f32" (global f64))) + "incompatible import type" +) +(assert_unlinkable + (module (import "test" "global-f32" (global (mut f32)))) + "incompatible import type" +) +(assert_unlinkable + (module (import "test" "global-mut-i64" (global (mut i32)))) + "incompatible import type" +) +(assert_unlinkable + (module (import "test" "global-mut-i64" (global (mut f32)))) + "incompatible import type" +) +(assert_unlinkable + (module (import "test" "global-mut-i64" (global (mut f64)))) + "incompatible import type" +) +(assert_unlinkable + (module (import "test" "global-mut-i64" (global i64))) + "incompatible import type" +) + (assert_unlinkable (module (import "test" "func" (global i32))) "incompatible import type" diff --git a/test/core/local_get.wast b/test/core/local_get.wast index ab564cbed0..6acab3988f 100644 --- a/test/core/local_get.wast +++ b/test/core/local_get.wast @@ -198,29 +198,29 @@ ;; Invalid local index (assert_invalid - (module (func $unbound-local (local i32 i64) (local.get 3))) + (module (func $unbound-local (local i32 i64) (local.get 3) drop)) "unknown local" ) (assert_invalid - (module (func $large-local (local i32 i64) (local.get 14324343))) + (module (func $large-local (local i32 i64) (local.get 14324343) drop)) "unknown local" ) (assert_invalid - (module (func $unbound-param (param i32 i64) (local.get 2))) + (module (func $unbound-param (param i32 i64) (local.get 2) drop)) "unknown local" ) (assert_invalid - (module (func $large-param (param i32 i64) (local.get 714324343))) + (module (func $large-param (param i32 i64) (local.get 714324343) drop)) "unknown local" ) (assert_invalid - (module (func $unbound-mixed (param i32) (local i32 i64) (local.get 3))) + (module (func $unbound-mixed (param i32) (local i32 i64) (local.get 3) drop)) "unknown local" ) (assert_invalid - (module (func $large-mixed (param i64) (local i32 i64) (local.get 214324343))) + (module (func $large-mixed (param i64) (local i32 i64) (local.get 214324343) drop)) "unknown local" ) diff --git a/test/core/local_tee.wast b/test/core/local_tee.wast index dde7321ec1..a158f0c7c2 100644 --- a/test/core/local_tee.wast +++ b/test/core/local_tee.wast @@ -595,45 +595,45 @@ "type mismatch" ) - -;; Invalid local index - (assert_invalid - (module (func $unbound-local (local i32 i64) (local.get 3))) - "unknown local" + (module (func $type-mixed-arg-num-vs-num (param f32) (local i32) (local.tee 1 (f32.const 0)))) + "type mismatch" ) (assert_invalid - (module (func $large-local (local i32 i64) (local.get 14324343))) - "unknown local" + (module (func $type-mixed-arg-num-vs-num (param i64 i32) (local f32) (local.tee 1 (f32.const 0)))) + "type mismatch" +) +(assert_invalid + (module (func $type-mixed-arg-num-vs-num (param i64) (local f64 i64) (local.tee 1 (i64.const 0)))) + "type mismatch" ) + +;; Invalid local index + (assert_invalid - (module (func $unbound-param (param i32 i64) (local.get 2))) + (module (func $unbound-local (local i32 i64) (local.tee 3 (i32.const 0)) drop)) "unknown local" ) (assert_invalid - (module (func $large-param (local i32 i64) (local.get 714324343))) + (module (func $large-local (local i32 i64) (local.tee 14324343 (i32.const 0)) drop)) "unknown local" ) (assert_invalid - (module (func $unbound-mixed (param i32) (local i32 i64) (local.get 3))) + (module (func $unbound-param (param i32 i64) (local.tee 2 (i32.const 0)) drop)) "unknown local" ) (assert_invalid - (module (func $large-mixed (param i64) (local i32 i64) (local.get 214324343))) + (module (func $large-param (param i32 i64) (local.tee 714324343 (i32.const 0)) drop)) "unknown local" ) (assert_invalid - (module (func $type-mixed-arg-num-vs-num (param f32) (local i32) (local.tee 1 (f32.const 0)))) - "type mismatch" -) -(assert_invalid - (module (func $type-mixed-arg-num-vs-num (param i64 i32) (local f32) (local.tee 1 (f32.const 0)))) - "type mismatch" + (module (func $unbound-mixed (param i32) (local i32 i64) (local.tee 3 (i32.const 0)) drop)) + "unknown local" ) (assert_invalid - (module (func $type-mixed-arg-num-vs-num (param i64) (local f64 i64) (local.tee 1 (i64.const 0)))) - "type mismatch" + (module (func $large-mixed (param i64) (local i32 i64) (local.tee 214324343 (i32.const 0)) drop)) + "unknown local" ) diff --git a/test/core/select.wast b/test/core/select.wast index cee2054911..e40347e355 100644 --- a/test/core/select.wast +++ b/test/core/select.wast @@ -28,10 +28,19 @@ (unreachable) (select) (unreachable) (i32.const 0) (select) (unreachable) (i32.const 0) (i32.const 0) (select) + (unreachable) (i32.const 0) (i32.const 0) (i32.const 0) (select) (unreachable) (f32.const 0) (i32.const 0) (select) (unreachable) ) + (func (export "select_unreached_result_1") (result i32) + (unreachable) (i32.add (select)) + ) + + (func (export "select_unreached_result_2") (result i64) + (unreachable) (i64.add (select (i64.const 0) (i32.const 0))) + ) + ;; As the argument of control constructs and instructions (func (export "as-select-first") (param i32) (result i32) @@ -287,22 +296,22 @@ (assert_return (invoke "as-convert-operand" (i32.const 1)) (i32.const 1)) (assert_invalid - (module (func $arity-0 (select (nop) (nop) (i32.const 1)))) + (module (func $arity-0 (select (nop) (nop) (i32.const 1)) (drop))) "type mismatch" ) ;; The first two operands should have the same type as each other (assert_invalid - (module (func $type-num-vs-num (select (i32.const 1) (i64.const 1) (i32.const 1)))) + (module (func $type-num-vs-num (select (i32.const 1) (i64.const 1) (i32.const 1)) (drop))) "type mismatch" ) (assert_invalid - (module (func $type-num-vs-num (select (i32.const 1) (f32.const 1.0) (i32.const 1)))) + (module (func $type-num-vs-num (select (i32.const 1) (f32.const 1.0) (i32.const 1)) (drop))) "type mismatch" ) (assert_invalid - (module (func $type-num-vs-num (select (i32.const 1) (f64.const 1.0) (i32.const 1)))) + (module (func $type-num-vs-num (select (i32.const 1) (f64.const 1.0) (i32.const 1)) (drop))) "type mismatch" ) @@ -412,3 +421,67 @@ ) "type mismatch" ) + +;; Third operand must be i32 + +(assert_invalid + (module (func (select (i32.const 1) (i32.const 1) (i64.const 1)) (drop))) + "type mismatch" +) +(assert_invalid + (module (func (select (i32.const 1) (i32.const 1) (f32.const 1)) (drop))) + "type mismatch" +) +(assert_invalid + (module (func (select (i32.const 1) (i32.const 1) (f64.const 1)) (drop))) + "type mismatch" +) + +;; Result of select has type of first two operands + +(assert_invalid + (module (func (result i32) (select (i64.const 1) (i64.const 1) (i32.const 1)))) + "type mismatch" +) + +;; Validation after unreachable + +;; The first two operands should have the same type as each other +(assert_invalid + (module (func (unreachable) (select (i32.const 1) (i64.const 1) (i32.const 1)) (drop))) + "type mismatch" +) + +(assert_invalid + (module (func (unreachable) (select (i64.const 1) (i32.const 1) (i32.const 1)) (drop))) + "type mismatch" +) + +;; Third operand must be i32 +(assert_invalid + (module (func (unreachable) (select (i32.const 1) (i32.const 1) (i64.const 1)) (drop))) + "type mismatch" +) + +(assert_invalid + (module (func (unreachable) (select (i32.const 1) (i64.const 1)) (drop))) + "type mismatch" +) + +(assert_invalid + (module (func (unreachable) (select (i64.const 1)) (drop))) + "type mismatch" +) + +;; Result of select has type of first two operands (type of second operand when first one is omitted) +(assert_invalid + (module (func (result i32) (unreachable) (select (i64.const 1) (i32.const 1)))) + "type mismatch" +) + +;; select always has non-empty result +(assert_invalid + (module (func (unreachable) (select))) + "type mismatch" +) + From 54dde91068d926e0d36ec29a3c5f5e4a73fb5faf Mon Sep 17 00:00:00 2001 From: Andreas Rossberg Date: Thu, 11 Feb 2021 17:31:35 +0100 Subject: [PATCH 196/199] Undo repo-local modifications --- .travis.yml | 2 +- README.md | 32 ++++++------------------- deploy_key.enc | Bin 3392 -> 3248 bytes document/core/appendix/algorithm.rst | 4 ++-- document/core/appendix/index-types.rst | 2 +- document/core/index.rst | 2 +- document/core/util/macros.def | 8 +++---- 7 files changed, 16 insertions(+), 34 deletions(-) diff --git a/.travis.yml b/.travis.yml index 912dbaac1a..403e9dc254 100644 --- a/.travis.yml +++ b/.travis.yml @@ -34,5 +34,5 @@ os: linux env: global: - - ENCRYPTION_LABEL: "5d9ec396f41d" + - ENCRYPTION_LABEL: "304454be9d6c" - COMMIT_AUTHOR_EMAIL: "noreply@webassembly.org" diff --git a/README.md b/README.md index 2edd9039af..83cdc4da6a 100644 --- a/README.md +++ b/README.md @@ -1,32 +1,14 @@ -[![Build Status](https://travis-ci.org/WebAssembly/reference-types.svg?branch=master)](https://travis-ci.org/WebAssembly/reference-types) - -# Reference Types Proposal for WebAssembly - -This repository is a clone of [github.com/WebAssembly/spec/](https://github.com/WebAssembly/spec/). -It is meant for discussion, prototype specification and implementation of a proposal to add support for basic reference types to WebAssembly. - -* See the [overview](proposals/reference-types/Overview.md) for a summary of the proposal. - -* See the [modified spec](https://webassembly.github.io/reference-types/core/) for details. - -The repository is now based on the [bulk operations proposal](proposals/bulk-memory-operations/Overview.md) and includes all respective changes. - -Original README from upstream repository follows... +[![Build Status](https://travis-ci.org/WebAssembly/spec.svg?branch=master)](https://travis-ci.org/WebAssembly/spec) # spec -This repository holds a prototypical reference implementation for WebAssembly, -which is currently serving as the official specification. Eventually, we expect -to produce a specification either written in human-readable prose or in a formal -specification language. - -It also holds the WebAssembly testsuite, which tests numerous aspects of -conformance to the spec. - -View the work-in-progress spec at [webassembly.github.io/spec](https://webassembly.github.io/spec/). +This repository holds the sources for the WebAssembly draft specification +(to seed a future +[WebAssembly Working Group](https://lists.w3.org/Archives/Public/public-new-work/2017Jun/0005.html)), +a reference implementation, and the official testsuite. -At this time, the contents of this repository are under development and known -to be "incomplet and inkorrect". +A formatted version of the spec is available here: +[webassembly.github.io/spec](https://webassembly.github.io/spec/), Participation is welcome. Discussions about new features, significant semantic changes, or any specification change likely to generate substantial discussion diff --git a/deploy_key.enc b/deploy_key.enc index bc508e387eea50920c7cc404c8f6cf497c9fce9f..b6d3e2f19771652a9711760b1712a77fe1b4e579 100644 GIT binary patch literal 3248 zcmV;h3{UeoaMr!6kTNmX>{8Y#<|(CVbO6TJr-;79Ag-eBM!B~g(FTQ5ldW}>C6w#F z7?FSyFeYZ$v_V^lQFEF>+7k9B7m`7vS_SQ$;wWv|QOclL{NpaXb;g5ti(%WUt|3;5 z3CA#OrS)XS){2AUta7q}MSmhTJq zo{c?28()!ibPsqvTfOAA!4zOONU^F*gLcD(DrJbnNphXRZ3yC#LaPJi{CC$C(2A_7 zNaF$Iwo+ftMAzTpRFW1@B>=0mk{V^}DS!4rt3&v*?r8!}EfiTzY#jX?%ckauU9h@W zx(fD`Pk=~T7D1zi5Xgo-F3df<=bCbjU0(ZD&z`12ST)Xxn<2-%!cB^F0IoG~-*{lROB{l$8;> zQYD6uvZB!WjR97=Gm5k(nd?fS-skc&EK?_V8WnS+v(_4N1NbVfWy{T9c3+w+eKW@y z`gzb1V%Tr>ul(ay+I}7y2o4<>nNeC`_9<4dQwbaZcv=lR5j&@)QY$OIg__IEl?CzP zj*w)N-7!X;zax-wu2%HYpX17nK^l2cLppXhM>Q8<9AmF4V+?wF~S-rGWRU;<& zEfi}`>wt%Un_w@H!oNoZ>x+M|o6OWL0ZWAvCDS3ci~T8hKI0BHLyhmaX>a@YdQNK^9SJORstB zfvrm3TfM$`MMQQXp+4m=U~?Y#8>LXJEJKe+QT3ai?lI{90Zbd!SJdk4H(U1tebkQS zElH@QyluL-tMcF~ED_;l>!0Ijv*4gtnDwmLYV{a3@tjZ`D zFgG=OkZ90lfbv6>Fy&2v?b=c~Y_N9G zUi9};vfpk;9dPn4FMkaR{o~nn&h!a-?Sdb%SZ)!fI~GWnk~X{F~0*MZTR*=jmm-h1@t zDL!$f-TC0j9#3k6yGm=yVm`^%@wfi3bq#*03KSe>$d+&xjHOcMc8uJt8)hN2{SBal z4ob$b$`dj=o#p1YnW?UI^yZ;rkMjLI{F#<8G09bp2NC-f7?!MtUZ(JwIdFlSzu%EdX7u+as(dHl z58QQZ`uk&2UcuOD{=l^SW7lbUC)YQxLZoD(4yfjbALj)ocgYIM0ZYz?(TpdH^*N^lP&fD?>5S3l5d9vDe0MYX}=L@v0ac*d^h zMC3X&i8_TGc*nis1+Hbb@FGCYM0^b7+Ks%np4Yi`?%nMjTjK}kiD^peA^u+*e>(aKEP(B~>~mZq#KO^e z%~M*@SsY^h6(tY`GdMou`@})%F*bIbRNZ>mC~Kmlo-i?%UtfW#dT*z*RcdL zpk60TCgJqxKBvX~s$%Shh(AI%*I`@P2!X_@lhC_lv0_yIg6%&*TKAQRPZQNW>=_H-#1pBvjD+m{Zb}zcH8nbpNqr9whn4 zA=y)BHKQ-DrD~ATW$s5sLj-tJ#cf~=mO{+4YNwZc;4(}zeG0i5iXTW*#VVOL90%~C zVKMQHgk?j=XH43>K+-CeY3%JXI)VIB$Ad;DSsk-VJs=GfjP+|s{r){_ozCKbFDNi| zfEk3yUlIo}(x+SiFz(8%;%1%!B5`O|M9Tgg3bui&lu)v`(ydUn{aib=ktlW8MU&;r zQ+2LIr_4e3%GTLQ5?58orh7HmWd&Z&T0Uz!9~Ha`K^gp=fQ`FR=0~z|>MuzT4#e%& zBXJPHh`^tE;|zIgNiR(*kU@PB&}J%3Coh;M^QnC8vP7h%*_Gozd?$RZWr_#dXYF>u zT>^8L;b}KO+gPONfMBv1ae%Hy6R+;S^w+Ng{zo&nGB`o<^fxC>{v`=!WnoSACN9e? z!P}dgK-N^z=5p%- zjAkKdA-dFrZxs{<7wntcycPzJOC})W{%YX>7&0{p8S%XXI0{sJi2me-X!z#kb@^(L zIrTxbTFMXTi!+maqh2OdhC54A&#rQ{4~>UL|6E*af1FP^b#OX~#=VRt;}}z+FhX7& z(?0)PAKjGZ*g(dZNg81514!QK;bQWS0-qDq&xgnv8vdcEkLzW9YdU7Q`jSwWHd*~b zqQ?O;jM%iLY>Zw*$r*lZ~?dz)vtCi6GqzmKd+b z!(zZgpXf?*+wbzsxQ&XJ3)2p#3|IEa$pe0b>QbH=rr|j)yS-i=SFADE7tJ`oCmN@} zL{UA^mr)_ZWdcbz>BGLSKFnFY^oV4EXulUCv6iQUG?d~nuNbxQiWI`F1pbLxAfG^h iY#Pu|2q&8>`3}#6q-2Cz`ZEbT?K&=q;2asiqpF?e?>4gl literal 3392 zcmV-G4Zre-1eU8xvN4;5I3;(DE@)0{e0SCBdLRQs8epBMI1_fo)FX|N>d+zrdiZ~> zx`Gd4>x7V^5Qt`|DC*MaEIHK<@j}L3aw=&nIr#lM-4=9OLRx8-K*Mv9{jWsUi^1Jw zB0$v$s{tXY^K|pmj-}{=(g(f~@LZ4b3v~yF4oYh4QM~&Ld~DIa10oMwRLeBr$hug= zTMm&yA6<8EmkG_yJsXhWn~#F)A2%xJ3Rx?SJ`Y~QU_mU1#wTUyF&L#O1hE6O`rM(U zsTG9Ca0fz#Y~53tYAAu-?O-T$P@9&AMiVP+SP-=TRI&{SUp&MH~Y0$G@`byHr9+LuELgDlt0%+D^Bu z2^d2JqkWB*MD{uI1nb5@G&Tje>=8@~FFtC9u3y0~u26O|I%~ns9sg}*{GjeRAVq!E zgJ@Xa5F{|2L7A)!Hp8HBoIDK{o`UzqlxtrTpPV zpaqUm&*uRPFNd7c86F)&H1^Zo)8a?n-?_Co9v4Cej&C2nG#kB1XB(QmA+PaB%L{W9 zU12y&!Md}DhSrGuX?w`WBhkiA8rhVSPa3X~3nNQ~gEc${9!dl-aGDn`k}C)eR9te( z5dtbId8TF0Dj|MIL9hzr!4Pq6&k(<{4n3driiKr(gN(@d3E9m5(a4ToRv5Vn8)&6= z-Kq2ZKv^O3ve2v&J44Qy8ApM-b2LsF8_W1#>$|9BLRvA2otB%cFkJ+fDoQnrYr%b# zZ=Y7!EDRkQum}D5Mqddm=`IXE50Bx9*gBCGo5UaDxXK?Np}gJ|?<4c8>cz)v3=`M^ zPBS_M@af>g>-e2wGMFRi4YCrDIDL8gM{2FVnX|+WQ^*JYWb&`b_CT=E&|fCM62={n zAAoZgJZ)+UfL}397h`BvmGe>j;#*PUqV@gWfQ^dFK5vq`F~}rPh1a1CzjSeMVv~mG zKPY)qrP5TXTMY{q7ZNqpRX;R!DjH?0JLmTXZXkcz z2_L(RC|vtGaJ?Gjy<0%Y-$c{n#S^ki3*Qx0Ox4sk9>0)fNc$(+J1&K=;GqpA0RnM- zxZlvp^zH9lN`Kin5YQC}O6EayqP%uwhjrQ=b;iD|SWKg;$Wwt{2Db%YQ31G3lmQCe z%Kgn}qIEqL5M14-B%sC1l3#6@>X6(IkjMWAZF-g4J9Nb=*Sj!ZDrr+A9o|LiSe-1l zJ4)nK$Y4bW4d}3EP{)>xS$Txs5pSwdztv6DRL}bdz{vS4fO^Y+l@ct~b5FdQ-z}Z; z!*Gz(?8V}6Jj8?Kzf>l?sR+p87_ijJ)+3yzn^}e0-0F%3Cy8bYlIB&I6G-ZsJsO?wV@Kffd?yu4h;)w;*CH?GSuI)=l9Y(Kr9(Sf<5aY( zV56=nDo6G7++ITu4V!2IL>+jp+;RUip$3~W=nY{lW!_@WtZ@u|fNzHvQCPP+$(_1? z#supPCUpBzF&iA8M5ZvxIqlZBg&8Y4?H^2+-j40wxbgaC4=0Lq`2~ z1=|Koz@4$>sqx>Y(L1AtGke5@Ll7b3Asau=Ld zI-|h>cX_%TG%u{9gyX8UO=l=Ii5y0>&!PlcLJnf(`TJ5H`YD|a|vs^B^AmweIoKj(vzV(jz99C-@7pbovPk| z;s?TR1>#aE!@(xtvt(iYQ4gZ1TrKhJ?c|w~a>veS3f4ElrEWxCzlF_c*!s>KAiCnK zh$z5r?IVT(n&hKjz!(?wPU1l5Uw>=<;*E_Pd>Cef@MNG*N-Ym^5~701fwZV zpq*bD2aW59j)=8b6;_0Et)-OjU$Fbsn1(^E(+l?FeQSh*(*TXR#J8#gN^31!#p-~? zHQ;5*$nQ1>i1v^kYyfdpJU>_Ysfxj|_8!xE-t!7FFqiz)%n$48GGAGUCn(zgWGAW( zG8ay#OfA~oOS5Dyjk65u1a@3p%sL#}L8@~xv|f{RBH(l1y}DAVXo@Rui!tvA@Z~Gu zl}+IhoLs41r)^@#Lze7N9TdJb2spiUk2dNC%n=YOr!vR;Yl0|yO09ds+-cH`D)vaE z1v!qxpoZppMyu>8Vpc@y6>Q7|%YhJXKh8T9K zhSRh=I1c$nP`nt^|K^utvTV4L^DTt<#6^JgSMhu& zdA|C{$E^Ko)v0FnhEv_CPzum~!Em$m2Jlwx`sA7g>umP-R|zU+))pg`PQeI7db=BE z$CI-s*=pZE7L%?tKPV*o;;ugBYrHB13NMPwZ>Vy;`UBB7ouqJ$fU*VD=^WjkXusYn zd+ppoN&DS~9t@!C<-|3oKDF5#;rmyE4Tc)cd6He9{mDOmEzM2wmcsQc1}QVBU4znN zP6`TKklseZdt=a2eFh_Jq?A3lq4MQUpF(*1uRT0q?V^p|eHlQgF*m2ja-UfPwO;vn z=-poco1^T_8Ee1s@=lDd3%fw5wyq=UjbL00Uh0K&2c^bNL#2Bqtgfh2{$KY22ctQ? ziz3X*<6V}TYM3rMep2t@$|m(cQMx338V#D1c8eXXaqkM}6ZyT@`8JOc#&bq}hO>|Q zmt9fU5Y|6ZU)Yz1*1`*#7!^ir0Mfj4Yd1dYYTN9=S@*8K?9D& z)p=b4$}NATK!y~?@X4cYX}*jq9C>t51$kFRI=WCCW|(k;Jdzb`+xI!ywFu3kuajsi zFQcE=c{BSs|CQ3vIO=^%l|}&0Z~X$&eQh72pO)s@Ydp-b!<9r@!hJMy`>Zk`@3wQO z-hc6!4Bz=Bg@S9YITy({RG>}Od{F!_0aHNNQ45(dwHjN~ zI>>EYkD^UYvtei^@+Eh?CRjxU6Fs-ghC=euQu$yKNYG*&!^hV21@e#7KmgpIWj#Fk ziY)6z!@)y%w^WH5$XwyAV1lvSN{^WuJX`Z{TuwHGET%lt%8GzP7C0#^+mYD(b&we^(}7uMiV5K>6N&)SV~t+-VL)v*-;G>yR{)mwSJEEpp-%yzUa{VlOoH5i76DKu z(R2rRi%cLSOM(xRiri_Ois7B#0Lf*i_T+C4!sK9qBC4 zJpyJEy|&o;+k6oKn8n{{f^G$+dzMHux@ z&{=k$F76t1_fVjtFp>xCA_bhTOxsA@+^xkQI-ilbK~Bt4m79C_i%?T9PaFwm^>tlY zp}Bg?=~i5~_nh}y7%=LxF0j=+7x@B_1ytkLyE(8hb`B;H3+e~;G4++&^6yiSj3t>% zdA>31Lvqaea1ITQZg-*A(Xi211Z=6TaETLefV_aT;iZr6cAtr7W7 zB5P8Vi<2x4TEErGY0wU|QImYlF@Q1QB8|LxppoK1r-yozGI^M0SFO*q79Z{U!G84F zsj533ewayE?A+gxVpXQkW8-hHT{Odd=oD6vAB9w;5b>NMG2^8%AG)HOJX903z1vdr zq^sudDd{_OuzV6R^`d(*h|O;`FtvfBLAEM3AHP0` zvA2&;LK-@4n+=Y9NK+Jo-;BV{2ol%626HoRa;fnhFCIrHWX80-J=bjjo!1y%fh}v? z@|zy4|IOoDa*q_uZ8bXBh{AKX#lz<2fig()ju#udilU5p<+wgBao_T&!ua` :math:`[\valtype^\ast] \to [\valtype^\ast]` :math:`\hex{60}` (-32 as |Bs7|) (reserved) :math:`\hex{5F}` .. :math:`\hex{41}` -:ref:`Result type ` :math:`[\epsilon]` :math:`\hex{40}` (-64 as |Bs7|) +:ref:`Result type ` :math:`[\epsilon]` :math:`\hex{40}` (-64 as |Bs7|) :ref:`Table type ` :math:`\limits~\reftype` (none) :ref:`Memory type ` :math:`\limits` (none) :ref:`Global type ` :math:`\mut~\valtype` (none) diff --git a/document/core/index.rst b/document/core/index.rst index 139a05b04e..1d8d6a4aa1 100644 --- a/document/core/index.rst +++ b/document/core/index.rst @@ -3,7 +3,7 @@ WebAssembly Specification .. only:: html - | Release |release| + bulk instructions + reference types (Draft, |today|) + | Release |release| (Draft, |today|) | Editor: Andreas Rossberg diff --git a/document/core/util/macros.def b/document/core/util/macros.def index 4e5b534c09..82928c6f80 100644 --- a/document/core/util/macros.def +++ b/document/core/util/macros.def @@ -3,11 +3,11 @@ .. External Standards .. ------------------ -.. |WasmDraft| replace:: https://webassembly.github.io/reference-types/core/ -.. _WasmDraft: https://webassembly.github.io/reference-types/core/ +.. |WasmDraft| replace:: https://webassembly.github.io/spec/core/ +.. _WasmDraft: https://webassembly.github.io/spec/core/ -.. |WasmIssues| replace:: https://github.com/webassembly/reference-types/issues/ -.. _WasmIssues: https://github.com/webassembly/reference-types/issues/ +.. |WasmIssues| replace:: https://github.com/webassembly/spec/issues/ +.. _WasmIssues: https://github.com/webassembly/spec/issues/ .. |IEEE754| replace:: IEEE 754-2019 .. _IEEE754: https://ieeexplore.ieee.org/document/8766229 From 1dca287b2926f721b9b2e3a0b4630d7c9bf9678a Mon Sep 17 00:00:00 2001 From: Andreas Rossberg Date: Wed, 10 Mar 2021 16:59:18 +0100 Subject: [PATCH 197/199] Makefile and other minor tweaks --- interpreter/Makefile | 22 +++++++++++++++++----- interpreter/exec/eval.ml | 10 +++++++--- interpreter/syntax/ast.ml | 2 +- interpreter/syntax/free.ml | 8 ++++++-- interpreter/syntax/operators.ml | 5 +++-- interpreter/valid/valid.ml | 2 +- 6 files changed, 35 insertions(+), 14 deletions(-) diff --git a/interpreter/Makefile b/interpreter/Makefile index c745311b9d..2cf0a4febd 100644 --- a/interpreter/Makefile +++ b/interpreter/Makefile @@ -20,7 +20,8 @@ WINMAKE = winmake.bat DIRS = util syntax binary text valid runtime exec script host main LIBS = bigarray FLAGS = -lexflags -ml -cflags '-w +a-4-27-42-44-45 -warn-error +a-3' -OCB = ocamlbuild $(FLAGS) $(DIRS:%=-I %) $(LIBS:%=-libs %) +OCBA = ocamlbuild $(FLAGS) $(DIRS:%=-I %) +OCB = $(OCBA) $(LIBS:%=-libs %) JS = # set to JS shell command to run JS tests @@ -32,8 +33,8 @@ default: opt debug: unopt opt: $(OPT) unopt: $(UNOPT) -libopt: _build/$(LIB).cmx -libunopt: _build/$(LIB).cmo +libopt: _build/$(LIB).cmx _build/$(LIB).cmxa +libunopt: _build/$(LIB).cmo _build/$(LIB).cma jslib: $(JSLIB) all: unopt opt libunopt libopt test land: $(WINMAKE) all @@ -68,6 +69,7 @@ main.native: _tags # Building library +FILES = $(shell ls $(DIRS:%=%/*.ml*)) PACK = $(shell echo `echo $(LIB) | sed 's/^\(.\).*$$/\\1/g' | tr [:lower:] [:upper:]``echo $(LIB) | sed 's/^.\(.*\)$$/\\1/g'`) .INTERMEDIATE: $(LIB).mlpack @@ -78,12 +80,22 @@ $(LIB).mlpack: $(DIRS) | sort | uniq \ >$@ -_build/$(LIB).cmo: $(LIB).mlpack _tags +.INTERMEDIATE: $(LIB).mllib +$(LIB).mllib: + echo Wasm >$@ + +_build/$(LIB).cmo: $(FILES) $(LIB).mlpack _tags Makefile $(OCB) -quiet $(LIB).cmo -_build/$(LIB).cmx: $(LIB).mlpack _tags +_build/$(LIB).cmx: $(FILES) $(LIB).mlpack _tags Makefile $(OCB) -quiet $(LIB).cmx +_build/$(LIB).cma: $(FILES) $(LIB).mlpack _tags Makefile + $(OCBA) -quiet $(LIB).cma + +_build/$(LIB).cmxa: $(FILES) $(LIB).mlpack _tags Makefile + $(OCBA) -quiet $(LIB).cmxa + # Building JavaScript library diff --git a/interpreter/exec/eval.ml b/interpreter/exec/eval.ml index 0db5a228a9..4a0134dd94 100644 --- a/interpreter/exec/eval.ml +++ b/interpreter/exec/eval.ml @@ -273,7 +273,7 @@ let rec step (c : config) : config = vs', [Trapping (table_error e.at Table.Bounds) @@ e.at] else if n = 0l then vs', [] - else if d <= s then + else if I32.le_u d s then vs', List.map (at e.at) [ Plain (Const (I32 d @@ e.at)); Plain (Const (I32 s @@ e.at)); @@ -373,7 +373,7 @@ let rec step (c : config) : config = vs', [Trapping (memory_error e.at Memory.Bounds) @@ e.at] else if n = 0l then vs', [] - else if d <= s then + else if I32.le_u d s then vs', List.map (at e.at) [ Plain (Const (I32 d @@ e.at)); Plain (Const (I32 s @@ e.at)); @@ -607,7 +607,11 @@ let create_data (inst : module_inst) (seg : data_segment) : data_inst = let add_import (m : module_) (ext : extern) (im : import) (inst : module_inst) : module_inst = if not (match_extern_type (extern_type_of ext) (import_type m im)) then - Link.error im.at "incompatible import type"; + Link.error im.at ("incompatible import type for " ^ + "\"" ^ Utf8.encode im.it.module_name ^ "\" " ^ + "\"" ^ Utf8.encode im.it.item_name ^ "\": " ^ + "expected " ^ Types.string_of_extern_type (import_type m im) ^ + ", got " ^ Types.string_of_extern_type (extern_type_of ext)); match ext with | ExternFunc func -> {inst with funcs = func :: inst.funcs} | ExternTable tab -> {inst with tables = tab :: inst.tables} diff --git a/interpreter/syntax/ast.ml b/interpreter/syntax/ast.ml index 38e5506256..d258986ea6 100644 --- a/interpreter/syntax/ast.ml +++ b/interpreter/syntax/ast.ml @@ -106,8 +106,8 @@ and instr' = | MemoryInit of var (* initialize memory range from segment *) | DataDrop of var (* drop passive data segment *) | RefNull of ref_type (* null reference *) - | RefIsNull (* null test *) | RefFunc of var (* function reference *) + | RefIsNull (* null test *) | Const of num (* constant *) | Test of testop (* numeric test *) | Compare of relop (* numeric comparison *) diff --git a/interpreter/syntax/free.ml b/interpreter/syntax/free.ml index 33bfefc0aa..60d5803340 100644 --- a/interpreter/syntax/free.ml +++ b/interpreter/syntax/free.ml @@ -59,14 +59,18 @@ let shift s = Set.map (Int32.add (-1l)) (Set.remove 0l s) let (++) = union let list free xs = List.fold_left union empty (List.map free xs) +let block_type = function + | VarBlockType x -> types (var x) + | ValBlockType _ -> empty + let rec instr (e : instr) = match e.it with | Unreachable | Nop | Drop | Select _ -> empty | RefNull _ | RefIsNull -> empty | RefFunc x -> funcs (var x) | Const _ | Test _ | Compare _ | Unary _ | Binary _ | Convert _ -> empty - | Block (_, es) | Loop (_, es) -> block es - | If (_, es1, es2) -> block es1 ++ block es2 + | Block (bt, es) | Loop (bt, es) -> block_type bt ++ block es + | If (bt, es1, es2) -> block_type bt ++ block es1 ++ block es2 | Br x | BrIf x -> labels (var x) | BrTable (xs, x) -> list (fun x -> labels (var x)) (x::xs) | Return -> empty diff --git a/interpreter/syntax/operators.ml b/interpreter/syntax/operators.ml index 2b80b627c9..d8467a5950 100644 --- a/interpreter/syntax/operators.ml +++ b/interpreter/syntax/operators.ml @@ -8,9 +8,8 @@ let i32_const n = Const (I32 n.it @@ n.at) let i64_const n = Const (I64 n.it @@ n.at) let f32_const n = Const (F32 n.it @@ n.at) let f64_const n = Const (F64 n.it @@ n.at) -let ref_func x = RefFunc x let ref_null t = RefNull t -let ref_is_null = RefIsNull +let ref_func x = RefFunc x let unreachable = Unreachable let nop = Nop @@ -89,6 +88,8 @@ let memory_copy = MemoryCopy let memory_init x = MemoryInit x let data_drop x = DataDrop x +let ref_is_null = RefIsNull + let i32_clz = Unary (I32 I32Op.Clz) let i32_ctz = Unary (I32 I32Op.Ctz) let i32_popcnt = Unary (I32 I32Op.Popcnt) diff --git a/interpreter/valid/valid.ml b/interpreter/valid/valid.ml index be8097ea8b..67c46d6464 100644 --- a/interpreter/valid/valid.ml +++ b/interpreter/valid/valid.ml @@ -38,7 +38,7 @@ let empty_context = let lookup category list x = try Lib.List32.nth list x.it with Failure _ -> - error x.at ("unknown " ^ category ^ " " ^ Int32.to_string x.it) + error x.at ("unknown " ^ category ^ " " ^ I32.to_string_u x.it) let type_ (c : context) x = lookup "type" c.types x let func (c : context) x = lookup "function" c.funcs x From 38b0c57cae13a953ac9de581c973d4fc3f0366a2 Mon Sep 17 00:00:00 2001 From: Andreas Rossberg Date: Wed, 10 Mar 2021 18:09:21 +0100 Subject: [PATCH 198/199] Update algorithm.rst --- document/core/appendix/algorithm.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/document/core/appendix/algorithm.rst b/document/core/appendix/algorithm.rst index bd86ee4f18..b85f210631 100644 --- a/document/core/appendix/algorithm.rst +++ b/document/core/appendix/algorithm.rst @@ -229,7 +229,7 @@ Other instructions are checked in a similar manner.         error_if(label_types(ctrls[n]).size() =/= arity) push_vals(pop_vals(label_types(ctrls[n]))) pop_vals(label_types(ctrls[m])) -       unreachable() +       unreachable() .. note:: From fa006af9ca14860d936d5a433b22ddc7bd1edd65 Mon Sep 17 00:00:00 2001 From: Andreas Rossberg Date: Wed, 10 Mar 2021 19:03:17 +0100 Subject: [PATCH 199/199] Fix test failures from merge --- document/core/appendix/algorithm.rst | 2 +- test/core/global.wast | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/document/core/appendix/algorithm.rst b/document/core/appendix/algorithm.rst index b85f210631..bd86ee4f18 100644 --- a/document/core/appendix/algorithm.rst +++ b/document/core/appendix/algorithm.rst @@ -229,7 +229,7 @@ Other instructions are checked in a similar manner.         error_if(label_types(ctrls[n]).size() =/= arity) push_vals(pop_vals(label_types(ctrls[n]))) pop_vals(label_types(ctrls[m])) -       unreachable() +       unreachable() .. note:: diff --git a/test/core/global.wast b/test/core/global.wast index 7be028c9f5..9fa5e22311 100644 --- a/test/core/global.wast +++ b/test/core/global.wast @@ -218,14 +218,14 @@ (assert_return (invoke "get-7") (f32.const 8)) (assert_return (invoke "get-8") (f64.const 9)) -(assert_return (invoke "set-5" (f32.const 8))) -(assert_return (invoke "set-6" (f64.const 9))) +(assert_return (invoke "set-7" (f32.const 8))) +(assert_return (invoke "set-8" (f64.const 9))) (assert_return (invoke "set-mr" (ref.extern 10))) (assert_return (invoke "get-x") (i32.const 6)) (assert_return (invoke "get-y") (i64.const 7)) -(assert_return (invoke "get-5") (f32.const 8)) -(assert_return (invoke "get-6") (f64.const 9)) +(assert_return (invoke "get-7") (f32.const 8)) +(assert_return (invoke "get-8") (f64.const 9)) (assert_return (invoke "get-mr") (ref.extern 10)) (assert_return (invoke "as-select-first") (i32.const 6))