diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml
index 145d6b7c..7bc79de5 100644
--- a/.github/workflows/main.yml
+++ b/.github/workflows/main.yml
@@ -9,7 +9,9 @@ jobs:
matrix:
rust: [stable, beta, nightly]
steps:
- - uses: actions/checkout@master
+ - uses: actions/checkout@v1
+ with:
+ submodules: true
- name: Install Rust
run: rustup update ${{ matrix.rust }} && rustup default ${{ matrix.rust }}
- name: Install wabt
diff --git a/crates/macro/src/lib.rs b/crates/macro/src/lib.rs
index dc3eba51..ed2ab073 100755
--- a/crates/macro/src/lib.rs
+++ b/crates/macro/src/lib.rs
@@ -561,6 +561,12 @@ fn create_visit(variants: &[WalrusVariant]) -> impl quote::ToTokens {
// ...
}
+ /// Visit `ElementId`
+ #[inline]
+ fn visit_element_id(&mut self, elem: &crate::ElementId) {
+ // ...
+ }
+
/// Visit `Value`.
#[inline]
fn visit_value(&mut self, value: &crate::ir::Value) {
@@ -645,6 +651,12 @@ fn create_visit(variants: &[WalrusVariant]) -> impl quote::ToTokens {
// ...
}
+ /// Visit `ElementId`
+ #[inline]
+ fn visit_element_id_mut(&mut self, elem: &mut crate::ElementId) {
+ // ...
+ }
+
/// Visit `Value`.
#[inline]
fn visit_value_mut(&mut self, value: &mut crate::ir::Value) {
diff --git a/crates/tests/tests/round_trip/elem-segments-1.wat b/crates/tests/tests/round_trip/elem-segments-1.wat
index 8b348403..b63c226a 100644
--- a/crates/tests/tests/round_trip/elem-segments-1.wat
+++ b/crates/tests/tests/round_trip/elem-segments-1.wat
@@ -5,4 +5,11 @@
(export "foo" (table 0))
)
-;; CHECK: (elem (;0;) (i32.const 1) 0)
+(; CHECK-ALL:
+ (module
+ (type (;0;) (func))
+ (func (;0;) (type 0))
+ (table (;0;) 1 funcref)
+ (export "foo" (table 0))
+ (elem (;0;) (i32.const 1) func 0))
+;)
diff --git a/crates/tests/tests/round_trip/elem-segments-2.wat b/crates/tests/tests/round_trip/elem-segments-2.wat
index 350a9622..58ccbd68 100644
--- a/crates/tests/tests/round_trip/elem-segments-2.wat
+++ b/crates/tests/tests/round_trip/elem-segments-2.wat
@@ -6,4 +6,12 @@
(export "foo" (table 0))
)
-;; CHECK: (elem (;0;) (i32.const 1) 0 0)
+(; CHECK-ALL:
+ (module
+ (type (;0;) (func))
+ (func (;0;) (type 0))
+ (table (;0;) 1 funcref)
+ (export "foo" (table 0))
+ (elem (;0;) (i32.const 1) func 0)
+ (elem (;1;) (i32.const 2) func 0))
+;)
diff --git a/crates/tests/tests/round_trip/elem-segments-3.wat b/crates/tests/tests/round_trip/elem-segments-3.wat
index 9a42a6e4..6870b07c 100644
--- a/crates/tests/tests/round_trip/elem-segments-3.wat
+++ b/crates/tests/tests/round_trip/elem-segments-3.wat
@@ -6,5 +6,12 @@
(export "foo" (table 0))
)
-;; CHECK: (elem (;0;) (i32.const 1) 0)
-;; NEXT: (elem (;1;) (i32.const 3) 0)
+(; CHECK-ALL:
+ (module
+ (type (;0;) (func))
+ (func (;0;) (type 0))
+ (table (;0;) 1 funcref)
+ (export "foo" (table 0))
+ (elem (;0;) (i32.const 1) func 0)
+ (elem (;1;) (i32.const 3) func 0))
+;)
diff --git a/crates/tests/tests/round_trip/keep-elem-segments.wat b/crates/tests/tests/round_trip/keep-elem-segments.wat
index 9eb9375e..8ee8ed6b 100644
--- a/crates/tests/tests/round_trip/keep-elem-segments.wat
+++ b/crates/tests/tests/round_trip/keep-elem-segments.wat
@@ -13,13 +13,14 @@
(export "foo" (func 0))
)
-;; CHECK: (module
-;; NEXT: (type (;0;) (func))
-;; NEXT: (func (;0;) (type 0)
-;; NEXT: i32.const 0
-;; NEXT: call_indirect (type 0))
-;; NEXT: (func (;1;) (type 0))
-;; NEXT: (table (;0;) 1 1 funcref)
-;; NEXT: (export "foo" (func 0))
-;; NEXT: (elem (;0;) (i32.const 0) 1))
-
+(; CHECK-ALL:
+ (module
+ (type (;0;) (func))
+ (func (;0;) (type 0)
+ i32.const 0
+ call_indirect (type 0))
+ (func (;1;) (type 0))
+ (table (;0;) 1 1 funcref)
+ (export "foo" (func 0))
+ (elem (;0;) (i32.const 0) func 1))
+;)
diff --git a/crates/tests/tests/round_trip/simd.wat b/crates/tests/tests/round_trip/simd.wat
index 78cec071..d081fffc 100644
--- a/crates/tests/tests/round_trip/simd.wat
+++ b/crates/tests/tests/round_trip/simd.wat
@@ -502,12 +502,6 @@
(func $i32x4_trunc_u_f32x4_sat (export "i32x4_trunc_u_f32x4_sat") (param v128) (result v128)
local.get 0
i32x4.trunc_sat_f32x4_u)
- (func $i64x2_trunc_s_f64x2_sat (export "i64x2_trunc_s_f64x2_sat") (param v128) (result v128)
- local.get 0
- i64x2.trunc_sat_f64x2_s)
- (func $i64x2_trunc_u_f64x2_sat (export "i64x2_trunc_u_f64x2_sat") (param v128) (result v128)
- local.get 0
- i64x2.trunc_sat_f64x2_u)
(func $f32x4.convert_i32x4_s (export "f32x4.convert_i32x4_s") (param v128) (result v128)
local.get 0
@@ -515,12 +509,6 @@
(func $f32x4.convert_i32x4_u (export "f32x4.convert_i32x4_u") (param v128) (result v128)
local.get 0
f32x4.convert_i32x4_u)
- (func $f64x2.convert_i64x2_s (export "f64x2.convert_i64x2_s") (param v128) (result v128)
- local.get 0
- f64x2.convert_i64x2_s)
- (func $f64x2.convert_i64x2_u (export "f64x2.convert_i64x2_u") (param v128) (result v128)
- local.get 0
- f64x2.convert_i64x2_u)
)
(; CHECK-ALL:
@@ -1015,24 +1003,12 @@
(func $i32x4_trunc_u_f32x4_sat (type 10) (param v128) (result v128)
local.get 0
i32x4.trunc_sat_f32x4_u)
- (func $i64x2_trunc_s_f64x2_sat (type 10) (param v128) (result v128)
- local.get 0
- i64x2.trunc_sat_f64x2_s)
- (func $i64x2_trunc_u_f64x2_sat (type 10) (param v128) (result v128)
- local.get 0
- i64x2.trunc_sat_f64x2_u)
(func $f32x4.convert_i32x4_s (type 10) (param v128) (result v128)
local.get 0
f32x4.convert_i32x4_s)
(func $f32x4.convert_i32x4_u (type 10) (param v128) (result v128)
local.get 0
f32x4.convert_i32x4_u)
- (func $f64x2.convert_i64x2_s (type 10) (param v128) (result v128)
- local.get 0
- f64x2.convert_i64x2_s)
- (func $f64x2.convert_i64x2_u (type 10) (param v128) (result v128)
- local.get 0
- f64x2.convert_i64x2_u)
(func $v128.const (type 0) (result v128)
v128.const i32x4 0x00000001 0x00000002 0x00000003 0x00000004)
(memory (;0;) 0)
@@ -1164,10 +1140,6 @@
(export "f64x2.max" (func $f64x2.max))
(export "i32x4_trunc_s_f32x4_sat" (func $i32x4_trunc_s_f32x4_sat))
(export "i32x4_trunc_u_f32x4_sat" (func $i32x4_trunc_u_f32x4_sat))
- (export "i64x2_trunc_s_f64x2_sat" (func $i64x2_trunc_s_f64x2_sat))
- (export "i64x2_trunc_u_f64x2_sat" (func $i64x2_trunc_u_f64x2_sat))
(export "f32x4.convert_i32x4_s" (func $f32x4.convert_i32x4_s))
- (export "f32x4.convert_i32x4_u" (func $f32x4.convert_i32x4_u))
- (export "f64x2.convert_i64x2_s" (func $f64x2.convert_i64x2_s))
- (export "f64x2.convert_i64x2_u" (func $f64x2.convert_i64x2_u)))
+ (export "f32x4.convert_i32x4_u" (func $f32x4.convert_i32x4_u)))
;)
diff --git a/crates/tests/tests/round_trip/table-init.wast b/crates/tests/tests/round_trip/table-init.wast
index 3441660c..a5bc4771 100644
--- a/crates/tests/tests/round_trip/table-init.wast
+++ b/crates/tests/tests/round_trip/table-init.wast
@@ -5,10 +5,12 @@
(elem (global.get 0) 0)
(export "x" (table 0)))
-;; CHECK: (module
-;; NEXT: (type
-;; NEXT: (import "x" "y" (global (;0;) i32))
-;; NEXT: (func
-;; NEXT: (table
-;; NEXT: (export "x" (table 0))
-;; NEXT: (elem (;0;) (global.get 0) 0))
+(; CHECK-ALL:
+ (module
+ (type (;0;) (func))
+ (import "x" "y" (global (;0;) i32))
+ (func (;0;) (type 0))
+ (table (;0;) 1 funcref)
+ (export "x" (table 0))
+ (elem (;0;) (global.get 0) func 0))
+;)
diff --git a/crates/tests/tests/spec-tests.rs b/crates/tests/tests/spec-tests.rs
index 098080a1..c48b398a 100644
--- a/crates/tests/tests/spec-tests.rs
+++ b/crates/tests/tests/spec-tests.rs
@@ -28,13 +28,8 @@ fn run(wast: &Path) -> Result<(), anyhow::Error> {
Some("sign-extension-ops") => &["--enable-sign-extension"],
Some("multi-value") => &["--enable-multi-value"],
Some("nontrapping-float-to-int-conversions") => &["--enable-saturating-float-to-int"],
-
- // Currently wabt doesn't have support for `ref.host` which is used in
- // these tests.
- Some("reference-types") => return Ok(()),
-
- // Currently wabt has broken support for `ref.func` initializers
- Some("bulk-memory-operations") => return Ok(()),
+ Some("reference-types") => &["--enable-reference-types", "--enable-bulk-memory"],
+ Some("bulk-memory-operations") => &["--enable-bulk-memory"],
// TODO: should get threads working
Some("threads") => return Ok(()),
@@ -76,8 +71,12 @@ fn run(wast: &Path) -> Result<(), anyhow::Error> {
let path = tempdir.path().join(filename);
match command["type"].as_str().unwrap() {
"assert_invalid" | "assert_malformed" => {
- if command["text"].as_str().unwrap() == "invalid result arity" {
- // These tests are valid with multi-value!
+ // Skip tests that are actually valid with various in-flight proposals
+ let text = command["text"].as_str().unwrap();
+ if text == "invalid result arity"
+ || text == "multiple memories"
+ || text == "multiple tables"
+ {
continue;
}
let wasm = fs::read(&path)?;
@@ -89,6 +88,14 @@ fn run(wast: &Path) -> Result<(), anyhow::Error> {
if message.contains("invalid result arity") {
continue;
}
+
+ // MVP wasm considers this tests to fail, but
+ // reference-types-enhanced wasm considers this test to
+ // pass. We implement the reference-types semantics, so
+ // let's go forward with that.
+ if wast.ends_with("unreached-invalid.wast") && line == 539 {
+ continue;
+ }
panic!("wasm parsed when it shouldn't (line {})", line);
}
}
diff --git a/src/dot.rs b/src/dot.rs
index cd237720..7a710308 100644
--- a/src/dot.rs
+++ b/src/dot.rs
@@ -281,7 +281,6 @@ impl DotNode for Table {
fields.add_field(&[&format!("Table {:?}", self.id())]);
fields.add_field(&["initial", &self.initial.to_string()]);
fields.add_field(&["maximum", &format!("{:?}", self.maximum)]);
- fields.add_field(&["kind", &format!("{:?}", self.kind)]);
if self.import.is_some() {
fields.add_field_with_port("import", "import");
}
@@ -528,7 +527,9 @@ impl DotNode for Element {
fn edges(&self, edges: &mut impl EdgeAggregator) {
for m in self.members.iter() {
- edges.add_edge(m);
+ if let Some(m) = m {
+ edges.add_edge(m);
+ }
}
}
}
diff --git a/src/init_expr.rs b/src/init_expr.rs
index f17f5aeb..883362ca 100644
--- a/src/init_expr.rs
+++ b/src/init_expr.rs
@@ -3,7 +3,7 @@
use crate::emit::{Emit, EmitContext};
use crate::ir::Value;
use crate::parse::IndicesToIds;
-use crate::{GlobalId, Result};
+use crate::{FunctionId, GlobalId, Result};
use anyhow::bail;
/// A constant which is produced in WebAssembly, typically used in global
@@ -14,6 +14,10 @@ pub enum InitExpr {
Value(Value),
/// A constant value referenced by the global specified
Global(GlobalId),
+ /// A null reference
+ RefNull,
+ /// A function initializer
+ RefFunc(FunctionId),
}
impl InitExpr {
@@ -27,6 +31,8 @@ impl InitExpr {
F64Const { value } => InitExpr::Value(Value::F64(f64::from_bits(value.bits()))),
V128Const { value } => InitExpr::Value(Value::V128(v128_to_u128(&value))),
GlobalGet { global_index } => InitExpr::Global(ids.get_global(global_index)?),
+ RefNull => InitExpr::RefNull,
+ RefFunc { function_index } => InitExpr::RefFunc(ids.get_func(function_index)?),
_ => bail!("invalid constant expression"),
};
match reader.read()? {
@@ -47,6 +53,11 @@ impl Emit for InitExpr {
cx.encoder.byte(0x23); // global.get
cx.encoder.u32(idx);
}
+ InitExpr::RefNull => cx.encoder.byte(0xd0), // ref.null
+ InitExpr::RefFunc(id) => {
+ cx.encoder.byte(0xd2); // ref.func
+ cx.encoder.u32(cx.indices.get_func_index(id));
+ }
}
cx.encoder.byte(0x0b); // end
}
diff --git a/src/ir/mod.rs b/src/ir/mod.rs
index 270aac64..485a09d8 100644
--- a/src/ir/mod.rs
+++ b/src/ir/mod.rs
@@ -9,7 +9,8 @@ pub use self::traversals::*;
use crate::encode::Encoder;
use crate::{
- DataId, FunctionId, GlobalId, LocalFunction, MemoryId, ModuleTypes, TableId, TypeId, ValType,
+ DataId, ElementId, FunctionId, GlobalId, LocalFunction, MemoryId, ModuleTypes, TableId, TypeId,
+ ValType,
};
use id_arena::Id;
use std::fmt;
@@ -556,6 +557,28 @@ pub enum Instr {
#[walrus(skip_visit)]
arg: MemArg,
},
+
+ /// `table.init`
+ TableInit {
+ /// The table we're copying into.
+ table: TableId,
+ /// The element we're getting items from.
+ elem: ElementId,
+ },
+
+ /// `elem.drop`
+ ElemDrop {
+ /// The elem segment to drop
+ elem: ElementId,
+ },
+
+ /// `table.copy`
+ TableCopy {
+ /// The source table
+ src: TableId,
+ /// The destination table
+ dst: TableId,
+ },
}
/// Argument in `V128Shuffle` of lane indices to select
@@ -1177,6 +1200,9 @@ impl Instr {
| Instr::V128Shuffle(..)
| Instr::LoadSimd(..)
| Instr::AtomicFence(..)
+ | Instr::TableInit(..)
+ | Instr::TableCopy(..)
+ | Instr::ElemDrop(..)
| Instr::Drop(..) => false,
}
}
diff --git a/src/module/elements.rs b/src/module/elements.rs
index 63403654..dbf233c2 100644
--- a/src/module/elements.rs
+++ b/src/module/elements.rs
@@ -1,10 +1,9 @@
//! Table elements within a wasm module.
use crate::emit::{Emit, EmitContext, Section};
-use crate::ir::Value;
use crate::parse::IndicesToIds;
use crate::tombstone_arena::{Id, Tombstone, TombstoneArena};
-use crate::{FunctionId, InitExpr, Module, Result, TableKind, ValType};
+use crate::{ir::Value, FunctionId, InitExpr, Module, Result, TableId, ValType};
use anyhow::{bail, Context};
/// A passive element segment identifier
@@ -15,8 +14,22 @@ pub type ElementId = Id;
pub struct Element {
id: Id,
+ /// Whether this segment is passive or active.
+ pub kind: ElementKind,
+
+ /// The type of elements in this segment
+ pub ty: ValType,
+
/// The function members of this passive elements segment.
- pub members: Vec,
+ pub members: Vec