Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement the reference types proposal #155

Merged
merged 4 commits into from Feb 5, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
4 changes: 3 additions & 1 deletion .github/workflows/main.yml
Expand Up @@ -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
Expand Down
12 changes: 12 additions & 0 deletions crates/macro/src/lib.rs
Expand Up @@ -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) {
Expand Down Expand Up @@ -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) {
Expand Down
9 changes: 8 additions & 1 deletion crates/tests/tests/round_trip/elem-segments-1.wat
Expand Up @@ -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))
;)
10 changes: 9 additions & 1 deletion crates/tests/tests/round_trip/elem-segments-2.wat
Expand Up @@ -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))
;)
11 changes: 9 additions & 2 deletions crates/tests/tests/round_trip/elem-segments-3.wat
Expand Up @@ -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))
;)
21 changes: 11 additions & 10 deletions crates/tests/tests/round_trip/keep-elem-segments.wat
Expand Up @@ -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))
;)
30 changes: 1 addition & 29 deletions crates/tests/tests/round_trip/simd.wat
Expand Up @@ -502,25 +502,13 @@
(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
f32x4.convert_i32x4_s)
(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:
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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)))
;)
16 changes: 9 additions & 7 deletions crates/tests/tests/round_trip/table-init.wast
Expand Up @@ -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))
;)
25 changes: 16 additions & 9 deletions crates/tests/tests/spec-tests.rs
Expand Up @@ -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(()),
Expand Down Expand Up @@ -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)?;
Expand All @@ -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);
}
}
Expand Down
5 changes: 3 additions & 2 deletions src/dot.rs
Expand Up @@ -281,7 +281,6 @@ impl DotNode for Table {
fields.add_field(&[&format!("<b>Table {:?}</b>", 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");
}
Expand Down Expand Up @@ -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);
}
}
}
}
13 changes: 12 additions & 1 deletion src/init_expr.rs
Expand Up @@ -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
Expand All @@ -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 {
Expand All @@ -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()? {
Expand All @@ -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
}
Expand Down
28 changes: 27 additions & 1 deletion src/ir/mod.rs
Expand Up @@ -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;
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -1177,6 +1200,9 @@ impl Instr {
| Instr::V128Shuffle(..)
| Instr::LoadSimd(..)
| Instr::AtomicFence(..)
| Instr::TableInit(..)
| Instr::TableCopy(..)
| Instr::ElemDrop(..)
| Instr::Drop(..) => false,
}
}
Expand Down