From 863f449048883fb56b24daacc5c44f5ba781a4b9 Mon Sep 17 00:00:00 2001 From: Brian Carroll Date: Sat, 28 Aug 2021 22:18:18 +0100 Subject: [PATCH 01/42] Create a library for the Wasm dev backend --- Cargo.toml | 1 + compiler/gen_wasm/Cargo.toml | 8 ++++++++ compiler/gen_wasm/src/lib.rs | 7 +++++++ 3 files changed, 16 insertions(+) create mode 100644 compiler/gen_wasm/Cargo.toml create mode 100644 compiler/gen_wasm/src/lib.rs diff --git a/Cargo.toml b/Cargo.toml index 01b160bf9a..27242439f3 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -20,6 +20,7 @@ members = [ "compiler/load", "compiler/gen_llvm", "compiler/gen_dev", + "compiler/gen_wasm", "compiler/build", "compiler/arena_pool", "compiler/test_gen", diff --git a/compiler/gen_wasm/Cargo.toml b/compiler/gen_wasm/Cargo.toml new file mode 100644 index 0000000000..0a45c9f176 --- /dev/null +++ b/compiler/gen_wasm/Cargo.toml @@ -0,0 +1,8 @@ +[package] +name = "gen_wasm" +version = "0.1.0" +edition = "2018" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] diff --git a/compiler/gen_wasm/src/lib.rs b/compiler/gen_wasm/src/lib.rs new file mode 100644 index 0000000000..31e1bb209f --- /dev/null +++ b/compiler/gen_wasm/src/lib.rs @@ -0,0 +1,7 @@ +#[cfg(test)] +mod tests { + #[test] + fn it_works() { + assert_eq!(2 + 2, 4); + } +} From a1102222ddebf5e4906b7af42eb50bcc147e2a95 Mon Sep 17 00:00:00 2001 From: Brian Carroll Date: Sun, 29 Aug 2021 10:52:22 +0100 Subject: [PATCH 02/42] Create a high-level structure for Wasm backend --- compiler/gen_wasm/Cargo.toml | 20 +++++++ compiler/gen_wasm/src/lib.rs | 106 +++++++++++++++++++++++++++++++++-- 2 files changed, 121 insertions(+), 5 deletions(-) diff --git a/compiler/gen_wasm/Cargo.toml b/compiler/gen_wasm/Cargo.toml index 0a45c9f176..984220214b 100644 --- a/compiler/gen_wasm/Cargo.toml +++ b/compiler/gen_wasm/Cargo.toml @@ -6,3 +6,23 @@ edition = "2018" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] +roc_collections = { path = "../collections" } +# roc_region = { path = "../region" } +# roc_load = { path = "../load" } +roc_module = { path = "../module" } +# roc_problem = { path = "../problem" } +# roc_types = { path = "../types" } +# roc_builtins = { path = "../builtins" } +# roc_constrain = { path = "../constrain" } +# roc_unify = { path = "../unify" } +# roc_solve = { path = "../solve" } +roc_mono = { path = "../mono" } +# im = "14" # im and im-rc should always have the same version! +# im-rc = "14" # im and im-rc should always have the same version! +bumpalo = { version = "3.6.1", features = ["collections"] } +# target-lexicon = "0.12.2" +# libloading = "0.6" +parity-wasm = "0.42" + +[dev-dependencies] +wasmer = "2.0.0" diff --git a/compiler/gen_wasm/src/lib.rs b/compiler/gen_wasm/src/lib.rs index 31e1bb209f..6204087518 100644 --- a/compiler/gen_wasm/src/lib.rs +++ b/compiler/gen_wasm/src/lib.rs @@ -1,7 +1,103 @@ -#[cfg(test)] -mod tests { - #[test] - fn it_works() { - assert_eq!(2 + 2, 4); +use bumpalo::{collections::Vec, Bump}; +use parity_wasm::{elements, builder}; +use parity_wasm::elements::{ValueType, Internal}; +use parity_wasm::builder::{ModuleBuilder, FunctionDefinition, FunctionBuilder, CodeLocation}; + +// use roc_builtins::bitcode; +use roc_collections::all::{MutMap, MutSet}; +// use roc_module::ident::{ModuleName, TagName}; +// use roc_module::low_level::LowLevel; +use roc_module::symbol::{Interns, Symbol}; +use roc_mono::ir::{BranchInfo, CallType, Expr, JoinPointId, Literal, Proc, ProcLayout, Stmt}; +use roc_mono::layout::{Builtin, Layout, LayoutIds}; + + +pub struct Env<'a> { + pub arena: &'a Bump, + pub interns: Interns, + pub exposed_to_host: MutSet, +} + +pub enum SymbolStorage { + Local(ValueType, u32), + LocalAndBase(ValueType, u32, u32), +} + +pub struct LabelId(u32); + +// Don't allocate any constant data at the address zero or anywhere near it. +// These addresses are not special in Wasm, but putting something there seems bug-prone. +// Emscripten leaves 1kB free so let's do the same for now, although 4 bytes would probably do. +const UNUSED_DATA_SECTION_BYTES: u32 = 1024; + +pub struct BackendWasm<'a> { + // module-level state + env: &'a Env<'a>, + module_builder: ModuleBuilder, + data_offset_map: MutMap, u32>, + data_offset_next: u32, + + // procedure-level state + symbol_storage_map: MutMap, + joinpoint_label_map: MutMap, +} + +pub fn build_module<'a>(env: &'a Env, procedures: MutMap<(Symbol, ProcLayout<'a>), Proc<'a>>) -> Result { + let mut backend = BackendWasm::new(env); + let mut layout_ids = LayoutIds::default(); + + for ((sym, layout), proc) in procedures { + let location = backend.build_proc(proc)?; + + if env.exposed_to_host.contains(&sym) { + let fn_name = layout_ids + .get_toplevel(sym, &layout) + .to_symbol_string(sym, &env.interns); + + let export = builder::export() + .field(fn_name.as_str()) + .with_internal(Internal::Function(location.body)) + .build(); + + backend.module_builder.push_export(export); + } + } + + Ok(backend.module_builder.build()) +} + +impl <'a>BackendWasm<'a> { + pub fn new(env: &'a Env) -> Self { + BackendWasm { + env, + module_builder: builder::module(), + data_offset_map: MutMap::default(), + data_offset_next: UNUSED_DATA_SECTION_BYTES, + symbol_storage_map: MutMap::default(), + joinpoint_label_map: MutMap::default(), + } + } + + fn build_proc(&mut self, proc: Proc<'a>) -> Result { + let mut function_builder = builder::function(); + // + // ... generate stuff ... + // + let def = function_builder.build(); + let location = self.module_builder.push_function(def); + Ok(location) + } + + fn build_stmt(&mut self, stmt: &Stmt<'a>, ret_layout: &Layout<'a>) -> Result<(), String> { + Err("todo: everything".to_string()) + } + + fn build_expr( + &mut self, + sym: &Symbol, + expr: &Expr<'a>, + layout: &Layout<'a>, + ) -> Result<(), String> { + Err("todo: everything".to_string()) } } From 06c0e0d8151ebfa97cbd47b1639d177565131e5e Mon Sep 17 00:00:00 2001 From: Brian Carroll Date: Sun, 29 Aug 2021 13:20:41 +0100 Subject: [PATCH 03/42] outline of build_proc --- compiler/gen_wasm/src/lib.rs | 132 +++++++++++++++++++++++++++-------- 1 file changed, 104 insertions(+), 28 deletions(-) diff --git a/compiler/gen_wasm/src/lib.rs b/compiler/gen_wasm/src/lib.rs index 6204087518..12a52a5f1f 100644 --- a/compiler/gen_wasm/src/lib.rs +++ b/compiler/gen_wasm/src/lib.rs @@ -1,7 +1,7 @@ use bumpalo::{collections::Vec, Bump}; -use parity_wasm::{elements, builder}; -use parity_wasm::elements::{ValueType, Internal}; -use parity_wasm::builder::{ModuleBuilder, FunctionDefinition, FunctionBuilder, CodeLocation}; +use parity_wasm::builder::{CodeLocation, FunctionBuilder, FunctionDefinition, ModuleBuilder}; +use parity_wasm::elements::{Internal, ValueType}; +use parity_wasm::{builder, elements}; // use roc_builtins::bitcode; use roc_collections::all::{MutMap, MutSet}; @@ -11,38 +11,72 @@ use roc_module::symbol::{Interns, Symbol}; use roc_mono::ir::{BranchInfo, CallType, Expr, JoinPointId, Literal, Proc, ProcLayout, Stmt}; use roc_mono::layout::{Builtin, Layout, LayoutIds}; - pub struct Env<'a> { pub arena: &'a Bump, pub interns: Interns, pub exposed_to_host: MutSet, } -pub enum SymbolStorage { - Local(ValueType, u32), - LocalAndBase(ValueType, u32, u32), +#[derive(Clone, Copy)] +struct LocalId(u32); + +#[derive(Clone, Copy)] +struct LabelId(u32); + +struct WasmLayout { + value_type: ValueType, + stack_memory: u32, } -pub struct LabelId(u32); +impl WasmLayout { + fn new(layout: &Layout) -> Result { + match layout { + Layout::Builtin(Builtin::Int64) => Ok(Self { + value_type: ValueType::I64, + stack_memory: 0, + }), + x => Err(format!("layout, {:?}, not implemented yet", x)), + } + } +} + +struct SymbolStorage(LocalId, WasmLayout); // Don't allocate any constant data at the address zero or anywhere near it. // These addresses are not special in Wasm, but putting something there seems bug-prone. // Emscripten leaves 1kB free so let's do the same for now, although 4 bytes would probably do. const UNUSED_DATA_SECTION_BYTES: u32 = 1024; -pub struct BackendWasm<'a> { - // module-level state - env: &'a Env<'a>, - module_builder: ModuleBuilder, - data_offset_map: MutMap, u32>, - data_offset_next: u32, - - // procedure-level state - symbol_storage_map: MutMap, +// State that gets reset for every generated function +struct FunctionGenerator { joinpoint_label_map: MutMap, + symbol_storage_map: MutMap, + stack_memory: u32, + return_on_stack: bool, } -pub fn build_module<'a>(env: &'a Env, procedures: MutMap<(Symbol, ProcLayout<'a>), Proc<'a>>) -> Result { +impl FunctionGenerator { + fn new() -> Self { + FunctionGenerator { + joinpoint_label_map: MutMap::default(), + symbol_storage_map: MutMap::default(), + stack_memory: 0, + return_on_stack: false, + } + } + + fn reset(&mut self) { + self.joinpoint_label_map.clear(); + self.symbol_storage_map.clear(); + self.stack_memory = 0; + self.return_on_stack = false; + } +} + +pub fn build_module<'a>( + env: &'a Env, + procedures: MutMap<(Symbol, ProcLayout<'a>), Proc<'a>>, +) -> Result { let mut backend = BackendWasm::new(env); let mut layout_ids = LayoutIds::default(); @@ -66,28 +100,70 @@ pub fn build_module<'a>(env: &'a Env, procedures: MutMap<(Symbol, ProcLayout<'a> Ok(backend.module_builder.build()) } -impl <'a>BackendWasm<'a> { - pub fn new(env: &'a Env) -> Self { +struct BackendWasm<'a> { + env: &'a Env<'a>, + module_builder: ModuleBuilder, + data_offset_map: MutMap, u32>, + data_offset_next: u32, + func_gen: FunctionGenerator, +} + +impl<'a> BackendWasm<'a> { + fn new(env: &'a Env) -> Self { BackendWasm { env, module_builder: builder::module(), data_offset_map: MutMap::default(), data_offset_next: UNUSED_DATA_SECTION_BYTES, - symbol_storage_map: MutMap::default(), - joinpoint_label_map: MutMap::default(), + func_gen: FunctionGenerator::new(), } } fn build_proc(&mut self, proc: Proc<'a>) -> Result { - let mut function_builder = builder::function(); - // - // ... generate stuff ... - // - let def = function_builder.build(); - let location = self.module_builder.push_function(def); + self.func_gen.reset(); + + let ret_layout = WasmLayout::new(&proc.ret_layout)?; + let ret_value_type = ret_layout.value_type; + let return_on_stack = ret_layout.stack_memory > 0; + self.func_gen.return_on_stack = return_on_stack; + + let mut arg_types = + Vec::with_capacity_in(proc.args.len() + (return_on_stack as usize), self.env.arena); + + if return_on_stack { + arg_types.push(ret_layout.value_type); + self.allocate_local(ret_layout, None); + } + + for (layout, symbol) in proc.args { + let wasm_layout = WasmLayout::new(layout)?; + arg_types.push(wasm_layout.value_type); + self.allocate_local(wasm_layout, Some(*symbol)); + } + + let signature = builder::signature() + .with_params(arg_types.to_vec()) // TODO: yuck + .with_result(ret_value_type) + .build_sig(); + + self.build_stmt(&proc.body, &proc.ret_layout)?; + + let function_def = builder::function().with_signature(signature).build(); + + let location = self.module_builder.push_function(function_def); Ok(location) } + fn allocate_local(&mut self, layout: WasmLayout, maybe_symbol: Option) -> LocalId { + let local_id = LocalId(self.func_gen.symbol_storage_map.len() as u32); + self.func_gen.stack_memory += layout.stack_memory; + let storage = SymbolStorage(local_id, layout); + if let Some(symbol) = maybe_symbol { + self.func_gen.symbol_storage_map.insert(symbol, storage); + } + local_id + } + fn build_stmt(&mut self, stmt: &Stmt<'a>, ret_layout: &Layout<'a>) -> Result<(), String> { Err("todo: everything".to_string()) } From 8d7e0471fd228eef54e7aa8455e5002123b3e838 Mon Sep 17 00:00:00 2001 From: Brian Carroll Date: Sun, 29 Aug 2021 19:18:01 +0100 Subject: [PATCH 04/42] Get rid of return-on-stack stuff for now, focus on numbers first --- compiler/gen_wasm/src/lib.rs | 32 +++++++++++++------------------- 1 file changed, 13 insertions(+), 19 deletions(-) diff --git a/compiler/gen_wasm/src/lib.rs b/compiler/gen_wasm/src/lib.rs index 12a52a5f1f..5b3018e21d 100644 --- a/compiler/gen_wasm/src/lib.rs +++ b/compiler/gen_wasm/src/lib.rs @@ -1,5 +1,5 @@ use bumpalo::{collections::Vec, Bump}; -use parity_wasm::builder::{CodeLocation, FunctionBuilder, FunctionDefinition, ModuleBuilder}; +use parity_wasm::builder::{CodeLocation, ModuleBuilder}; use parity_wasm::elements::{Internal, ValueType}; use parity_wasm::{builder, elements}; @@ -8,7 +8,7 @@ use roc_collections::all::{MutMap, MutSet}; // use roc_module::ident::{ModuleName, TagName}; // use roc_module::low_level::LowLevel; use roc_module::symbol::{Interns, Symbol}; -use roc_mono::ir::{BranchInfo, CallType, Expr, JoinPointId, Literal, Proc, ProcLayout, Stmt}; +use roc_mono::ir::{Expr, JoinPointId, Literal, Proc, ProcLayout, Stmt}; use roc_mono::layout::{Builtin, Layout, LayoutIds}; pub struct Env<'a> { @@ -52,7 +52,6 @@ struct FunctionGenerator { joinpoint_label_map: MutMap, symbol_storage_map: MutMap, stack_memory: u32, - return_on_stack: bool, } impl FunctionGenerator { @@ -61,7 +60,6 @@ impl FunctionGenerator { joinpoint_label_map: MutMap::default(), symbol_storage_map: MutMap::default(), stack_memory: 0, - return_on_stack: false, } } @@ -69,7 +67,6 @@ impl FunctionGenerator { self.joinpoint_label_map.clear(); self.symbol_storage_map.clear(); self.stack_memory = 0; - self.return_on_stack = false; } } @@ -124,21 +121,20 @@ impl<'a> BackendWasm<'a> { let ret_layout = WasmLayout::new(&proc.ret_layout)?; let ret_value_type = ret_layout.value_type; - let return_on_stack = ret_layout.stack_memory > 0; - self.func_gen.return_on_stack = return_on_stack; - - let mut arg_types = - Vec::with_capacity_in(proc.args.len() + (return_on_stack as usize), self.env.arena); - - if return_on_stack { - arg_types.push(ret_layout.value_type); - self.allocate_local(ret_layout, None); + if ret_layout.stack_memory > 0 { + // TODO: insert an extra param for a pointer to space allocated in callee's stack... or does Roc do something else? + return Err(format!( + "Not yet implemented: Return in stack memory for non-primtitive layouts like {:?}", + proc.ret_layout + )); } + let mut arg_types = Vec::with_capacity_in(proc.args.len(), self.env.arena); + for (layout, symbol) in proc.args { let wasm_layout = WasmLayout::new(layout)?; arg_types.push(wasm_layout.value_type); - self.allocate_local(wasm_layout, Some(*symbol)); + self.allocate_local(wasm_layout, *symbol); } let signature = builder::signature() @@ -154,13 +150,11 @@ impl<'a> BackendWasm<'a> { Ok(location) } - fn allocate_local(&mut self, layout: WasmLayout, maybe_symbol: Option) -> LocalId { + fn allocate_local(&mut self, layout: WasmLayout, symbol: Symbol) -> LocalId { let local_id = LocalId(self.func_gen.symbol_storage_map.len() as u32); self.func_gen.stack_memory += layout.stack_memory; let storage = SymbolStorage(local_id, layout); - if let Some(symbol) = maybe_symbol { - self.func_gen.symbol_storage_map.insert(symbol, storage); - } + self.func_gen.symbol_storage_map.insert(symbol, storage); local_id } From 4d76b9d15d3b10deff908eb3bcf1e4c6fdcdfd15 Mon Sep 17 00:00:00 2001 From: Brian Carroll Date: Sun, 29 Aug 2021 20:31:30 +0100 Subject: [PATCH 05/42] Refactor locals --- compiler/gen_wasm/src/lib.rs | 33 ++++++++++++++++++++------------- 1 file changed, 20 insertions(+), 13 deletions(-) diff --git a/compiler/gen_wasm/src/lib.rs b/compiler/gen_wasm/src/lib.rs index 5b3018e21d..d8c28c909e 100644 --- a/compiler/gen_wasm/src/lib.rs +++ b/compiler/gen_wasm/src/lib.rs @@ -1,6 +1,6 @@ -use bumpalo::{collections::Vec, Bump}; +use bumpalo::{Bump}; use parity_wasm::builder::{CodeLocation, ModuleBuilder}; -use parity_wasm::elements::{Internal, ValueType}; +use parity_wasm::elements::{Internal, ValueType, Local}; use parity_wasm::{builder, elements}; // use roc_builtins::bitcode; @@ -12,7 +12,7 @@ use roc_mono::ir::{Expr, JoinPointId, Literal, Proc, ProcLayout, Stmt}; use roc_mono::layout::{Builtin, Layout, LayoutIds}; pub struct Env<'a> { - pub arena: &'a Bump, + pub arena: &'a Bump, // not really using this much, parity_wasm works with std::vec a lot pub interns: Interns, pub exposed_to_host: MutSet, } @@ -50,6 +50,7 @@ const UNUSED_DATA_SECTION_BYTES: u32 = 1024; // State that gets reset for every generated function struct FunctionGenerator { joinpoint_label_map: MutMap, + locals: std::vec::Vec, symbol_storage_map: MutMap, stack_memory: u32, } @@ -60,14 +61,27 @@ impl FunctionGenerator { joinpoint_label_map: MutMap::default(), symbol_storage_map: MutMap::default(), stack_memory: 0, + locals: std::vec::Vec::new(), } } fn reset(&mut self) { self.joinpoint_label_map.clear(); + self.locals.clear(); self.symbol_storage_map.clear(); self.stack_memory = 0; } + + fn insert_local(&mut self, layout: WasmLayout, symbol: Symbol) -> LocalId { + let local_id = LocalId(self.locals.len() as u32); + self.locals.push(Local::new(1, layout.value_type)); + self.stack_memory += layout.stack_memory; + + let storage = SymbolStorage(local_id, layout); + self.symbol_storage_map.insert(symbol, storage); + + local_id + } } pub fn build_module<'a>( @@ -129,16 +143,16 @@ impl<'a> BackendWasm<'a> { )); } - let mut arg_types = Vec::with_capacity_in(proc.args.len(), self.env.arena); + let mut arg_types = std::vec::Vec::with_capacity(proc.args.len()); for (layout, symbol) in proc.args { let wasm_layout = WasmLayout::new(layout)?; arg_types.push(wasm_layout.value_type); - self.allocate_local(wasm_layout, *symbol); + self.func_gen.insert_local(wasm_layout, *symbol); } let signature = builder::signature() - .with_params(arg_types.to_vec()) // TODO: yuck + .with_params(arg_types) // requires std::Vec, not Bumpalo .with_result(ret_value_type) .build_sig(); @@ -150,13 +164,6 @@ impl<'a> BackendWasm<'a> { Ok(location) } - fn allocate_local(&mut self, layout: WasmLayout, symbol: Symbol) -> LocalId { - let local_id = LocalId(self.func_gen.symbol_storage_map.len() as u32); - self.func_gen.stack_memory += layout.stack_memory; - let storage = SymbolStorage(local_id, layout); - self.func_gen.symbol_storage_map.insert(symbol, storage); - local_id - } fn build_stmt(&mut self, stmt: &Stmt<'a>, ret_layout: &Layout<'a>) -> Result<(), String> { Err("todo: everything".to_string()) From 6500cb3c35a92a89e8e7e41bad6a817f3df6cbcc Mon Sep 17 00:00:00 2001 From: Brian Carroll Date: Sun, 29 Aug 2021 21:07:15 +0100 Subject: [PATCH 06/42] Add a body to the function --- compiler/gen_wasm/src/lib.rs | 27 ++++++++++++++++----------- 1 file changed, 16 insertions(+), 11 deletions(-) diff --git a/compiler/gen_wasm/src/lib.rs b/compiler/gen_wasm/src/lib.rs index d8c28c909e..370d8f9fb0 100644 --- a/compiler/gen_wasm/src/lib.rs +++ b/compiler/gen_wasm/src/lib.rs @@ -1,6 +1,6 @@ -use bumpalo::{Bump}; +use bumpalo::Bump; use parity_wasm::builder::{CodeLocation, ModuleBuilder}; -use parity_wasm::elements::{Internal, ValueType, Local}; +use parity_wasm::elements::{Instruction, Instructions, Internal, Local, ValueType}; use parity_wasm::{builder, elements}; // use roc_builtins::bitcode; @@ -47,8 +47,9 @@ struct SymbolStorage(LocalId, WasmLayout); // Emscripten leaves 1kB free so let's do the same for now, although 4 bytes would probably do. const UNUSED_DATA_SECTION_BYTES: u32 = 1024; -// State that gets reset for every generated function +// State for generating a single function struct FunctionGenerator { + instructions: std::vec::Vec, joinpoint_label_map: MutMap, locals: std::vec::Vec, symbol_storage_map: MutMap, @@ -58,6 +59,7 @@ struct FunctionGenerator { impl FunctionGenerator { fn new() -> Self { FunctionGenerator { + instructions: std::vec::Vec::new(), joinpoint_label_map: MutMap::default(), symbol_storage_map: MutMap::default(), stack_memory: 0, @@ -116,7 +118,6 @@ struct BackendWasm<'a> { module_builder: ModuleBuilder, data_offset_map: MutMap, u32>, data_offset_next: u32, - func_gen: FunctionGenerator, } impl<'a> BackendWasm<'a> { @@ -126,12 +127,11 @@ impl<'a> BackendWasm<'a> { module_builder: builder::module(), data_offset_map: MutMap::default(), data_offset_next: UNUSED_DATA_SECTION_BYTES, - func_gen: FunctionGenerator::new(), } } fn build_proc(&mut self, proc: Proc<'a>) -> Result { - self.func_gen.reset(); + let mut func_gen = FunctionGenerator::new(); // yeah probably don't need to allocate a new one every time, but tell that to the borrow checker! ;-) let ret_layout = WasmLayout::new(&proc.ret_layout)?; let ret_value_type = ret_layout.value_type; @@ -148,7 +148,7 @@ impl<'a> BackendWasm<'a> { for (layout, symbol) in proc.args { let wasm_layout = WasmLayout::new(layout)?; arg_types.push(wasm_layout.value_type); - self.func_gen.insert_local(wasm_layout, *symbol); + func_gen.insert_local(wasm_layout, *symbol); } let signature = builder::signature() @@ -156,16 +156,21 @@ impl<'a> BackendWasm<'a> { .with_result(ret_value_type) .build_sig(); - self.build_stmt(&proc.body, &proc.ret_layout)?; + self.build_stmt(&mut func_gen, &proc.body, &proc.ret_layout)?; - let function_def = builder::function().with_signature(signature).build(); + let function_def = builder::function() + .with_signature(signature) + .body() + .with_locals(func_gen.locals) + .with_instructions(Instructions::new(func_gen.instructions)) + .build() // body + .build(); // function let location = self.module_builder.push_function(function_def); Ok(location) } - - fn build_stmt(&mut self, stmt: &Stmt<'a>, ret_layout: &Layout<'a>) -> Result<(), String> { + fn build_stmt(&mut self, func_gen: &mut FunctionGenerator, stmt: &Stmt<'a>, ret_layout: &Layout<'a>) -> Result<(), String> { Err("todo: everything".to_string()) } From e5d5bb27fa67175c66bab02610e304b80125e510 Mon Sep 17 00:00:00 2001 From: Brian Carroll Date: Mon, 30 Aug 2021 00:23:46 +0100 Subject: [PATCH 07/42] Implement a bit more of the IR --- compiler/gen_wasm/src/lib.rs | 71 ++++++++++++++++++++++++++++++++---- 1 file changed, 64 insertions(+), 7 deletions(-) diff --git a/compiler/gen_wasm/src/lib.rs b/compiler/gen_wasm/src/lib.rs index 370d8f9fb0..63c9a66670 100644 --- a/compiler/gen_wasm/src/lib.rs +++ b/compiler/gen_wasm/src/lib.rs @@ -1,14 +1,16 @@ use bumpalo::Bump; use parity_wasm::builder::{CodeLocation, ModuleBuilder}; -use parity_wasm::elements::{Instruction, Instructions, Internal, Local, ValueType}; +use parity_wasm::elements::{ + Instruction, Instruction::*, Instructions, Internal, Local, ValueType, +}; use parity_wasm::{builder, elements}; // use roc_builtins::bitcode; use roc_collections::all::{MutMap, MutSet}; // use roc_module::ident::{ModuleName, TagName}; -// use roc_module::low_level::LowLevel; +use roc_module::low_level::LowLevel; use roc_module::symbol::{Interns, Symbol}; -use roc_mono::ir::{Expr, JoinPointId, Literal, Proc, ProcLayout, Stmt}; +use roc_mono::ir::{CallType, Expr, JoinPointId, Literal, Proc, ProcLayout, Stmt}; use roc_mono::layout::{Builtin, Layout, LayoutIds}; pub struct Env<'a> { @@ -44,7 +46,6 @@ struct SymbolStorage(LocalId, WasmLayout); // Don't allocate any constant data at the address zero or anywhere near it. // These addresses are not special in Wasm, but putting something there seems bug-prone. -// Emscripten leaves 1kB free so let's do the same for now, although 4 bytes would probably do. const UNUSED_DATA_SECTION_BYTES: u32 = 1024; // State for generating a single function @@ -170,16 +171,72 @@ impl<'a> BackendWasm<'a> { Ok(location) } - fn build_stmt(&mut self, func_gen: &mut FunctionGenerator, stmt: &Stmt<'a>, ret_layout: &Layout<'a>) -> Result<(), String> { - Err("todo: everything".to_string()) + fn build_stmt( + &mut self, + func_gen: &mut FunctionGenerator, + stmt: &Stmt<'a>, + ret_layout: &Layout<'a>, + ) -> Result<(), String> { + match stmt { + Stmt::Let(sym, expr, layout, following) => { + self.build_expr(func_gen, sym, expr, layout)?; + + let wasm_layout = WasmLayout::new(layout)?; + let local_id = func_gen.insert_local(wasm_layout, *sym); + func_gen.instructions.push(SetLocal(local_id.0)); + + self.build_stmt(func_gen, following, ret_layout)?; + Ok(()) + } + Stmt::Ret(sym) => { + if let Some(SymbolStorage(local_id, wasm_layout)) = + func_gen.symbol_storage_map.get(sym) + { + func_gen.instructions.push(GetLocal(local_id.0)); + func_gen.instructions.push(Return); + Ok(()) + } else { + Err(format!( + "Not yet implemented: returning values with layout {:?}", + ret_layout + )) + } + } + x => Err(format!("statement not yet implemented: {:?}", x)), + } } fn build_expr( &mut self, + func_gen: &mut FunctionGenerator, sym: &Symbol, expr: &Expr<'a>, layout: &Layout<'a>, ) -> Result<(), String> { - Err("todo: everything".to_string()) + match expr { + Expr::Literal(lit) => self.load_literal(func_gen, lit), + x => Err(format!("Expression is not yet implemented {:?}", x)), + } + } + + fn load_literal( + &mut self, + func_gen: &mut FunctionGenerator, + lit: &Literal<'a>, + ) -> Result<(), String> { + match lit { + Literal::Int(x) => { + func_gen.instructions.push(I64Const(*x as i64)); + Ok(()) + } + Literal::Float(x) => { + // F64Const takes a u64?? + // I've raised an issue in the library to check https://github.com/paritytech/parity-wasm/issues/314 + let val: u64 = unsafe { std::mem::transmute(*x) }; + func_gen.instructions.push(F64Const(val)); + Ok(()) + } + x => Err(format!("loading literal, {:?}, is not yet implemented", x)), + } } } From e67efaba4dc8d39639154af8c1f93b0877c8f624 Mon Sep 17 00:00:00 2001 From: Brian Carroll Date: Mon, 30 Aug 2021 23:07:12 +0100 Subject: [PATCH 08/42] Split up Wasm module and function --- compiler/gen_wasm/src/function.rs | 240 +++++++++++++++++++++++++++++ compiler/gen_wasm/src/lib.rs | 244 +----------------------------- compiler/gen_wasm/src/module.rs | 107 +++++++++++++ 3 files changed, 349 insertions(+), 242 deletions(-) create mode 100644 compiler/gen_wasm/src/function.rs create mode 100644 compiler/gen_wasm/src/module.rs diff --git a/compiler/gen_wasm/src/function.rs b/compiler/gen_wasm/src/function.rs new file mode 100644 index 0000000000..07de4b12d1 --- /dev/null +++ b/compiler/gen_wasm/src/function.rs @@ -0,0 +1,240 @@ +use parity_wasm::elements::{Instruction, Instruction::*, Local, ValueType}; + +use roc_collections::all::MutMap; +use roc_module::low_level::LowLevel; +use roc_module::symbol::Symbol; +use roc_mono::ir::{CallType, Expr, Literal, Proc, Stmt}; +use roc_mono::layout::{Builtin, Layout}; + +use crate::module::ModuleState; + +#[derive(Clone, Copy)] +struct LocalId(u32); + +#[derive(Clone, Copy)] +struct LabelId(u32); + +struct WasmLayout { + value_type: ValueType, + stack_memory: u32, +} + +struct SymbolStorage(LocalId, WasmLayout); + +impl WasmLayout { + fn new(layout: &Layout) -> Result { + match layout { + Layout::Builtin(Builtin::Int64) => Ok(Self { + value_type: ValueType::I64, + stack_memory: 0, + }), + x => Err(format!("layout, {:?}, not implemented yet", x)), + } + } +} + +pub struct FunctionGenerator<'a> { + pub instructions: std::vec::Vec, + pub ret_type: ValueType, + pub arg_types: std::vec::Vec, + pub locals: std::vec::Vec, + module_state: &'a mut ModuleState, + // joinpoint_label_map: MutMap, + symbol_storage_map: MutMap, + stack_memory: u32, +} + +impl<'a> FunctionGenerator<'a> { + pub fn new(module_state: &'a mut ModuleState) -> Self { + FunctionGenerator { + instructions: std::vec::Vec::new(), + ret_type: ValueType::I32, + arg_types: std::vec::Vec::new(), + locals: std::vec::Vec::new(), + module_state: module_state, + // joinpoint_label_map: MutMap::default(), + symbol_storage_map: MutMap::default(), + stack_memory: 0, + } + } + + pub fn build(&mut self, proc: Proc<'a>) -> Result<(), String> { + let ret_layout = WasmLayout::new(&proc.ret_layout)?; + if ret_layout.stack_memory > 0 { + // TODO: if returning a struct by value, add an extra argument for a pointer to callee's stack memory + return Err(format!( + "Not yet implemented: Return in stack memory for non-primtitive layouts like {:?}", + proc.ret_layout + )); + } + + self.ret_type = ret_layout.value_type; + self.arg_types = std::vec::Vec::with_capacity(proc.args.len()); + + for (layout, symbol) in proc.args { + let wasm_layout = WasmLayout::new(layout)?; + self.arg_types.push(wasm_layout.value_type); + self.insert_local(wasm_layout, *symbol); + } + + self.build_stmt(&proc.body, &proc.ret_layout)?; + Ok(()) + } + + fn insert_local(&mut self, layout: WasmLayout, symbol: Symbol) -> LocalId { + let local_id = LocalId(self.locals.len() as u32); + self.locals.push(Local::new(1, layout.value_type)); + self.stack_memory += layout.stack_memory; + + let storage = SymbolStorage(local_id, layout); + self.symbol_storage_map.insert(symbol, storage); + + local_id + } + + fn get_symbol_storage(&self, sym: &Symbol) -> Result<&SymbolStorage, String> { + self.symbol_storage_map + .get(sym) + .ok_or(format!("Symbol not found in function scope {:?}", sym)) + } + + fn load_from_symbol(&mut self, sym: &Symbol) -> Result<(), String> { + let SymbolStorage(LocalId(local_id), _) = self.get_symbol_storage(sym)?; + let id: u32 = *local_id; + self.instructions.push(GetLocal(id)); + Ok(()) + } + + // Store whatever value is on top of the VM's stack + fn store_to_symbol(&mut self, sym: &Symbol) -> Result<(), String> { + let SymbolStorage(LocalId(local_id), _) = self.get_symbol_storage(sym)?; + let id: u32 = *local_id; + self.instructions.push(SetLocal(id)); + Ok(()) + } + + fn build_stmt(&mut self, stmt: &Stmt<'a>, ret_layout: &Layout<'a>) -> Result<(), String> { + match stmt { + Stmt::Let(sym, expr, layout, following) => { + self.build_expr(sym, expr, layout)?; + + let wasm_layout = WasmLayout::new(layout)?; + let local_id = self.insert_local(wasm_layout, *sym); + self.instructions.push(SetLocal(local_id.0)); + + self.build_stmt(following, ret_layout)?; + Ok(()) + } + Stmt::Ret(sym) => { + if let Some(SymbolStorage(local_id, _)) = self.symbol_storage_map.get(sym) { + self.instructions.push(GetLocal(local_id.0)); + self.instructions.push(Return); + Ok(()) + } else { + Err(format!( + "Not yet implemented: returning values with layout {:?}", + ret_layout + )) + } + } + x => Err(format!("statement not yet implemented: {:?}", x)), + } + } + + fn build_expr( + &mut self, + sym: &Symbol, + expr: &Expr<'a>, + layout: &Layout<'a>, + ) -> Result<(), String> { + match expr { + Expr::Literal(lit) => self.load_literal(lit), + + Expr::Call(roc_mono::ir::Call { + call_type, + arguments, + }) => match call_type { + CallType::ByName { name: func_sym, .. } => { + for arg in *arguments { + self.load_from_symbol(arg)?; + } + let function_location = + self.module_state + .proc_symbol_map + .get(func_sym) + .ok_or(format!( + "Cannot find function {:?} called from {:?}", + func_sym, sym + ))?; + self.instructions.push(Call(function_location.body)); + self.store_to_symbol(sym)?; + Ok(()) + } + + CallType::LowLevel { op: lowlevel, .. } => { + self.build_call_low_level(sym, lowlevel, arguments, layout) + } + x => Err(format!("the call type, {:?}, is not yet implemented", x)), + }, + + x => Err(format!("Expression is not yet implemented {:?}", x)), + } + } + + fn load_literal(&mut self, lit: &Literal<'a>) -> Result<(), String> { + match lit { + Literal::Int(x) => { + self.instructions.push(I64Const(*x as i64)); + Ok(()) + } + Literal::Float(x) => { + let val: f64 = *x; + self.instructions.push(F64Const(val.to_bits())); + Ok(()) + } + x => Err(format!("loading literal, {:?}, is not yet implemented", x)), + } + } + + fn build_call_low_level( + &mut self, + sym: &Symbol, + lowlevel: &LowLevel, + args: &'a [Symbol], + layout: &Layout<'a>, + ) -> Result<(), String> { + for arg in args { + self.load_from_symbol(arg)?; + } + let wasm_layout = WasmLayout::new(layout)?; + self.build_instructions_lowlevel(lowlevel, wasm_layout.value_type)?; + self.store_to_symbol(sym)?; + Ok(()) + } + + fn build_instructions_lowlevel( + &mut self, + lowlevel: &LowLevel, + value_type: ValueType, + ) -> Result<(), String> { + // TODO: Find a way to organise all the lowlevel ops and layouts! There's lots! + // + // Some Roc low-level ops care about wrapping, clipping, sign-extending... + // For those, we'll need to pre-process each argument before the main op, + // so simple arrays of instructions won't work. But there are common patterns. + let instructions: &[Instruction] = match lowlevel { + // Matching on Wasm type might not be enough, maybe need Roc layout for sign-extension + LowLevel::NumAdd => match value_type { + ValueType::I32 => &[I32Add], + ValueType::I64 => &[I64Add], + ValueType::F32 => &[F32Add], + ValueType::F64 => &[F64Add], + }, + _ => { + return Err(format!("unsupported low-level op {:?}", lowlevel)); + } + }; + self.instructions.extend_from_slice(instructions); + Ok(()) + } +} diff --git a/compiler/gen_wasm/src/lib.rs b/compiler/gen_wasm/src/lib.rs index 63c9a66670..d020707d3f 100644 --- a/compiler/gen_wasm/src/lib.rs +++ b/compiler/gen_wasm/src/lib.rs @@ -1,242 +1,2 @@ -use bumpalo::Bump; -use parity_wasm::builder::{CodeLocation, ModuleBuilder}; -use parity_wasm::elements::{ - Instruction, Instruction::*, Instructions, Internal, Local, ValueType, -}; -use parity_wasm::{builder, elements}; - -// use roc_builtins::bitcode; -use roc_collections::all::{MutMap, MutSet}; -// use roc_module::ident::{ModuleName, TagName}; -use roc_module::low_level::LowLevel; -use roc_module::symbol::{Interns, Symbol}; -use roc_mono::ir::{CallType, Expr, JoinPointId, Literal, Proc, ProcLayout, Stmt}; -use roc_mono::layout::{Builtin, Layout, LayoutIds}; - -pub struct Env<'a> { - pub arena: &'a Bump, // not really using this much, parity_wasm works with std::vec a lot - pub interns: Interns, - pub exposed_to_host: MutSet, -} - -#[derive(Clone, Copy)] -struct LocalId(u32); - -#[derive(Clone, Copy)] -struct LabelId(u32); - -struct WasmLayout { - value_type: ValueType, - stack_memory: u32, -} - -impl WasmLayout { - fn new(layout: &Layout) -> Result { - match layout { - Layout::Builtin(Builtin::Int64) => Ok(Self { - value_type: ValueType::I64, - stack_memory: 0, - }), - x => Err(format!("layout, {:?}, not implemented yet", x)), - } - } -} - -struct SymbolStorage(LocalId, WasmLayout); - -// Don't allocate any constant data at the address zero or anywhere near it. -// These addresses are not special in Wasm, but putting something there seems bug-prone. -const UNUSED_DATA_SECTION_BYTES: u32 = 1024; - -// State for generating a single function -struct FunctionGenerator { - instructions: std::vec::Vec, - joinpoint_label_map: MutMap, - locals: std::vec::Vec, - symbol_storage_map: MutMap, - stack_memory: u32, -} - -impl FunctionGenerator { - fn new() -> Self { - FunctionGenerator { - instructions: std::vec::Vec::new(), - joinpoint_label_map: MutMap::default(), - symbol_storage_map: MutMap::default(), - stack_memory: 0, - locals: std::vec::Vec::new(), - } - } - - fn reset(&mut self) { - self.joinpoint_label_map.clear(); - self.locals.clear(); - self.symbol_storage_map.clear(); - self.stack_memory = 0; - } - - fn insert_local(&mut self, layout: WasmLayout, symbol: Symbol) -> LocalId { - let local_id = LocalId(self.locals.len() as u32); - self.locals.push(Local::new(1, layout.value_type)); - self.stack_memory += layout.stack_memory; - - let storage = SymbolStorage(local_id, layout); - self.symbol_storage_map.insert(symbol, storage); - - local_id - } -} - -pub fn build_module<'a>( - env: &'a Env, - procedures: MutMap<(Symbol, ProcLayout<'a>), Proc<'a>>, -) -> Result { - let mut backend = BackendWasm::new(env); - let mut layout_ids = LayoutIds::default(); - - for ((sym, layout), proc) in procedures { - let location = backend.build_proc(proc)?; - - if env.exposed_to_host.contains(&sym) { - let fn_name = layout_ids - .get_toplevel(sym, &layout) - .to_symbol_string(sym, &env.interns); - - let export = builder::export() - .field(fn_name.as_str()) - .with_internal(Internal::Function(location.body)) - .build(); - - backend.module_builder.push_export(export); - } - } - - Ok(backend.module_builder.build()) -} - -struct BackendWasm<'a> { - env: &'a Env<'a>, - module_builder: ModuleBuilder, - data_offset_map: MutMap, u32>, - data_offset_next: u32, -} - -impl<'a> BackendWasm<'a> { - fn new(env: &'a Env) -> Self { - BackendWasm { - env, - module_builder: builder::module(), - data_offset_map: MutMap::default(), - data_offset_next: UNUSED_DATA_SECTION_BYTES, - } - } - - fn build_proc(&mut self, proc: Proc<'a>) -> Result { - let mut func_gen = FunctionGenerator::new(); // yeah probably don't need to allocate a new one every time, but tell that to the borrow checker! ;-) - - let ret_layout = WasmLayout::new(&proc.ret_layout)?; - let ret_value_type = ret_layout.value_type; - if ret_layout.stack_memory > 0 { - // TODO: insert an extra param for a pointer to space allocated in callee's stack... or does Roc do something else? - return Err(format!( - "Not yet implemented: Return in stack memory for non-primtitive layouts like {:?}", - proc.ret_layout - )); - } - - let mut arg_types = std::vec::Vec::with_capacity(proc.args.len()); - - for (layout, symbol) in proc.args { - let wasm_layout = WasmLayout::new(layout)?; - arg_types.push(wasm_layout.value_type); - func_gen.insert_local(wasm_layout, *symbol); - } - - let signature = builder::signature() - .with_params(arg_types) // requires std::Vec, not Bumpalo - .with_result(ret_value_type) - .build_sig(); - - self.build_stmt(&mut func_gen, &proc.body, &proc.ret_layout)?; - - let function_def = builder::function() - .with_signature(signature) - .body() - .with_locals(func_gen.locals) - .with_instructions(Instructions::new(func_gen.instructions)) - .build() // body - .build(); // function - - let location = self.module_builder.push_function(function_def); - Ok(location) - } - - fn build_stmt( - &mut self, - func_gen: &mut FunctionGenerator, - stmt: &Stmt<'a>, - ret_layout: &Layout<'a>, - ) -> Result<(), String> { - match stmt { - Stmt::Let(sym, expr, layout, following) => { - self.build_expr(func_gen, sym, expr, layout)?; - - let wasm_layout = WasmLayout::new(layout)?; - let local_id = func_gen.insert_local(wasm_layout, *sym); - func_gen.instructions.push(SetLocal(local_id.0)); - - self.build_stmt(func_gen, following, ret_layout)?; - Ok(()) - } - Stmt::Ret(sym) => { - if let Some(SymbolStorage(local_id, wasm_layout)) = - func_gen.symbol_storage_map.get(sym) - { - func_gen.instructions.push(GetLocal(local_id.0)); - func_gen.instructions.push(Return); - Ok(()) - } else { - Err(format!( - "Not yet implemented: returning values with layout {:?}", - ret_layout - )) - } - } - x => Err(format!("statement not yet implemented: {:?}", x)), - } - } - - fn build_expr( - &mut self, - func_gen: &mut FunctionGenerator, - sym: &Symbol, - expr: &Expr<'a>, - layout: &Layout<'a>, - ) -> Result<(), String> { - match expr { - Expr::Literal(lit) => self.load_literal(func_gen, lit), - x => Err(format!("Expression is not yet implemented {:?}", x)), - } - } - - fn load_literal( - &mut self, - func_gen: &mut FunctionGenerator, - lit: &Literal<'a>, - ) -> Result<(), String> { - match lit { - Literal::Int(x) => { - func_gen.instructions.push(I64Const(*x as i64)); - Ok(()) - } - Literal::Float(x) => { - // F64Const takes a u64?? - // I've raised an issue in the library to check https://github.com/paritytech/parity-wasm/issues/314 - let val: u64 = unsafe { std::mem::transmute(*x) }; - func_gen.instructions.push(F64Const(val)); - Ok(()) - } - x => Err(format!("loading literal, {:?}, is not yet implemented", x)), - } - } -} +pub mod module; +mod function; diff --git a/compiler/gen_wasm/src/module.rs b/compiler/gen_wasm/src/module.rs new file mode 100644 index 0000000000..408ea3b4fd --- /dev/null +++ b/compiler/gen_wasm/src/module.rs @@ -0,0 +1,107 @@ +use bumpalo::Bump; +use parity_wasm::builder::{CodeLocation, ModuleBuilder}; +use parity_wasm::elements::{Instructions, Internal}; +use parity_wasm::{builder, elements}; + +use roc_collections::all::{MutMap, MutSet}; +use roc_module::symbol::{Interns, Symbol}; +use roc_mono::ir::{CallType, Expr, Literal, Proc, ProcLayout, Stmt}; +use roc_mono::layout::LayoutIds; + +use crate::function::FunctionGenerator; + +pub struct Env<'a> { + pub arena: &'a Bump, // not really using this much, parity_wasm works with std::vec a lot + pub interns: Interns, + pub exposed_to_host: MutSet, +} + +// Don't allocate any constant data at the address zero or anywhere near it. +// These addresses are not special in Wasm, but putting something there seems bug-prone. +const UNUSED_DATA_SECTION_BYTES: u32 = 1024; + +pub fn build_module<'a>( + env: &'a Env, + procedures: MutMap<(Symbol, ProcLayout<'a>), Proc<'a>>, +) -> Result { + let mut module_state = ModuleState::new(env); + let mut layout_ids = LayoutIds::default(); + + for ((sym, layout), proc) in procedures { + let location = build_proc(&mut module_state, proc)?; + + if env.exposed_to_host.contains(&sym) { + let fn_name = layout_ids + .get_toplevel(sym, &layout) + .to_symbol_string(sym, &env.interns); + + let export = builder::export() + .field(fn_name.as_str()) + .with_internal(Internal::Function(location.body)) + .build(); + + module_state.module_builder.push_export(export); + } + module_state.proc_symbol_map.insert(sym, location); + } + + Ok(module_state.module_builder.build()) +} + +fn build_proc<'a>(module_state: &mut ModuleState, proc: Proc<'a>) -> Result { + // TODO: see if we can reuse the same memory each time and reset it? + // Can't convince the borrow-checker to let me do that, as things get moved into the function builder. + let mut func_gen = FunctionGenerator::new(module_state); + func_gen.build(proc)?; + + let signature = builder::signature() + .with_params(func_gen.arg_types) // requires std::Vec, not Bumpalo + .with_result(func_gen.ret_type) + .build_sig(); + + let function_def = builder::function() + .with_signature(signature) + .body() + .with_locals(func_gen.locals) + .with_instructions(Instructions::new(func_gen.instructions)) + .build() // body + .build(); // function + + let location = module_state.module_builder.push_function(function_def); + Ok(location) +} + +pub struct ModuleState<'a> { + _env: &'a Env<'a>, + module_builder: ModuleBuilder, + pub proc_symbol_map: MutMap, + pub _data_offset_map: MutMap, u32>, + pub _data_offset_next: u32, +} + +impl<'a> ModuleState<'a> { + fn new(_env: &'a Env) -> Self { + ModuleState { + _env, + module_builder: builder::module(), + proc_symbol_map: MutMap::default(), + _data_offset_map: MutMap::default(), + _data_offset_next: UNUSED_DATA_SECTION_BYTES, + } + } +} + +// TODO: use something like this for very simple inlining +// Create a HashMap of inlined Procs, generate each call with different Symbol arguments +fn _is_lowlevel_wrapper<'a>(proc: Proc<'a>) -> bool { + match proc.body { + Stmt::Let(_, expr, _, Stmt::Ret(..)) => match expr { + Expr::Call(roc_mono::ir::Call { call_type, .. }) => match call_type { + CallType::LowLevel { .. } => true, + _ => false, + }, + _ => false, + }, + _ => false, + } +} From 3bf94e020cca2d3822598b2fc6726fab224748ba Mon Sep 17 00:00:00 2001 From: Brian Carroll Date: Wed, 1 Sep 2021 18:20:54 +0100 Subject: [PATCH 09/42] Beat the borrow-checker by following gen_dev structure --- .../gen_wasm/src/{function.rs => backend.rs} | 94 ++++++++++----- compiler/gen_wasm/src/lib.rs | 64 ++++++++++- compiler/gen_wasm/src/module.rs | 107 ------------------ 3 files changed, 128 insertions(+), 137 deletions(-) rename compiler/gen_wasm/src/{function.rs => backend.rs} (76%) delete mode 100644 compiler/gen_wasm/src/module.rs diff --git a/compiler/gen_wasm/src/function.rs b/compiler/gen_wasm/src/backend.rs similarity index 76% rename from compiler/gen_wasm/src/function.rs rename to compiler/gen_wasm/src/backend.rs index 07de4b12d1..2dd9cedcf8 100644 --- a/compiler/gen_wasm/src/function.rs +++ b/compiler/gen_wasm/src/backend.rs @@ -1,4 +1,6 @@ -use parity_wasm::elements::{Instruction, Instruction::*, Local, ValueType}; +use parity_wasm::builder; +use parity_wasm::builder::{CodeLocation, ModuleBuilder}; +use parity_wasm::elements::{Instruction, Instruction::*, Instructions, Local, ValueType}; use roc_collections::all::MutMap; use roc_module::low_level::LowLevel; @@ -6,7 +8,9 @@ use roc_module::symbol::Symbol; use roc_mono::ir::{CallType, Expr, Literal, Proc, Stmt}; use roc_mono::layout::{Builtin, Layout}; -use crate::module::ModuleState; +// Don't allocate any constant data at address zero or near it. Would be valid, but bug-prone. +// Follow Emscripten's example by using 1kB (4 bytes would probably do) +const UNUSED_DATA_SECTION_BYTES: u32 = 1024; #[derive(Clone, Copy)] struct LocalId(u32); @@ -14,13 +18,13 @@ struct LocalId(u32); #[derive(Clone, Copy)] struct LabelId(u32); +struct SymbolStorage(LocalId, WasmLayout); + struct WasmLayout { value_type: ValueType, stack_memory: u32, } -struct SymbolStorage(LocalId, WasmLayout); - impl WasmLayout { fn new(layout: &Layout) -> Result { match layout { @@ -33,32 +37,52 @@ impl WasmLayout { } } -pub struct FunctionGenerator<'a> { - pub instructions: std::vec::Vec, - pub ret_type: ValueType, - pub arg_types: std::vec::Vec, - pub locals: std::vec::Vec, - module_state: &'a mut ModuleState, - // joinpoint_label_map: MutMap, - symbol_storage_map: MutMap, +pub struct WasmBackend<'a> { + // Module: Wasm AST + pub builder: ModuleBuilder, + + // Module: internal state & IR mappings + _data_offset_map: MutMap, u32>, + _data_offset_next: u32, + proc_symbol_map: MutMap, + + // Functions: Wasm AST + instructions: std::vec::Vec, + ret_type: ValueType, + arg_types: std::vec::Vec, + locals: std::vec::Vec, + + // Functions: internal state & IR mappings stack_memory: u32, + symbol_storage_map: MutMap, + // joinpoint_label_map: MutMap, } -impl<'a> FunctionGenerator<'a> { - pub fn new(module_state: &'a mut ModuleState) -> Self { - FunctionGenerator { +impl<'a> WasmBackend<'a> { + pub fn new() -> Self { + WasmBackend { + // Module: Wasm AST + builder: builder::module(), + + // Module: internal state & IR mappings + _data_offset_map: MutMap::default(), + _data_offset_next: UNUSED_DATA_SECTION_BYTES, + proc_symbol_map: MutMap::default(), + + // Functions: Wasm AST instructions: std::vec::Vec::new(), ret_type: ValueType::I32, arg_types: std::vec::Vec::new(), locals: std::vec::Vec::new(), - module_state: module_state, - // joinpoint_label_map: MutMap::default(), - symbol_storage_map: MutMap::default(), + + // Functions: internal state & IR mappings stack_memory: 0, + symbol_storage_map: MutMap::default(), + // joinpoint_label_map: MutMap::default(), } } - pub fn build(&mut self, proc: Proc<'a>) -> Result<(), String> { + pub fn build_proc(&mut self, proc: Proc<'a>, sym: Symbol) -> Result { let ret_layout = WasmLayout::new(&proc.ret_layout)?; if ret_layout.stack_memory > 0 { // TODO: if returning a struct by value, add an extra argument for a pointer to callee's stack memory @@ -78,7 +102,25 @@ impl<'a> FunctionGenerator<'a> { } self.build_stmt(&proc.body, &proc.ret_layout)?; - Ok(()) + + let signature = builder::signature() + .with_params(self.arg_types.clone()) // requires std::Vec, not Bumpalo + .with_result(self.ret_type.clone()) + .build_sig(); + + let function_def = builder::function() + .with_signature(signature) + .body() + .with_locals(self.locals.clone()) + .with_instructions(Instructions::new(self.instructions.clone())) + .build() // body + .build(); // function + + let location = self.builder.push_function(function_def); + let function_index = location.body; + self.proc_symbol_map.insert(sym, location); + + Ok(function_index) } fn insert_local(&mut self, layout: WasmLayout, symbol: Symbol) -> LocalId { @@ -158,14 +200,10 @@ impl<'a> FunctionGenerator<'a> { for arg in *arguments { self.load_from_symbol(arg)?; } - let function_location = - self.module_state - .proc_symbol_map - .get(func_sym) - .ok_or(format!( - "Cannot find function {:?} called from {:?}", - func_sym, sym - ))?; + let function_location = self.proc_symbol_map.get(func_sym).ok_or(format!( + "Cannot find function {:?} called from {:?}", + func_sym, sym + ))?; self.instructions.push(Call(function_location.body)); self.store_to_symbol(sym)?; Ok(()) diff --git a/compiler/gen_wasm/src/lib.rs b/compiler/gen_wasm/src/lib.rs index d020707d3f..53c544e3fb 100644 --- a/compiler/gen_wasm/src/lib.rs +++ b/compiler/gen_wasm/src/lib.rs @@ -1,2 +1,62 @@ -pub mod module; -mod function; +mod backend; + +use bumpalo::Bump; +use parity_wasm::builder; +use parity_wasm::elements::Internal; + +use roc_collections::all::{MutMap, MutSet}; +use roc_module::symbol::{Interns, Symbol}; +use roc_mono::ir::{CallType, Expr, Proc, ProcLayout, Stmt}; +use roc_mono::layout::LayoutIds; + +use crate::backend::WasmBackend; + +pub struct Env<'a> { + pub arena: &'a Bump, // not really using this much, parity_wasm works with std::vec a lot + pub interns: Interns, + pub exposed_to_host: MutSet, +} + +pub fn build_module<'a>( + env: &'a Env, + procedures: MutMap<(Symbol, ProcLayout<'a>), Proc<'a>>, +) -> Result, String> { + let mut backend = WasmBackend::new(); + let mut layout_ids = LayoutIds::default(); + + let mut exports = std::vec::Vec::new(); + for ((sym, layout), proc) in procedures { + let function_index = backend.build_proc(proc, sym)?; + if env.exposed_to_host.contains(&sym) { + let fn_name = layout_ids + .get_toplevel(sym, &layout) + .to_symbol_string(sym, &env.interns); + + let export = builder::export() + .field(fn_name.as_str()) + .with_internal(Internal::Function(function_index)) + .build(); + + exports.push(export); + } + } + let module = backend.builder.build(); + module + .to_bytes() + .map_err(|e| -> String { format!("Error serialising Wasm module {:?}", e) }) +} + +// TODO: use something like this for very simple inlining +// Create a HashMap of inlined Procs, generate each call with different Symbol arguments +fn _is_lowlevel_wrapper<'a>(proc: Proc<'a>) -> bool { + match proc.body { + Stmt::Let(_, expr, _, Stmt::Ret(..)) => match expr { + Expr::Call(roc_mono::ir::Call { call_type, .. }) => match call_type { + CallType::LowLevel { .. } => true, + _ => false, + }, + _ => false, + }, + _ => false, + } +} diff --git a/compiler/gen_wasm/src/module.rs b/compiler/gen_wasm/src/module.rs deleted file mode 100644 index 408ea3b4fd..0000000000 --- a/compiler/gen_wasm/src/module.rs +++ /dev/null @@ -1,107 +0,0 @@ -use bumpalo::Bump; -use parity_wasm::builder::{CodeLocation, ModuleBuilder}; -use parity_wasm::elements::{Instructions, Internal}; -use parity_wasm::{builder, elements}; - -use roc_collections::all::{MutMap, MutSet}; -use roc_module::symbol::{Interns, Symbol}; -use roc_mono::ir::{CallType, Expr, Literal, Proc, ProcLayout, Stmt}; -use roc_mono::layout::LayoutIds; - -use crate::function::FunctionGenerator; - -pub struct Env<'a> { - pub arena: &'a Bump, // not really using this much, parity_wasm works with std::vec a lot - pub interns: Interns, - pub exposed_to_host: MutSet, -} - -// Don't allocate any constant data at the address zero or anywhere near it. -// These addresses are not special in Wasm, but putting something there seems bug-prone. -const UNUSED_DATA_SECTION_BYTES: u32 = 1024; - -pub fn build_module<'a>( - env: &'a Env, - procedures: MutMap<(Symbol, ProcLayout<'a>), Proc<'a>>, -) -> Result { - let mut module_state = ModuleState::new(env); - let mut layout_ids = LayoutIds::default(); - - for ((sym, layout), proc) in procedures { - let location = build_proc(&mut module_state, proc)?; - - if env.exposed_to_host.contains(&sym) { - let fn_name = layout_ids - .get_toplevel(sym, &layout) - .to_symbol_string(sym, &env.interns); - - let export = builder::export() - .field(fn_name.as_str()) - .with_internal(Internal::Function(location.body)) - .build(); - - module_state.module_builder.push_export(export); - } - module_state.proc_symbol_map.insert(sym, location); - } - - Ok(module_state.module_builder.build()) -} - -fn build_proc<'a>(module_state: &mut ModuleState, proc: Proc<'a>) -> Result { - // TODO: see if we can reuse the same memory each time and reset it? - // Can't convince the borrow-checker to let me do that, as things get moved into the function builder. - let mut func_gen = FunctionGenerator::new(module_state); - func_gen.build(proc)?; - - let signature = builder::signature() - .with_params(func_gen.arg_types) // requires std::Vec, not Bumpalo - .with_result(func_gen.ret_type) - .build_sig(); - - let function_def = builder::function() - .with_signature(signature) - .body() - .with_locals(func_gen.locals) - .with_instructions(Instructions::new(func_gen.instructions)) - .build() // body - .build(); // function - - let location = module_state.module_builder.push_function(function_def); - Ok(location) -} - -pub struct ModuleState<'a> { - _env: &'a Env<'a>, - module_builder: ModuleBuilder, - pub proc_symbol_map: MutMap, - pub _data_offset_map: MutMap, u32>, - pub _data_offset_next: u32, -} - -impl<'a> ModuleState<'a> { - fn new(_env: &'a Env) -> Self { - ModuleState { - _env, - module_builder: builder::module(), - proc_symbol_map: MutMap::default(), - _data_offset_map: MutMap::default(), - _data_offset_next: UNUSED_DATA_SECTION_BYTES, - } - } -} - -// TODO: use something like this for very simple inlining -// Create a HashMap of inlined Procs, generate each call with different Symbol arguments -fn _is_lowlevel_wrapper<'a>(proc: Proc<'a>) -> bool { - match proc.body { - Stmt::Let(_, expr, _, Stmt::Ret(..)) => match expr { - Expr::Call(roc_mono::ir::Call { call_type, .. }) => match call_type { - CallType::LowLevel { .. } => true, - _ => false, - }, - _ => false, - }, - _ => false, - } -} From 9ba7076d8e5c22066d53f79f9c01ce550cc15f4d Mon Sep 17 00:00:00 2001 From: Brian Carroll Date: Wed, 1 Sep 2021 19:07:01 +0100 Subject: [PATCH 10/42] Cleanups after self-review - Fix clippy warnings - Improve a comment - Delete commented-out lines in Cargo.toml - Checkin Cargo.lock --- Cargo.lock | 662 +++++++++++++++++-------------- compiler/gen_wasm/Cargo.toml | 12 - compiler/gen_wasm/src/backend.rs | 4 +- compiler/gen_wasm/src/lib.rs | 17 +- 4 files changed, 358 insertions(+), 337 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 7e1feca44c..265a73f085 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -9,7 +9,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "af0ac006645f86f20f6c6fa4dcaef920bf803df819123626f9440e35835e7d80" dependencies = [ "ab_glyph_rasterizer", - "owned_ttf_parser 0.12.0", + "owned_ttf_parser 0.12.1", ] [[package]] @@ -173,7 +173,7 @@ dependencies = [ "cfg-if 1.0.0", "libc", "miniz_oxide", - "object 0.26.1", + "object 0.26.2", "rustc-demangle", ] @@ -203,9 +203,9 @@ checksum = "349f9b6a179ed607305526ca489b34ad0a41aed5f7980fa90eb03160b69598fb" [[package]] name = "bitflags" -version = "1.2.1" +version = "1.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] name = "bitmaps" @@ -278,9 +278,9 @@ checksum = "e3b5ca7a04898ad4bcd41c90c5285445ff5b791899bb1b0abdd2a2aa791211d7" [[package]] name = "bytemuck" -version = "1.5.1" +version = "1.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bed57e2090563b83ba8f83366628ce535a7584c9afa4c9fc0612a03925c6df58" +checksum = "72957246c41db82b8ef88a5486143830adeb8227ef9837740bdec67724cf2c5b" dependencies = [ "bytemuck_derive", ] @@ -291,9 +291,9 @@ version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8e215f8c2f9f79cb53c8335e687ffd07d5bfcb6fe5fc80723762d0be46e7cc54" dependencies = [ - "proc-macro2 1.0.27", + "proc-macro2 1.0.29", "quote 1.0.9", - "syn 1.0.72", + "syn 1.0.75", ] [[package]] @@ -320,18 +320,18 @@ dependencies = [ [[package]] name = "cast" -version = "0.2.6" +version = "0.2.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "57cdfa5d50aad6cb4d44dcab6101a7f79925bd59d82ca42f38a9856a28865374" +checksum = "4c24dab4283a142afa2fdca129b80ad2c6284e073930f964c3a1293c225ee39a" dependencies = [ "rustc_version", ] [[package]] name = "cc" -version = "1.0.68" +version = "1.0.70" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4a72c244c1ff497a746a7e1fb3d14bd08420ecda70c8f25c7112f2781652d787" +checksum = "d26a6ce4b6a484fa3edb70f7efa6fc430fd2b87285fe8b84304fd0936faa0dc0" dependencies = [ "jobserver", ] @@ -399,9 +399,9 @@ source = "git+https://github.com/rtfeldman/clap?branch=master#e1d83a78804a271b05 dependencies = [ "heck", "proc-macro-error 0.4.12", - "proc-macro2 1.0.27", + "proc-macro2 1.0.29", "quote 1.0.9", - "syn 1.0.72", + "syn 1.0.75", ] [[package]] @@ -496,7 +496,7 @@ dependencies = [ [[package]] name = "confy" version = "0.4.0" -source = "git+https://github.com/rust-cli/confy#6ae700bb0e6e2f9f7138d0c1871f604013c8f59f" +source = "git+https://github.com/rust-cli/confy#664992aecd97b4af0eda8d9d2825885662e1c6b4" dependencies = [ "directories-next", "serde", @@ -505,9 +505,9 @@ dependencies = [ [[package]] name = "const_format" -version = "0.2.14" +version = "0.2.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c75ea7d6aeb2ebd1ee24f7b7e1b23242ef5a56b3a693733b99bfbe5ef31d0306" +checksum = "59c7d3aa11be45d56befebb10f4a8785fcb62aabddf5f33638efef922e505ec9" dependencies = [ "const_format_proc_macros", ] @@ -518,7 +518,7 @@ version = "0.2.14" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "29c36c619c422113552db4eb28cddba8faa757e33f758cc3415bd2885977b591" dependencies = [ - "proc-macro2 1.0.27", + "proc-macro2 1.0.29", "quote 1.0.9", "unicode-xid 0.2.2", ] @@ -627,9 +627,9 @@ dependencies = [ [[package]] name = "cpufeatures" -version = "0.1.4" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed00c67cb5d0a7d64a44f6ad2668db7e7530311dd53ea79bcd4fb022c64911c8" +checksum = "95059428f66df56b63431fdb4e1947ed2190586af5c5a8a8b71122bdf5a7f469" dependencies = [ "libc", ] @@ -706,14 +706,14 @@ dependencies = [ [[package]] name = "criterion" version = "0.3.5" -source = "git+https://github.com/Anton-4/criterion.rs#9bd532e35486a3b321d4012534d3e97751a53f85" +source = "git+https://github.com/Anton-4/criterion.rs#3e46ad2b234e36928fb5234d36cf53b5837cbb87" dependencies = [ "atty", "cast", "clap 2.33.3", "criterion-plot", "csv", - "itertools 0.10.0", + "itertools 0.10.1", "lazy_static", "num-traits", "oorandom", @@ -731,7 +731,7 @@ dependencies = [ [[package]] name = "criterion-plot" version = "0.4.3" -source = "git+https://github.com/Anton-4/criterion.rs#9bd532e35486a3b321d4012534d3e97751a53f85" +source = "git+https://github.com/Anton-4/criterion.rs#3e46ad2b234e36928fb5234d36cf53b5837cbb87" dependencies = [ "cast", "itertools 0.9.0", @@ -745,7 +745,7 @@ checksum = "69323bff1fb41c635347b8ead484a5ca6c3f11914d784170b158d8449ab07f8e" dependencies = [ "cfg-if 0.1.10", "crossbeam-channel 0.4.4", - "crossbeam-deque 0.7.3", + "crossbeam-deque 0.7.4", "crossbeam-epoch 0.8.2", "crossbeam-queue", "crossbeam-utils 0.7.2", @@ -773,9 +773,9 @@ dependencies = [ [[package]] name = "crossbeam-deque" -version = "0.7.3" +version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9f02af974daeee82218205558e51ec8768b48cf524bd01d550abe5573a608285" +checksum = "c20ff29ded3204c5106278a81a38f4b482636ed4fa1e6cfbeef193291beb29ed" dependencies = [ "crossbeam-epoch 0.8.2", "crossbeam-utils 0.7.2", @@ -784,9 +784,9 @@ dependencies = [ [[package]] name = "crossbeam-deque" -version = "0.8.0" +version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94af6efb46fef72616855b036a624cf27ba656ffc9be1b9a3c931cfc7749a9a9" +checksum = "6455c0ca19f0d2fbf751b908d5c55c1f5cbc65e03c4225427254b46890bdde1e" dependencies = [ "cfg-if 1.0.0", "crossbeam-epoch 0.9.5", @@ -877,19 +877,19 @@ dependencies = [ [[package]] name = "ctor" -version = "0.1.20" +version = "0.1.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5e98e2ad1a782e33928b96fc3948e7c355e5af34ba4de7670fe8bac2a3b2006d" +checksum = "ccc0a48a9b826acdf4028595adc9db92caea352f7af011a3034acd172a52a0aa" dependencies = [ "quote 1.0.9", - "syn 1.0.72", + "syn 1.0.75", ] [[package]] name = "d3d12" -version = "0.4.0" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "091ed1b25fe47c7ff129fc440c23650b6114f36aa00bc7212cc8041879294428" +checksum = "2daefd788d1e96e0a9d66dee4b828b883509bc3ea9ce30665f04c3246372690c" dependencies = [ "bitflags", "libloading 0.7.0", @@ -924,10 +924,10 @@ checksum = "f0c960ae2da4de88a91b2d920c2a7233b400bc33cb28453a2987822d8392519b" dependencies = [ "fnv", "ident_case", - "proc-macro2 1.0.27", + "proc-macro2 1.0.29", "quote 1.0.9", "strsim 0.9.3", - "syn 1.0.72", + "syn 1.0.75", ] [[package]] @@ -938,10 +938,10 @@ checksum = "2c34d8efb62d0c2d7f60ece80f75e5c63c1588ba68032740494b0b9a996466e3" dependencies = [ "fnv", "ident_case", - "proc-macro2 1.0.27", + "proc-macro2 1.0.29", "quote 1.0.9", "strsim 0.10.0", - "syn 1.0.72", + "syn 1.0.75", ] [[package]] @@ -952,7 +952,7 @@ checksum = "d9b5a2f4ac4969822c62224815d069952656cadc7084fdca9751e6d959189b72" dependencies = [ "darling_core 0.10.2", "quote 1.0.9", - "syn 1.0.72", + "syn 1.0.75", ] [[package]] @@ -963,7 +963,7 @@ checksum = "ade7bff147130fe5e6d39f089c6bd49ec0250f35d70b2eebf72afdfc919f15cc" dependencies = [ "darling_core 0.13.0", "quote 1.0.9", - "syn 1.0.72", + "syn 1.0.75", ] [[package]] @@ -972,9 +972,9 @@ version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fcc3dd5e9e9c0b295d6e1e4d811fb6f157d5ffd784b8d202fc62eac8035a770b" dependencies = [ - "proc-macro2 1.0.27", + "proc-macro2 1.0.29", "quote 1.0.9", - "syn 1.0.72", + "syn 1.0.75", ] [[package]] @@ -1117,9 +1117,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6451128aa6655d880755345d085494cf7561a6bee7c8dc821e5d77e6d267ecd4" dependencies = [ "darling 0.13.0", - "proc-macro2 1.0.27", + "proc-macro2 1.0.29", "quote 1.0.9", - "syn 1.0.72", + "syn 1.0.75", ] [[package]] @@ -1134,9 +1134,9 @@ dependencies = [ [[package]] name = "env_logger" -version = "0.8.3" +version = "0.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "17392a012ea30ef05a610aa97dfb49496e71c9f676b27879922ea5bdf60d9d3f" +checksum = "a19187fea3ac7e84da7dacf48de0c45d63c6a76f9490dae389aead16c243fce3" dependencies = [ "atty", "humantime", @@ -1184,9 +1184,9 @@ checksum = "37ab347416e802de484e4d03c7316c48f1ecb56574dfd4a46a80f173ce1de04d" [[package]] name = "flate2" -version = "1.0.20" +version = "1.0.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cd3aec53de10fe96d7d8c565eb17f2c687bb5518a2ec453b5b1252964526abe0" +checksum = "80edafed416a46fb378521624fab1cfa2eb514784fd8921adbe8a8d8321da811" dependencies = [ "cfg-if 1.0.0", "crc32fast", @@ -1239,9 +1239,9 @@ checksum = "3dcaa9ae7725d12cdb85b3ad99a434db70b468c09ded17e012d86b5c1010f7a7" [[package]] name = "futures" -version = "0.3.15" +version = "0.3.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0e7e43a803dae2fa37c1f6a8fe121e1f7bf9548b4dfc0522a42f34145dadfc27" +checksum = "a12aa0eb539080d55c3f2d45a67c3b58b6b0773c1a3ca2dfec66d58c97fd66ca" dependencies = [ "futures-channel", "futures-core", @@ -1254,9 +1254,9 @@ dependencies = [ [[package]] name = "futures-channel" -version = "0.3.15" +version = "0.3.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e682a68b29a882df0545c143dc3646daefe80ba479bcdede94d5a703de2871e2" +checksum = "5da6ba8c3bb3c165d3c7319fc1cc8304facf1fb8db99c5de877183c08a273888" dependencies = [ "futures-core", "futures-sink", @@ -1264,15 +1264,15 @@ dependencies = [ [[package]] name = "futures-core" -version = "0.3.15" +version = "0.3.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0402f765d8a89a26043b889b26ce3c4679d268fa6bb22cd7c6aad98340e179d1" +checksum = "88d1c26957f23603395cd326b0ffe64124b818f4449552f960d815cfba83a53d" [[package]] name = "futures-executor" -version = "0.3.15" +version = "0.3.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "badaa6a909fac9e7236d0620a2f57f7664640c56575b71a7552fbd68deafab79" +checksum = "45025be030969d763025784f7f355043dc6bc74093e4ecc5000ca4dc50d8745c" dependencies = [ "futures-core", "futures-task", @@ -1281,40 +1281,40 @@ dependencies = [ [[package]] name = "futures-io" -version = "0.3.15" +version = "0.3.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "acc499defb3b348f8d8f3f66415835a9131856ff7714bf10dadfc4ec4bdb29a1" +checksum = "522de2a0fe3e380f1bc577ba0474108faf3f6b18321dbf60b3b9c39a75073377" [[package]] name = "futures-macro" -version = "0.3.15" +version = "0.3.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4c40298486cdf52cc00cd6d6987892ba502c7656a16a4192a9992b1ccedd121" +checksum = "18e4a4b95cea4b4ccbcf1c5675ca7c4ee4e9e75eb79944d07defde18068f79bb" dependencies = [ "autocfg 1.0.1", "proc-macro-hack", - "proc-macro2 1.0.27", + "proc-macro2 1.0.29", "quote 1.0.9", - "syn 1.0.72", + "syn 1.0.75", ] [[package]] name = "futures-sink" -version = "0.3.15" +version = "0.3.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a57bead0ceff0d6dde8f465ecd96c9338121bb7717d3e7b108059531870c4282" +checksum = "36ea153c13024fe480590b3e3d4cad89a0cfacecc24577b68f86c6ced9c2bc11" [[package]] name = "futures-task" -version = "0.3.15" +version = "0.3.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a16bef9fc1a4dddb5bee51c989e3fbba26569cbb0e31f5b303c184e3dd33dae" +checksum = "1d3d00f4eddb73e498a54394f228cd55853bdf059259e8e7bc6e69d408892e99" [[package]] name = "futures-util" -version = "0.3.15" +version = "0.3.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "feb5c238d27e2bf94ffdfd27b2c29e3df4a68c4193bb6427384259e2bf191967" +checksum = "36568465210a3a6ee45e1f165136d68671471a501e632e9a98d96872222b5481" dependencies = [ "autocfg 1.0.1", "futures-channel", @@ -1324,7 +1324,7 @@ dependencies = [ "futures-sink", "futures-task", "memchr", - "pin-project-lite 0.2.6", + "pin-project-lite 0.2.7", "pin-utils", "proc-macro-hack", "proc-macro-nested", @@ -1340,6 +1340,18 @@ dependencies = [ "byteorder", ] +[[package]] +name = "gen_wasm" +version = "0.1.0" +dependencies = [ + "bumpalo", + "parity-wasm", + "roc_collections", + "roc_module", + "roc_mono", + "wasmer", +] + [[package]] name = "generational-arena" version = "0.2.8" @@ -1427,9 +1439,9 @@ dependencies = [ [[package]] name = "gfx-backend-dx12" -version = "0.9.0" +version = "0.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "61f09e9d8c2aa69e9a21eb83c0f5d1a286c6d37da011f796e550d180b08090ce" +checksum = "21506399f64a3c4d389182a89a30073856ae33eb712315456b4fd8f39ee7682a" dependencies = [ "arrayvec", "bit-set", @@ -1559,9 +1571,9 @@ version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1a5bcf1bbeab73aa4cf2fde60a846858dc036163c7c33bec309f8d17de785479" dependencies = [ - "proc-macro2 1.0.27", + "proc-macro2 1.0.29", "quote 1.0.9", - "syn 1.0.72", + "syn 1.0.75", ] [[package]] @@ -1615,7 +1627,7 @@ checksum = "ac2c82074cafb68b9e459c50c655f7eedcb92d6ee7166813802934bc6fc29fa3" dependencies = [ "ab_glyph", "crossbeam-channel 0.5.1", - "crossbeam-deque 0.8.0", + "crossbeam-deque 0.8.1", "linked-hash-map", "rayon", "rustc-hash", @@ -1623,9 +1635,9 @@ dependencies = [ [[package]] name = "glyph_brush_layout" -version = "0.2.2" +version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "15cf18cf985bd942f05e14552b63c9d08f7d0ed1ec79a977eb9747c9e065f497" +checksum = "cc32c2334f00ca5ac3695c5009ae35da21da8c62d255b5b96d56e2597a637a38" dependencies = [ "ab_glyph", "approx 0.5.0", @@ -1707,9 +1719,9 @@ dependencies = [ [[package]] name = "hermit-abi" -version = "0.1.18" +version = "0.1.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "322f4de77956e22ed0e5032c359a0f1273f1f7f0d79bfa3b8ffbc730d7fbcc5c" +checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33" dependencies = [ "libc", ] @@ -1784,12 +1796,12 @@ dependencies = [ [[package]] name = "indexmap" -version = "1.6.2" +version = "1.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "824845a0bf897a9042383849b02c1bc219c2383772efcd5c6f9766fa4b81aef3" +checksum = "bc633605454125dec4b66843673f01c7df2b89479b32e0ed634e43a91cff62a5" dependencies = [ "autocfg 1.0.1", - "hashbrown 0.9.1", + "hashbrown 0.11.2", "serde", ] @@ -1819,9 +1831,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ce046d161f000fffde5f432a0d034d0341dc152643b2598ed5bfce44c4f3a8f0" dependencies = [ "proc-macro-hack", - "proc-macro2 1.0.27", + "proc-macro2 1.0.29", "quote 1.0.9", - "syn 1.0.72", + "syn 1.0.75", "unindent", ] @@ -1851,9 +1863,9 @@ name = "inkwell_internals" version = "0.3.0" source = "git+https://github.com/rtfeldman/inkwell?tag=llvm12-0.release5#b5aa51313d4cfa4e1b52ad630cb786140671478b" dependencies = [ - "proc-macro2 1.0.27", + "proc-macro2 1.0.29", "quote 1.0.9", - "syn 1.0.72", + "syn 1.0.75", ] [[package]] @@ -1870,9 +1882,9 @@ checksum = "90953f308a79fe6d62a4643e51f848fbfddcd05975a38e69fdf4ab86a7baf7ca" [[package]] name = "instant" -version = "0.1.9" +version = "0.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "61124eeebbd69b8190558df225adf7e4caafce0d743919e5d6b19652314ec5ec" +checksum = "bee0328b1209d157ef001c94dd85b4f8f64139adb0eac2659f4b08382b2f474d" dependencies = [ "cfg-if 1.0.0", ] @@ -1894,9 +1906,9 @@ version = "0.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "75c094e94816723ab936484666968f5b58060492e880f3c8d00489a1e244fa51" dependencies = [ - "proc-macro2 1.0.27", + "proc-macro2 1.0.29", "quote 1.0.9", - "syn 1.0.72", + "syn 1.0.75", ] [[package]] @@ -1919,18 +1931,18 @@ dependencies = [ [[package]] name = "itertools" -version = "0.10.0" +version = "0.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "37d572918e350e82412fe766d24b15e6682fb2ed2bbe018280caa810397cb319" +checksum = "69ddb889f9d0d08a67338271fa9b62996bc788c7796a5c18cf057420aaed5eaf" dependencies = [ "either", ] [[package]] name = "itoa" -version = "0.4.7" +version = "0.4.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd25036021b0de88a0aff6b850051563c6516d0bf53f8638938edbb9de732736" +checksum = "b71991ff56294aa922b450139ee08b3bfc70982c6b2c7562771375cf73542dd4" [[package]] name = "jni-sys" @@ -1940,18 +1952,18 @@ checksum = "8eaf4bc02d17cbdd7ff4c7438cafcdf7fb9a4613313ad11b4f8fefe7d3fa0130" [[package]] name = "jobserver" -version = "0.1.22" +version = "0.1.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "972f5ae5d1cb9c6ae417789196c803205313edde988685da5e3aae0827b9e7fd" +checksum = "af25a77299a7f711a01975c35a6a424eb6862092cc2d6c72c4ed6cbc56dfc1fa" dependencies = [ "libc", ] [[package]] name = "js-sys" -version = "0.3.51" +version = "0.3.53" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "83bdfbace3a0e81a4253f73b49e960b053e396a11012cbd49b9b74d6a2b67062" +checksum = "e4bf49d50e2961077d9c99f4b7997d770a1114f087c3c2e0069b36c13fc2979d" dependencies = [ "wasm-bindgen", ] @@ -2002,9 +2014,9 @@ checksum = "3576a87f2ba00f6f106fdfcd16db1d698d648a26ad8e0573cad8537c3c362d2a" [[package]] name = "libc" -version = "0.2.96" +version = "0.2.101" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5600b4e6efc5421841a2138a6b082e07fe12f9aaa12783d50e5d13325b26b4fc" +checksum = "3cb00336871be5ed2c8ed44b60ae9959dc5b9f08539422ed43f09e34ecaeba21" [[package]] name = "libloading" @@ -2034,22 +2046,22 @@ checksum = "7fb9b38af92608140b86b693604b9ffcc5824240a484d1ecd4795bacb2fe88f3" [[package]] name = "llvm-sys" -version = "120.0.0" +version = "120.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b883556196140c6b6e7a18b19236b9a699c8611aad2e48a0a6403cf1123945a" +checksum = "7cd0739fb23e5d801f6ff11a9d587448bdd86dea2459ba2b57fbed90a9ae1b5a" dependencies = [ "cc", "lazy_static", "libc", "regex", - "semver", + "semver 0.11.0", ] [[package]] name = "lock_api" -version = "0.4.4" +version = "0.4.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0382880606dff6d15c9476c416d18690b72742aa7b605bb6dd6ec9030fbf07eb" +checksum = "712a4d093c9976e24e7dbca41db895dabcbac38eb5f4045393d17a95bdfb1109" dependencies = [ "scopeguard", ] @@ -2081,7 +2093,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c0fbfc88337168279f2e9ae06e157cfed4efd3316e14dc96ed074d4f2e6c5952" dependencies = [ "quote 1.0.9", - "syn 1.0.72", + "syn 1.0.75", ] [[package]] @@ -2158,9 +2170,9 @@ dependencies = [ [[package]] name = "metal" -version = "0.23.0" +version = "0.23.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "79d7d769f1c104b8388294d6594d491d2e21240636f5f94d37f8a0f3d7904450" +checksum = "e0514f491f4cc03632ab399ee01e2c1c1b12d3e1cf2d667c1ff5f87d6dcd2084" dependencies = [ "bitflags", "block", @@ -2170,6 +2182,12 @@ dependencies = [ "objc", ] +[[package]] +name = "minimal-lexical" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6595bb28ed34f43c3fe088e48f6cfb2e033cab45f25a5384d5fdf564fbc8c4b2" + [[package]] name = "miniz_oxide" version = "0.4.4" @@ -2290,9 +2308,9 @@ checksum = "05d1c6307dc424d0f65b9b06e94f88248e6305726b14729fd67a5e47b2dc481d" dependencies = [ "darling 0.10.2", "proc-macro-crate", - "proc-macro2 1.0.27", + "proc-macro2 1.0.29", "quote 1.0.9", - "syn 1.0.72", + "syn 1.0.75", ] [[package]] @@ -2351,11 +2369,12 @@ dependencies = [ [[package]] name = "nom" -version = "6.1.2" +version = "7.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e7413f999671bd4745a7b624bd370a569fb6bc574b23c83a3c5ed2e453f3d5e2" +checksum = "7ffd9d26838a953b4af82cbeb9f1592c6798916983959be223a7124e992742c1" dependencies = [ "memchr", + "minimal-lexical", "version_check", ] @@ -2401,9 +2420,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ffa5a33ddddfee04c0283a7653987d634e880347e96b5b2ed64de07efb59db9d" dependencies = [ "proc-macro-crate", - "proc-macro2 1.0.27", + "proc-macro2 1.0.29", "quote 1.0.9", - "syn 1.0.72", + "syn 1.0.75", ] [[package]] @@ -2469,18 +2488,18 @@ dependencies = [ [[package]] name = "object" -version = "0.26.1" +version = "0.26.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ee2766204889d09937d00bfbb7fec56bb2a199e2ade963cab19185d8a6104c7c" +checksum = "39f37e50073ccad23b6d09bcb5b263f4e76d3bb6038e4a3c08e52162ffa8abc2" dependencies = [ "memchr", ] [[package]] name = "once_cell" -version = "1.7.2" +version = "1.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af8b08b04175473088b46763e51ee54da5f9a164bc162f615b91bc179dbf15a3" +checksum = "692fcb63b64b1758029e0a96ee63e049ce8c5948587f2f7208df04625e5f6b56" [[package]] name = "oorandom" @@ -2502,9 +2521,9 @@ checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5" [[package]] name = "ordered-float" -version = "2.5.1" +version = "2.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f100fcfb41e5385e0991f74981732049f9b896821542a219420491046baafdc2" +checksum = "039f02eb0f69271f26abe3202189275d7aa2258b903cb0281b5de710a2570ff3" dependencies = [ "num-traits", ] @@ -2529,11 +2548,11 @@ dependencies = [ [[package]] name = "owned_ttf_parser" -version = "0.12.0" +version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3a3c7a20e3f122223e68eef6ca58e39bc1ea8a1d83418ba4c2c1ba189d2ee355" +checksum = "60ac8dda2e5cc09bf6480e3b3feff9783db251710c922ae9369a429c51efdeb0" dependencies = [ - "ttf-parser 0.12.1", + "ttf-parser 0.12.3", ] [[package]] @@ -2565,16 +2584,22 @@ version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0b4b5f600e60dd3a147fb57b4547033d382d1979eb087af310e91cb45a63b1f4" dependencies = [ - "proc-macro2 1.0.27", + "proc-macro2 1.0.29", "quote 1.0.9", - "syn 1.0.72", + "syn 1.0.75", ] [[package]] -name = "parking_lot" -version = "0.11.1" +name = "parity-wasm" +version = "0.42.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6d7744ac029df22dca6284efe4e898991d28e3085c706c972bcd7da4a27a15eb" +checksum = "be5e13c266502aadf83426d87d81a0f5d1ef45b8027f5a471c360abfe4bfae92" + +[[package]] +name = "parking_lot" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7d17b78036a60663b797adeaee46f5c9dfebb86948d1255007a1d6be0271ff99" dependencies = [ "instant", "lock_api", @@ -2583,16 +2608,16 @@ dependencies = [ [[package]] name = "parking_lot_core" -version = "0.8.3" +version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa7a782938e745763fe6907fc6ba86946d72f49fe7e21de074e08128a99fb018" +checksum = "d76e8e1493bcac0d2766c42737f34458f1c8c50c0d23bcb24ea953affb273216" dependencies = [ "backtrace", "cfg-if 1.0.0", "instant", "libc", "petgraph", - "redox_syscall 0.2.8", + "redox_syscall", "smallvec", "thread-id", "winapi 0.3.9", @@ -2631,9 +2656,9 @@ checksum = "99b8db626e31e5b81787b9783425769681b347011cc59471e33ea46d2ea0cf55" dependencies = [ "pest", "pest_meta", - "proc-macro2 1.0.27", + "proc-macro2 1.0.29", "quote 1.0.9", - "syn 1.0.72", + "syn 1.0.75", ] [[package]] @@ -2703,9 +2728,9 @@ checksum = "257b64915a082f7811703966789728173279bdebb956b143dbcd23f6f970a777" [[package]] name = "pin-project-lite" -version = "0.2.6" +version = "0.2.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc0e1f259c92177c30a4c9d177246edd0a3568b25756a977d0632cf8fa37e905" +checksum = "8d31d11c69a6b52a174b42bdc0c30e5e11670f90788b2c471c31c1d17d449443" [[package]] name = "pin-utils" @@ -2733,15 +2758,15 @@ dependencies = [ [[package]] name = "plotters-backend" -version = "0.3.0" +version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b07fffcddc1cb3a1de753caa4e4df03b79922ba43cf882acc1bdd7e8df9f4590" +checksum = "d88417318da0eaf0fdcdb51a0ee6c3bed624333bff8f946733049380be67ac1c" [[package]] name = "plotters-svg" -version = "0.3.0" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b38a02e23bd9604b842a812063aec4ef702b57989c37b655254bb61c471ad211" +checksum = "521fa9638fa597e1dc53e9412a4f9cefb01187ee1f7413076f9e6749e2885ba9" dependencies = [ "plotters-backend", ] @@ -2790,9 +2815,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "18f33027081eba0a6d8aba6d1b1c3a3be58cbb12106341c2d5759fcd9b5277e7" dependencies = [ "proc-macro-error-attr 0.4.12", - "proc-macro2 1.0.27", + "proc-macro2 1.0.29", "quote 1.0.9", - "syn 1.0.72", + "syn 1.0.75", "version_check", ] @@ -2803,9 +2828,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c" dependencies = [ "proc-macro-error-attr 1.0.4", - "proc-macro2 1.0.27", + "proc-macro2 1.0.29", "quote 1.0.9", - "syn 1.0.72", + "syn 1.0.75", "version_check", ] @@ -2815,9 +2840,9 @@ version = "0.4.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8a5b4b77fdb63c1eca72173d68d24501c54ab1269409f6b672c85deb18af69de" dependencies = [ - "proc-macro2 1.0.27", + "proc-macro2 1.0.29", "quote 1.0.9", - "syn 1.0.72", + "syn 1.0.75", "syn-mid", "version_check", ] @@ -2828,7 +2853,7 @@ version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869" dependencies = [ - "proc-macro2 1.0.27", + "proc-macro2 1.0.29", "quote 1.0.9", "version_check", ] @@ -2856,18 +2881,18 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.27" +version = "1.0.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f0d8caf72986c1a598726adc988bb5984792ef84f5ee5aa50209145ee8077038" +checksum = "b9f5105d4fdaab20335ca9565e106a5d9b82b6219b5ba735731124ac6711d23d" dependencies = [ "unicode-xid 0.2.2", ] [[package]] name = "profiling" -version = "1.0.2" +version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0a7c000c0ce9d9bb94c0fbacdf20e5087fbe652c556ffb2c9387d980e17d51fb" +checksum = "87dfd5592a8eed7e74f56ad7b125f8234763b805c30f0c7c95c486920026a6ec" [[package]] name = "ptr_meta" @@ -2884,9 +2909,9 @@ version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "16b845dbfca988fa33db069c0e230574d15a3088f147a87b64c7589eb662c9ac" dependencies = [ - "proc-macro2 1.0.27", + "proc-macro2 1.0.29", "quote 1.0.9", - "syn 1.0.72", + "syn 1.0.75", ] [[package]] @@ -2918,9 +2943,9 @@ version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "588f6378e4dd99458b60ec275b4477add41ce4fa9f64dcba6f15adccb19b50d6" dependencies = [ - "env_logger 0.8.3", + "env_logger 0.8.4", "log", - "rand 0.8.3", + "rand 0.8.4", ] [[package]] @@ -2940,9 +2965,9 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b22a693222d716a9587786f37ac3f6b4faedb5b80c23914e7303ff5a1d8016e9" dependencies = [ - "proc-macro2 1.0.27", + "proc-macro2 1.0.29", "quote 1.0.9", - "syn 1.0.72", + "syn 1.0.75", ] [[package]] @@ -2960,7 +2985,7 @@ version = "1.0.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c3d0b9745dc2debf507c8422de05d7226cc1f0644216dfdfead988f9b1ab32a7" dependencies = [ - "proc-macro2 1.0.27", + "proc-macro2 1.0.29", ] [[package]] @@ -2998,14 +3023,14 @@ dependencies = [ [[package]] name = "rand" -version = "0.8.3" +version = "0.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ef9e7e66b4468674bfcb0c81af8b7fa0bb154fa9f28eb840da5c447baeb8d7e" +checksum = "2e7573632e6454cf6b99d7aac4ccca54be06da05aca2ef7423d22d27d4d4bcd8" dependencies = [ "libc", - "rand_chacha 0.3.0", - "rand_core 0.6.2", - "rand_hc 0.3.0", + "rand_chacha 0.3.1", + "rand_core 0.6.3", + "rand_hc 0.3.1", ] [[package]] @@ -3030,12 +3055,12 @@ dependencies = [ [[package]] name = "rand_chacha" -version = "0.3.0" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e12735cf05c9e10bf21534da50a147b924d555dc7a547c42e6bb2d5b6017ae0d" +checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" dependencies = [ "ppv-lite86", - "rand_core 0.6.2", + "rand_core 0.6.3", ] [[package]] @@ -3064,9 +3089,9 @@ dependencies = [ [[package]] name = "rand_core" -version = "0.6.2" +version = "0.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "34cf66eb183df1c5876e2dcf6b13d57340741e8dc255b48e40a26de954d06ae7" +checksum = "d34f1408f55294453790c48b2f1ebbb1c5b4b7563eb1f418bcfcfdbb06ebb4e7" dependencies = [ "getrandom 0.2.3", ] @@ -3091,11 +3116,11 @@ dependencies = [ [[package]] name = "rand_hc" -version = "0.3.0" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3190ef7066a446f2e7f42e239d161e905420ccab01eb967c9eb27d21b2322a73" +checksum = "d51e9f596de227fda2ea6c84607f5558e196eeaf43c986b724ba4fb8fdf497e7" dependencies = [ - "rand_core 0.6.2", + "rand_core 0.6.3", ] [[package]] @@ -3191,7 +3216,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c06aca804d41dbc8ba42dfd964f0d01334eceb64314b9ecf7c5fad5188a06d90" dependencies = [ "autocfg 1.0.1", - "crossbeam-deque 0.8.0", + "crossbeam-deque 0.8.1", "either", "rayon-core", ] @@ -3203,7 +3228,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d78120e2c850279833f1dd3582f730c4ab53ed95aeaaaa862a2a5c71b1656d8e" dependencies = [ "crossbeam-channel 0.5.1", - "crossbeam-deque 0.8.0", + "crossbeam-deque 0.8.1", "crossbeam-utils 0.8.5", "lazy_static", "num_cpus", @@ -3220,15 +3245,9 @@ dependencies = [ [[package]] name = "redox_syscall" -version = "0.1.57" +version = "0.2.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "41cc0f7e4d5d4544e8861606a285bb08d3e70712ccc7d2b84d7c0ccfaf4b05ce" - -[[package]] -name = "redox_syscall" -version = "0.2.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "742739e41cd49414de871ea5e549afb7e2a3ac77b589bcbebe8c82fab37147fc" +checksum = "8383f39639269cde97d255a32bdb68c047337295414940c68bdd30c2e13203ff" dependencies = [ "bitflags", ] @@ -3240,7 +3259,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "528532f3d801c87aec9def2add9ca802fe569e44a544afe633765267840abe64" dependencies = [ "getrandom 0.2.3", - "redox_syscall 0.2.8", + "redox_syscall", ] [[package]] @@ -3322,9 +3341,9 @@ version = "0.6.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ba8f489f6b6d8551bb15904293c1ad58a6abafa7d8390d15f7ed05a2afcd87d5" dependencies = [ - "proc-macro2 1.0.27", + "proc-macro2 1.0.29", "quote 1.0.9", - "syn 1.0.72", + "syn 1.0.75", ] [[package]] @@ -3514,7 +3533,7 @@ dependencies = [ "colored", "confy", "copypasta", - "env_logger 0.8.3", + "env_logger 0.8.4", "futures", "glyph_brush", "im 15.0.0", @@ -3531,7 +3550,7 @@ dependencies = [ "pretty_assertions 0.6.1", "quickcheck 1.0.3", "quickcheck_macros 1.0.0", - "rand 0.8.3", + "rand 0.8.4", "roc_can", "roc_collections", "roc_fmt", @@ -3843,9 +3862,9 @@ dependencies = [ [[package]] name = "ropey" -version = "1.2.0" +version = "1.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f0f3ef16589fdbb3e8fbce3dca944c08e61f39c7f16064b21a257d68ea911a83" +checksum = "9150aff6deb25b20ed110889f070a678bcd1033e46e5e9d6fb1abeab17947f28" dependencies = [ "smallvec", ] @@ -3861,9 +3880,9 @@ dependencies = [ [[package]] name = "rustc-demangle" -version = "0.1.19" +version = "0.1.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "410f7acf3cb3a44527c5d9546bad4bf4e6c460915d5f9f2fc524498bfe8f70ce" +checksum = "7ef03e0a2b150c7a90d01faf6254c9c48a41e95fb2a8c2ac1c6f0d2b9aefc342" [[package]] name = "rustc-hash" @@ -3873,11 +3892,11 @@ checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" [[package]] name = "rustc_version" -version = "0.3.3" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f0dfe2087c51c460008730de8b57e6a320782fbfb312e1f4d520e6c6fae155ee" +checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366" dependencies = [ - "semver", + "semver 1.0.4", ] [[package]] @@ -3910,7 +3929,7 @@ dependencies = [ "scopeguard", "unicode-segmentation", "unicode-width", - "utf8parse 0.2.0", + "utf8parse", "winapi 0.3.9", ] @@ -3920,7 +3939,7 @@ version = "0.3.1" source = "git+https://github.com/rtfeldman/rustyline?tag=prompt-fix#a6b8a20d2bf5c3793d7367848be2f4afec2f0d99" dependencies = [ "quote 1.0.9", - "syn 1.0.72", + "syn 1.0.75", ] [[package]] @@ -3965,6 +3984,12 @@ dependencies = [ "semver-parser", ] +[[package]] +name = "semver" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "568a8e6258aa33c13358f81fd834adb854c6f7c9468520910a9b1e8fac068012" + [[package]] name = "semver-parser" version = "0.10.2" @@ -3976,9 +4001,9 @@ dependencies = [ [[package]] name = "serde" -version = "1.0.126" +version = "1.0.130" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec7505abeacaec74ae4778d9d9328fe5a5d04253220a85c4ee022239fc996d03" +checksum = "f12d06de37cf59146fbdecab66aa99f9fe4f78722e3607577a5375d66bd0c913" dependencies = [ "serde_derive", ] @@ -4006,9 +4031,9 @@ dependencies = [ [[package]] name = "serde_cbor" -version = "0.11.1" +version = "0.11.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e18acfa2f90e8b735b2836ab8d538de304cbb6729a7360729ea5a895d15a622" +checksum = "2bef2ebfde456fb76bbcf9f59315333decc4fda0b2b44b420243c11e0f5ec1f5" dependencies = [ "half", "serde", @@ -4016,20 +4041,20 @@ dependencies = [ [[package]] name = "serde_derive" -version = "1.0.126" +version = "1.0.130" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "963a7dbc9895aeac7ac90e74f34a5d5261828f79df35cbed41e10189d3804d43" +checksum = "d7bc1a1ab1961464eae040d96713baa5a724a8152c1222492465b54322ec508b" dependencies = [ - "proc-macro2 1.0.27", + "proc-macro2 1.0.29", "quote 1.0.9", - "syn 1.0.72", + "syn 1.0.75", ] [[package]] name = "serde_json" -version = "1.0.64" +version = "1.0.67" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "799e97dc9fdae36a5c8b8f2cae9ce2ee9fdce2058c57a93e6099d919fd982f79" +checksum = "a7f9e390c27c3c0ce8bc5d725f6e4d30a29d26659494aa4b17535f7522c5c950" dependencies = [ "itoa", "ryu", @@ -4038,12 +4063,12 @@ dependencies = [ [[package]] name = "serde_yaml" -version = "0.8.17" +version = "0.8.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "15654ed4ab61726bf918a39cb8d98a2e2995b002387807fa6ba58fdf7f59bb23" +checksum = "ad104641f3c958dab30eb3010e834c2622d1f3f4c530fef1dee20ad9485f3c09" dependencies = [ "dtoa", - "linked-hash-map", + "indexmap", "serde", "yaml-rust", ] @@ -4065,9 +4090,9 @@ version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b2acd6defeddb41eb60bb468f8825d0cfd0c2a76bc03bfd235b6a1dc4f6a1ad5" dependencies = [ - "proc-macro2 1.0.27", + "proc-macro2 1.0.29", "quote 1.0.9", - "syn 1.0.72", + "syn 1.0.75", ] [[package]] @@ -4084,9 +4109,9 @@ dependencies = [ [[package]] name = "sha2" -version = "0.9.5" +version = "0.9.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b362ae5752fd2137731f9fa25fd4d9058af34666ca1966fb969119cc35719f12" +checksum = "9204c41a1597a8c5af23c82d1c921cb01ec0a4c59e07a9c7306062829a3903f3" dependencies = [ "block-buffer 0.9.0", "cfg-if 1.0.0", @@ -4097,9 +4122,9 @@ dependencies = [ [[package]] name = "siphasher" -version = "0.3.5" +version = "0.3.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cbce6d4507c7e4a3962091436e56e95290cb71fa302d0d270e32130b75fbff27" +checksum = "729a25c17d72b06c68cb47955d44fda88ad2d3e7d77e025663fdd69b93dd71a1" [[package]] name = "sized-chunks" @@ -4123,15 +4148,15 @@ dependencies = [ [[package]] name = "slab" -version = "0.4.3" +version = "0.4.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f173ac3d1a7e3b28003f40de0b5ce7fe2710f9b9dc3fc38664cebee46b3b6527" +checksum = "c307a32c1c5c437f38c7fd45d753050587732ba8628319fbdf12a7e289ccc590" [[package]] name = "slotmap" -version = "0.4.0" +version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c46a3482db8f247956e464d783693ece164ca056e6e67563ee5505bdb86452cd" +checksum = "6bf34684c5767b87de9119790e92e9a1d60056be2ceeaf16a8e6ef13082aeab1" [[package]] name = "smallvec" @@ -4159,12 +4184,29 @@ dependencies = [ ] [[package]] -name = "smithay-clipboard" -version = "0.6.3" +name = "smithay-client-toolkit" +version = "0.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "06384dfaf645908220d976ae24ed39f6cf92efecb0225ea0a948e403014de527" +checksum = "ec783683499a2cfc85b6df3d04f83b1907b5cbd98a1aed44667dbdf1eac4e64c" dependencies = [ - "smithay-client-toolkit", + "bitflags", + "dlib 0.5.0", + "lazy_static", + "log", + "memmap2 0.2.3", + "nix 0.20.0", + "wayland-client", + "wayland-cursor", + "wayland-protocols", +] + +[[package]] +name = "smithay-clipboard" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "986c5b4a7bd4f50d4c51f81f844745535cb488360f9cf63293780b109b9295f3" +dependencies = [ + "smithay-client-toolkit 0.14.0", "wayland-client", ] @@ -4185,9 +4227,9 @@ version = "0.6.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1508efa03c362e23817f96cde18abed596a25219a8b2c66e8db33c03543d315b" dependencies = [ - "proc-macro2 1.0.27", + "proc-macro2 1.0.29", "quote 1.0.9", - "syn 1.0.72", + "syn 1.0.75", ] [[package]] @@ -4234,9 +4276,9 @@ dependencies = [ [[package]] name = "strip-ansi-escapes" -version = "0.1.0" +version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9d63676e2abafa709460982ddc02a3bb586b6d15a49b75c212e06edd3933acee" +checksum = "011cbb39cf7c1f62871aea3cc46e5817b0937b49e9447370c93cacbe93a766d8" dependencies = [ "vte", ] @@ -4266,11 +4308,11 @@ dependencies = [ [[package]] name = "syn" -version = "1.0.72" +version = "1.0.75" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1e8cdbefb79a9a5a65e0db8b47b723ee907b7c7f8496c76a1770b5c310bab82" +checksum = "b7f58f7e8eaa0009c5fec437aabf511bd9933e4b2d7407bd05273c01a8906ea7" dependencies = [ - "proc-macro2 1.0.27", + "proc-macro2 1.0.29", "quote 1.0.9", "unicode-xid 0.2.2", ] @@ -4281,20 +4323,20 @@ version = "0.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "baa8e7560a164edb1621a55d18a0c59abf49d360f47aa7b821061dd7eea7fac9" dependencies = [ - "proc-macro2 1.0.27", + "proc-macro2 1.0.29", "quote 1.0.9", - "syn 1.0.72", + "syn 1.0.75", ] [[package]] name = "synstructure" -version = "0.12.4" +version = "0.12.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b834f2d66f734cb897113e34aaff2f1ab4719ca946f9a7358dba8f8064148701" +checksum = "474aaa926faa1603c40b7885a9eaea29b444d1cb2850cb7c0e37bb1a4182f4fa" dependencies = [ - "proc-macro2 1.0.27", + "proc-macro2 1.0.29", "quote 1.0.9", - "syn 1.0.72", + "syn 1.0.75", "unicode-xid 0.2.2", ] @@ -4312,8 +4354,8 @@ checksum = "dac1c663cfc93810f88aed9b8941d48cabf856a1b111c29a40439018d870eb22" dependencies = [ "cfg-if 1.0.0", "libc", - "rand 0.8.3", - "redox_syscall 0.2.8", + "rand 0.8.4", + "redox_syscall", "remove_dir_all", "winapi 0.3.9", ] @@ -4404,9 +4446,9 @@ name = "test_mono_macros" version = "0.1.0" dependencies = [ "darling 0.10.2", - "proc-macro2 1.0.27", + "proc-macro2 1.0.29", "quote 1.0.9", - "syn 1.0.72", + "syn 1.0.75", ] [[package]] @@ -4420,32 +4462,32 @@ dependencies = [ [[package]] name = "thiserror" -version = "1.0.25" +version = "1.0.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa6f76457f59514c7eeb4e59d891395fab0b2fd1d40723ae737d64153392e9c6" +checksum = "283d5230e63df9608ac7d9691adc1dfb6e701225436eb64d0b9a7f0a5a04f6ec" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.25" +version = "1.0.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a36768c0fbf1bb15eca10defa29526bda730a2376c2ab4393ccfa16fb1a318d" +checksum = "fa3884228611f5cd3608e2d409bf7dce832e4eb3135e3f11addbd7e41bd68e71" dependencies = [ - "proc-macro2 1.0.27", + "proc-macro2 1.0.29", "quote 1.0.9", - "syn 1.0.72", + "syn 1.0.75", ] [[package]] name = "thread-id" -version = "3.3.0" +version = "4.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c7fbf4c9d56b320106cd64fd024dadfa0be7cb4706725fc44a7d7ce952d820c1" +checksum = "5fdfe0627923f7411a43ec9ec9c39c3a9b4151be313e0922042581fb6c9b717f" dependencies = [ "libc", - "redox_syscall 0.1.57", + "redox_syscall", "winapi 0.3.9", ] @@ -4506,7 +4548,7 @@ checksum = "09adeb8c97449311ccd28a427f96fb563e7fd31aabf994189879d9da2394b89d" dependencies = [ "cfg-if 1.0.0", "log", - "pin-project-lite 0.2.6", + "pin-project-lite 0.2.7", "tracing-attributes", "tracing-core", ] @@ -4517,9 +4559,9 @@ version = "0.1.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c42e6fa53307c8a17e4ccd4dc81cf5ec38db9209f59b222210375b54ee40d1e2" dependencies = [ - "proc-macro2 1.0.27", + "proc-macro2 1.0.29", "quote 1.0.9", - "syn 1.0.72", + "syn 1.0.75", ] [[package]] @@ -4539,18 +4581,18 @@ checksum = "3e5d7cd7ab3e47dda6e56542f4bbf3824c15234958c6e1bd6aaa347e93499fdc" [[package]] name = "ttf-parser" -version = "0.12.1" +version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2fc71742ead70703a55d184f82087302f2f9ffa3793e64db46a78bf75dd723f4" +checksum = "7ae2f58a822f08abdaf668897e96a5656fe72f5a9ce66422423e8849384872e6" [[package]] name = "twox-hash" -version = "1.6.0" +version = "1.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "04f8ab788026715fa63b31960869617cba39117e520eb415b0139543e325ab59" +checksum = "1f559b464de2e2bdabcac6a210d12e9b5a5973c251e102c44c585c71d51bd78e" dependencies = [ - "cfg-if 0.1.10", - "rand 0.7.3", + "cfg-if 1.0.0", + "rand 0.8.4", "static_assertions", ] @@ -4585,9 +4627,9 @@ version = "0.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "504f9626fe6cc1c376227864781996668e15c1ff251d222f63ef17f310bf1fec" dependencies = [ - "proc-macro2 1.0.27", + "proc-macro2 1.0.29", "quote 1.0.9", - "syn 1.0.72", + "syn 1.0.75", ] [[package]] @@ -4607,9 +4649,9 @@ dependencies = [ [[package]] name = "unicode-segmentation" -version = "1.7.1" +version = "1.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bb0d2e7be6ae3a5fa87eed5fb451aff96f2573d2694942e40543ae0bbe19c796" +checksum = "8895849a949e7845e06bd6dc1aa51731a103c42707010a5b591c0038fb73385b" [[package]] name = "unicode-width" @@ -4635,12 +4677,6 @@ version = "0.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f14ee04d9415b52b3aeab06258a3f07093182b88ba0f9b8d203f211a7a7d41c7" -[[package]] -name = "utf8parse" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8772a4ccbb4e89959023bc5b7cb8623a795caa7092d99f3aa9501b9484d4557d" - [[package]] name = "utf8parse" version = "0.2.0" @@ -4693,11 +4729,23 @@ checksum = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d" [[package]] name = "vte" -version = "0.3.3" +version = "0.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4f42f536e22f7fcbb407639765c8fd78707a33109301f834a594758bedd6e8cf" +checksum = "6cbce692ab4ca2f1f3047fcf732430249c0e971bfdd2b234cf2c47ad93af5983" dependencies = [ - "utf8parse 0.1.1", + "arrayvec", + "utf8parse", + "vte_generate_state_changes", +] + +[[package]] +name = "vte_generate_state_changes" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d257817081c7dffcdbab24b9e62d2def62e2ff7d00b1c20062551e6cccc145ff" +dependencies = [ + "proc-macro2 1.0.29", + "quote 1.0.9", ] [[package]] @@ -4725,9 +4773,9 @@ checksum = "fd6fbd9a79829dd1ad0cc20627bf1ed606756a7f77edff7b66b7064f9cb327c6" [[package]] name = "wasm-bindgen" -version = "0.2.74" +version = "0.2.76" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d54ee1d4ed486f78874278e63e4069fc1ab9f6a18ca492076ffb90c5eb2997fd" +checksum = "8ce9b1b516211d33767048e5d47fa2a381ed8b76fc48d2ce4aa39877f9f183e0" dependencies = [ "cfg-if 1.0.0", "wasm-bindgen-macro", @@ -4735,24 +4783,24 @@ dependencies = [ [[package]] name = "wasm-bindgen-backend" -version = "0.2.74" +version = "0.2.76" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3b33f6a0694ccfea53d94db8b2ed1c3a8a4c86dd936b13b9f0a15ec4a451b900" +checksum = "cfe8dc78e2326ba5f845f4b5bf548401604fa20b1dd1d365fb73b6c1d6364041" dependencies = [ "bumpalo", "lazy_static", "log", - "proc-macro2 1.0.27", + "proc-macro2 1.0.29", "quote 1.0.9", - "syn 1.0.72", + "syn 1.0.75", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-futures" -version = "0.4.24" +version = "0.4.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5fba7978c679d53ce2d0ac80c8c175840feb849a161664365d1287b41f2e67f1" +checksum = "95fded345a6559c2cfee778d562300c581f7d4ff3edb9b0d230d69800d213972" dependencies = [ "cfg-if 1.0.0", "js-sys", @@ -4762,9 +4810,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro" -version = "0.2.74" +version = "0.2.76" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "088169ca61430fe1e58b8096c24975251700e7b1f6fd91cc9d59b04fb9b18bd4" +checksum = "44468aa53335841d9d6b6c023eaab07c0cd4bddbcfdee3e2bb1e8d2cb8069fef" dependencies = [ "quote 1.0.9", "wasm-bindgen-macro-support", @@ -4772,22 +4820,22 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.74" +version = "0.2.76" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "be2241542ff3d9f241f5e2cb6dd09b37efe786df8851c54957683a49f0987a97" +checksum = "0195807922713af1e67dc66132c7328206ed9766af3858164fb583eedc25fbad" dependencies = [ - "proc-macro2 1.0.27", + "proc-macro2 1.0.29", "quote 1.0.9", - "syn 1.0.72", + "syn 1.0.75", "wasm-bindgen-backend", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-shared" -version = "0.2.74" +version = "0.2.76" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d7cff876b8f18eed75a66cf49b65e7f967cb354a7aa16003fb55dbfd25b44b4f" +checksum = "acdb075a845574a1fa5f09fd77e43f7747599301ea3417a9fbffdeedfc1f4a29" [[package]] name = "wasmer" @@ -4859,9 +4907,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1ee7b351bcc1e782997c72dc0b5b328f3ddcad4813b8ce3cac3f25ae5a4ab56b" dependencies = [ "proc-macro-error 1.0.4", - "proc-macro2 1.0.27", + "proc-macro2 1.0.29", "quote 1.0.9", - "syn 1.0.72", + "syn 1.0.75", ] [[package]] @@ -5029,9 +5077,9 @@ dependencies = [ [[package]] name = "wayland-client" -version = "0.28.5" +version = "0.28.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "06ca44d86554b85cf449f1557edc6cc7da935cc748c8e4bf1c507cbd43bae02c" +checksum = "e3ab332350e502f159382201394a78e3cc12d0f04db863429260164ea40e0355" dependencies = [ "bitflags", "downcast-rs", @@ -5045,9 +5093,9 @@ dependencies = [ [[package]] name = "wayland-commons" -version = "0.28.5" +version = "0.28.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8bd75ae380325dbcff2707f0cd9869827ea1d2d6d534cff076858d3f0460fd5a" +checksum = "a21817947c7011bbd0a27e11b17b337bfd022e8544b071a2641232047966fbda" dependencies = [ "nix 0.20.0", "once_cell", @@ -5057,9 +5105,9 @@ dependencies = [ [[package]] name = "wayland-cursor" -version = "0.28.5" +version = "0.28.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b37e5455ec72f5de555ec39b5c3704036ac07c2ecd50d0bffe02d5fe2d4e65ab" +checksum = "be610084edd1586d45e7bdd275fe345c7c1873598caa464c4fb835dee70fa65a" dependencies = [ "nix 0.20.0", "wayland-client", @@ -5068,9 +5116,9 @@ dependencies = [ [[package]] name = "wayland-protocols" -version = "0.28.5" +version = "0.28.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "95df3317872bcf9eec096c864b69aa4769a1d5d6291a5b513f8ba0af0efbd52c" +checksum = "286620ea4d803bacf61fa087a4242ee316693099ee5a140796aaba02b29f861f" dependencies = [ "bitflags", "wayland-client", @@ -5080,20 +5128,20 @@ dependencies = [ [[package]] name = "wayland-scanner" -version = "0.28.5" +version = "0.28.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "389d680d7bd67512dc9c37f39560224327038deb0f0e8d33f870900441b68720" +checksum = "ce923eb2deb61de332d1f356ec7b6bf37094dc5573952e1c8936db03b54c03f1" dependencies = [ - "proc-macro2 1.0.27", + "proc-macro2 1.0.29", "quote 1.0.9", "xml-rs", ] [[package]] name = "wayland-sys" -version = "0.28.5" +version = "0.28.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2907bd297eef464a95ba9349ea771611771aa285b932526c633dc94d5400a8e2" +checksum = "d841fca9aed7febf9bed2e9796c49bf58d4152ceda8ac949ebe00868d8f0feb8" dependencies = [ "dlib 0.5.0", "lazy_static", @@ -5132,9 +5180,9 @@ dependencies = [ [[package]] name = "wgpu-core" -version = "0.9.0" +version = "0.9.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2af5c8acd3ae5781a277cdf65a17f3a7135de5ae782775620e74ea16c9d47770" +checksum = "958a8a5e418492723ab4e7933bf6dbdf06f5dc87274ba2ae0e4f9c891aac579c" dependencies = [ "arrayvec", "bitflags", @@ -5260,7 +5308,7 @@ dependencies = [ "parking_lot", "percent-encoding", "raw-window-handle", - "smithay-client-toolkit", + "smithay-client-toolkit 0.12.3", "wayland-client", "winapi 0.3.9", "x11-dl", @@ -5327,9 +5375,9 @@ dependencies = [ [[package]] name = "xcursor" -version = "0.3.3" +version = "0.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3a9a231574ae78801646617cefd13bfe94be907c0e4fa979cfd8b770aa3c5d08" +checksum = "463705a63313cd4301184381c5e8042f0a7e9b4bb63653f216311d4ae74690b7" dependencies = [ "nom", ] @@ -5348,9 +5396,9 @@ checksum = "a67300977d3dc3f8034dae89778f502b6ba20b269527b3223ba59c0cf393bb8a" [[package]] name = "xml-rs" -version = "0.8.3" +version = "0.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b07db065a5cf61a7e4ba64f29e67db906fb1787316516c4e6e5ff0fea1efcd8a" +checksum = "d2d7d3948613f75c98fd9328cfdcc45acc4d360655289d0a7d4ec931392200a3" [[package]] name = "yaml-rust" @@ -5377,7 +5425,7 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d498dbd1fd7beb83c86709ae1c33ca50942889473473d287d56ce4770a18edfb" dependencies = [ - "proc-macro2 1.0.27", - "syn 1.0.72", + "proc-macro2 1.0.29", + "syn 1.0.75", "synstructure", ] diff --git a/compiler/gen_wasm/Cargo.toml b/compiler/gen_wasm/Cargo.toml index 984220214b..15c2140934 100644 --- a/compiler/gen_wasm/Cargo.toml +++ b/compiler/gen_wasm/Cargo.toml @@ -7,21 +7,9 @@ edition = "2018" [dependencies] roc_collections = { path = "../collections" } -# roc_region = { path = "../region" } -# roc_load = { path = "../load" } roc_module = { path = "../module" } -# roc_problem = { path = "../problem" } -# roc_types = { path = "../types" } -# roc_builtins = { path = "../builtins" } -# roc_constrain = { path = "../constrain" } -# roc_unify = { path = "../unify" } -# roc_solve = { path = "../solve" } roc_mono = { path = "../mono" } -# im = "14" # im and im-rc should always have the same version! -# im-rc = "14" # im and im-rc should always have the same version! bumpalo = { version = "3.6.1", features = ["collections"] } -# target-lexicon = "0.12.2" -# libloading = "0.6" parity-wasm = "0.42" [dev-dependencies] diff --git a/compiler/gen_wasm/src/backend.rs b/compiler/gen_wasm/src/backend.rs index 2dd9cedcf8..21064dc06f 100644 --- a/compiler/gen_wasm/src/backend.rs +++ b/compiler/gen_wasm/src/backend.rs @@ -105,7 +105,7 @@ impl<'a> WasmBackend<'a> { let signature = builder::signature() .with_params(self.arg_types.clone()) // requires std::Vec, not Bumpalo - .with_result(self.ret_type.clone()) + .with_result(self.ret_type) .build_sig(); let function_def = builder::function() @@ -261,7 +261,7 @@ impl<'a> WasmBackend<'a> { // For those, we'll need to pre-process each argument before the main op, // so simple arrays of instructions won't work. But there are common patterns. let instructions: &[Instruction] = match lowlevel { - // Matching on Wasm type might not be enough, maybe need Roc layout for sign-extension + // Wasm type might not be enough, may need to sign-extend i8 etc. Maybe in load_from_symbol? LowLevel::NumAdd => match value_type { ValueType::I32 => &[I32Add], ValueType::I64 => &[I64Add], diff --git a/compiler/gen_wasm/src/lib.rs b/compiler/gen_wasm/src/lib.rs index 53c544e3fb..ce0f5d48cd 100644 --- a/compiler/gen_wasm/src/lib.rs +++ b/compiler/gen_wasm/src/lib.rs @@ -6,7 +6,7 @@ use parity_wasm::elements::Internal; use roc_collections::all::{MutMap, MutSet}; use roc_module::symbol::{Interns, Symbol}; -use roc_mono::ir::{CallType, Expr, Proc, ProcLayout, Stmt}; +use roc_mono::ir::{Proc, ProcLayout}; use roc_mono::layout::LayoutIds; use crate::backend::WasmBackend; @@ -45,18 +45,3 @@ pub fn build_module<'a>( .to_bytes() .map_err(|e| -> String { format!("Error serialising Wasm module {:?}", e) }) } - -// TODO: use something like this for very simple inlining -// Create a HashMap of inlined Procs, generate each call with different Symbol arguments -fn _is_lowlevel_wrapper<'a>(proc: Proc<'a>) -> bool { - match proc.body { - Stmt::Let(_, expr, _, Stmt::Ret(..)) => match expr { - Expr::Call(roc_mono::ir::Call { call_type, .. }) => match call_type { - CallType::LowLevel { .. } => true, - _ => false, - }, - _ => false, - }, - _ => false, - } -} From 0770bb242e2d95968c56db26f69c194d31ab68c8 Mon Sep 17 00:00:00 2001 From: Brian Carroll Date: Wed, 1 Sep 2021 20:12:01 +0100 Subject: [PATCH 11/42] Reset after each procedure, and reserve space in vecs --- compiler/gen_wasm/src/backend.rs | 21 +++++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) diff --git a/compiler/gen_wasm/src/backend.rs b/compiler/gen_wasm/src/backend.rs index 21064dc06f..c27ea37000 100644 --- a/compiler/gen_wasm/src/backend.rs +++ b/compiler/gen_wasm/src/backend.rs @@ -70,10 +70,10 @@ impl<'a> WasmBackend<'a> { proc_symbol_map: MutMap::default(), // Functions: Wasm AST - instructions: std::vec::Vec::new(), + instructions: std::vec::Vec::with_capacity(256), ret_type: ValueType::I32, - arg_types: std::vec::Vec::new(), - locals: std::vec::Vec::new(), + arg_types: std::vec::Vec::with_capacity(8), + locals: std::vec::Vec::with_capacity(32), // Functions: internal state & IR mappings stack_memory: 0, @@ -82,6 +82,18 @@ impl<'a> WasmBackend<'a> { } } + fn reset(&mut self) { + // Functions: Wasm AST + self.instructions.clear(); + self.arg_types.clear(); + self.locals.clear(); + + // Functions: internal state & IR mappings + self.stack_memory = 0; + self.symbol_storage_map.clear(); + // joinpoint_label_map.clear(); + } + pub fn build_proc(&mut self, proc: Proc<'a>, sym: Symbol) -> Result { let ret_layout = WasmLayout::new(&proc.ret_layout)?; if ret_layout.stack_memory > 0 { @@ -93,7 +105,7 @@ impl<'a> WasmBackend<'a> { } self.ret_type = ret_layout.value_type; - self.arg_types = std::vec::Vec::with_capacity(proc.args.len()); + self.arg_types.reserve(proc.args.len()); for (layout, symbol) in proc.args { let wasm_layout = WasmLayout::new(layout)?; @@ -119,6 +131,7 @@ impl<'a> WasmBackend<'a> { let location = self.builder.push_function(function_def); let function_index = location.body; self.proc_symbol_map.insert(sym, location); + self.reset(); Ok(function_index) } From ff29b19338a8fb82ef07f237efb47a0838b90ac7 Mon Sep 17 00:00:00 2001 From: Folkert Date: Wed, 1 Sep 2021 22:34:36 +0200 Subject: [PATCH 12/42] add wasm tests --- Cargo.lock | 11 + compiler/gen_wasm/Cargo.toml | 12 + compiler/gen_wasm/tests/helpers/eval.rs | 469 ++++++++++++ compiler/gen_wasm/tests/helpers/mod.rs | 44 ++ compiler/gen_wasm/tests/wasm_num.rs | 863 ++++++++++++++++++++++ compiler/gen_wasm/tests/wasm_records.rs | 937 ++++++++++++++++++++++++ 6 files changed, 2336 insertions(+) create mode 100644 compiler/gen_wasm/tests/helpers/eval.rs create mode 100644 compiler/gen_wasm/tests/helpers/mod.rs create mode 100644 compiler/gen_wasm/tests/wasm_num.rs create mode 100644 compiler/gen_wasm/tests/wasm_records.rs diff --git a/Cargo.lock b/Cargo.lock index 265a73f085..d2d122f76c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1345,11 +1345,22 @@ name = "gen_wasm" version = "0.1.0" dependencies = [ "bumpalo", + "indoc 0.3.6", + "libc", "parity-wasm", + "pretty_assertions 0.5.1", + "roc_builtins", + "roc_can", "roc_collections", + "roc_load", "roc_module", "roc_mono", + "roc_std", + "roc_types", + "target-lexicon", + "tempfile", "wasmer", + "wasmer-wasi", ] [[package]] diff --git a/compiler/gen_wasm/Cargo.toml b/compiler/gen_wasm/Cargo.toml index 15c2140934..14e2be583d 100644 --- a/compiler/gen_wasm/Cargo.toml +++ b/compiler/gen_wasm/Cargo.toml @@ -13,4 +13,16 @@ bumpalo = { version = "3.6.1", features = ["collections"] } parity-wasm = "0.42" [dev-dependencies] +roc_can = { path = "../can" } +roc_builtins = { path = "../builtins" } +roc_load = { path = "../load" } +roc_types = { path = "../types" } +roc_std = { path = "../../roc_std" } +roc_module = { path = "../module" } +indoc = "0.3.3" +pretty_assertions = "0.5.1" +libc = "0.2" +target-lexicon = "0.12.2" wasmer = "2.0.0" +wasmer-wasi = "2.0.0" +tempfile = "3.1.0" diff --git a/compiler/gen_wasm/tests/helpers/eval.rs b/compiler/gen_wasm/tests/helpers/eval.rs new file mode 100644 index 0000000000..b11eda739a --- /dev/null +++ b/compiler/gen_wasm/tests/helpers/eval.rs @@ -0,0 +1,469 @@ +use roc_can::builtins::builtin_defs_map; +use roc_collections::all::{MutMap, MutSet}; +use roc_std::{RocDec, RocList, RocOrder, RocStr}; + +fn promote_expr_to_module(src: &str) -> String { + let mut buffer = String::from("app \"test\" provides [ main ] to \"./platform\"\n\nmain =\n"); + + for line in src.lines() { + // indent the body! + buffer.push_str(" "); + buffer.push_str(line); + buffer.push('\n'); + } + + buffer +} + +#[allow(dead_code)] +pub fn helper_wasm<'a>( + arena: &'a bumpalo::Bump, + src: &str, + stdlib: &'a roc_builtins::std::StdLib, + _is_gen_test: bool, + _ignore_problems: bool, +) -> wasmer::Instance { + use std::path::{Path, PathBuf}; + + let filename = PathBuf::from("Test.roc"); + let src_dir = Path::new("fake/test/path"); + + let module_src; + let temp; + if src.starts_with("app") { + // this is already a module + module_src = src; + } else { + // this is an expression, promote it to a module + temp = promote_expr_to_module(src); + module_src = &temp; + } + + let exposed_types = MutMap::default(); + let loaded = roc_load::file::load_and_monomorphize_from_str( + arena, + filename, + module_src, + stdlib, + src_dir, + exposed_types, + 8, + builtin_defs_map, + ); + + let loaded = loaded.expect("failed to load module"); + + use roc_load::file::MonomorphizedModule; + let MonomorphizedModule { + procedures: top_procedures, + interns, + exposed_to_host, + .. + } = loaded; + + let mut procedures = MutMap::default(); + + for (key, proc) in top_procedures { + procedures.insert(key, proc); + } + + let exposed_to_host = exposed_to_host.keys().copied().collect::>(); + + let env = gen_wasm::Env { + arena, + interns, + exposed_to_host, + }; + + let module_bytes = gen_wasm::build_module(&env, procedures).unwrap(); + + // for debugging (e.g. with wasm2wat) + if false { + use std::io::Write; + let mut file = std::fs::File::create("/home/folkertdev/roc/wasm/manual.wasm").unwrap(); + file.write_all(&module_bytes).unwrap(); + } + + // now, do wasmer stuff + + use wasmer::{Function, Instance, Module, Store}; + + let store = Store::default(); + // let module = Module::from_file(&store, &test_wasm_path).unwrap(); + let module = Module::new(&store, &module_bytes).unwrap(); + + // First, we create the `WasiEnv` + use wasmer_wasi::WasiState; + let mut wasi_env = WasiState::new("hello") + // .args(&["world"]) + // .env("KEY", "Value") + .finalize() + .unwrap(); + + // Then, we get the import object related to our WASI + // and attach it to the Wasm instance. + let mut import_object = wasi_env + .import_object(&module) + .unwrap_or_else(|_| wasmer::imports!()); + + { + let mut exts = wasmer::Exports::new(); + + let main_function = Function::new_native(&store, fake_wasm_main_function); + let ext = wasmer::Extern::Function(main_function); + exts.insert("main", ext); + + let main_function = Function::new_native(&store, wasm_roc_panic); + let ext = wasmer::Extern::Function(main_function); + exts.insert("roc_panic", ext); + + import_object.register("env", exts); + } + + Instance::new(&module, &import_object).unwrap() +} + +#[allow(dead_code)] +fn wasm_roc_panic(address: u32, tag_id: u32) { + match tag_id { + 0 => { + let mut string = ""; + + MEMORY.with(|f| { + let memory = f.borrow().unwrap(); + + let ptr: wasmer::WasmPtr = wasmer::WasmPtr::new(address); + let width = 100; + let c_ptr = (ptr.deref(memory, 0, width)).unwrap(); + + use libc::c_char; + use std::ffi::CStr; + let slice = unsafe { CStr::from_ptr(c_ptr as *const _ as *const c_char) }; + string = slice.to_str().unwrap(); + }); + + panic!("Roc failed with message: {:?}", string) + } + _ => todo!(), + } +} + +use std::cell::RefCell; + +thread_local! { + pub static MEMORY: RefCell> = RefCell::new(None); +} + +#[allow(dead_code)] +fn fake_wasm_main_function(_: u32, _: u32) -> u32 { + panic!("wasm entered the main function; this should never happen!") +} + +#[allow(dead_code)] +pub fn assert_wasm_evals_to_help(src: &str, ignore_problems: bool) -> Result +where + T: FromWasmMemory, +{ + let arena = bumpalo::Bump::new(); + + // NOTE the stdlib must be in the arena; just taking a reference will segfault + let stdlib = arena.alloc(roc_builtins::std::standard_stdlib()); + + let is_gen_test = true; + let instance = + crate::helpers::eval::helper_wasm(&arena, src, stdlib, is_gen_test, ignore_problems); + + let memory = instance.exports.get_memory("memory").unwrap(); + + crate::helpers::eval::MEMORY.with(|f| { + *f.borrow_mut() = Some(unsafe { std::mem::transmute(memory) }); + }); + + let test_wrapper = instance.exports.get_function("test_wrapper").unwrap(); + + match test_wrapper.call(&[]) { + Err(e) => Err(format!("{:?}", e)), + Ok(result) => { + let address = match result[0] { + wasmer::Value::I32(a) => a, + _ => panic!(), + }; + + let output = ::decode( + memory, + // skip the RocCallResult tag id + address as u32 + 8, + ); + + Ok(output) + } + } +} + +#[macro_export] +macro_rules! assert_wasm_evals_to { + ($src:expr, $expected:expr, $ty:ty, $transform:expr, $ignore_problems:expr) => { + match $crate::helpers::eval::assert_wasm_evals_to_help::<$ty>($src, $ignore_problems) { + Err(msg) => println!("{:?}", msg), + Ok(actual) => { + #[allow(clippy::bool_assert_comparison)] + assert_eq!($transform(actual), $expected) + } + } + }; + + ($src:expr, $expected:expr, $ty:ty) => { + $crate::assert_wasm_evals_to!($src, $expected, $ty, $crate::helpers::eval::identity, false); + }; + + ($src:expr, $expected:expr, $ty:ty, $transform:expr) => { + $crate::assert_wasm_evals_to!($src, $expected, $ty, $transform, false); + }; +} + +#[macro_export] +macro_rules! assert_evals_to { + ($src:expr, $expected:expr, $ty:ty) => {{ + assert_evals_to!($src, $expected, $ty, $crate::helpers::eval::identity); + }}; + ($src:expr, $expected:expr, $ty:ty, $transform:expr) => { + // Same as above, except with an additional transformation argument. + { + $crate::assert_wasm_evals_to!($src, $expected, $ty, $transform, false); + } + }; +} + +#[allow(dead_code)] +pub fn identity(value: T) -> T { + value +} + +pub trait FromWasmMemory: Sized { + const SIZE_OF_WASM: usize; + const ALIGN_OF_WASM: usize; + const ACTUAL_WIDTH: usize = if (Self::SIZE_OF_WASM % Self::ALIGN_OF_WASM) == 0 { + Self::SIZE_OF_WASM + } else { + Self::SIZE_OF_WASM + (Self::ALIGN_OF_WASM - (Self::SIZE_OF_WASM % Self::ALIGN_OF_WASM)) + }; + + fn decode(memory: &wasmer::Memory, offset: u32) -> Self; +} + +macro_rules! from_wasm_memory_primitive_decode { + ($type_name:ident) => { + const SIZE_OF_WASM: usize = core::mem::size_of::<$type_name>(); + const ALIGN_OF_WASM: usize = core::mem::align_of::<$type_name>(); + + fn decode(memory: &wasmer::Memory, offset: u32) -> Self { + use core::mem::MaybeUninit; + + let mut output: MaybeUninit = MaybeUninit::uninit(); + let width = std::mem::size_of::(); + + let ptr = output.as_mut_ptr(); + let raw_ptr = ptr as *mut u8; + let slice = unsafe { std::slice::from_raw_parts_mut(raw_ptr, width) }; + + let ptr: wasmer::WasmPtr = wasmer::WasmPtr::new(offset as u32); + let foobar = (ptr.deref(memory, 0, width as u32)).unwrap(); + let wasm_slice = unsafe { std::mem::transmute(foobar) }; + + slice.copy_from_slice(wasm_slice); + + unsafe { output.assume_init() } + } + }; +} + +macro_rules! from_wasm_memory_primitive { + ($($type_name:ident ,)+) => { + $( + impl FromWasmMemory for $type_name { + from_wasm_memory_primitive_decode!($type_name); + } + )* + } +} + +from_wasm_memory_primitive!( + u8, i8, u16, i16, u32, i32, u64, i64, u128, i128, f32, f64, bool, RocDec, RocOrder, +); + +impl FromWasmMemory for () { + const SIZE_OF_WASM: usize = 0; + const ALIGN_OF_WASM: usize = 0; + + fn decode(_: &wasmer::Memory, _: u32) -> Self {} +} + +impl FromWasmMemory for RocStr { + const SIZE_OF_WASM: usize = 8; + const ALIGN_OF_WASM: usize = 4; + + fn decode(memory: &wasmer::Memory, offset: u32) -> Self { + let bytes = ::decode(memory, offset); + + let length = (bytes >> 32) as u32; + let elements = bytes as u32; + + if length == 0 { + RocStr::default() + } else if (length as i32) < 0 { + // this is a small string + let last_byte = bytes.to_ne_bytes()[7]; + let actual_length = (last_byte ^ 0b1000_0000) as usize; + + let slice = &bytes.to_ne_bytes()[..actual_length as usize]; + RocStr::from_slice(slice) + } else { + // this is a big string + let ptr: wasmer::WasmPtr = wasmer::WasmPtr::new(elements); + let foobar = (ptr.deref(memory, 0, length)).unwrap(); + let wasm_slice = unsafe { std::mem::transmute(foobar) }; + + RocStr::from_slice(wasm_slice) + } + } +} + +impl FromWasmMemory for RocList { + const SIZE_OF_WASM: usize = 8; + const ALIGN_OF_WASM: usize = 4; + + fn decode(memory: &wasmer::Memory, offset: u32) -> Self { + let bytes = ::decode(memory, offset); + + let length = (bytes >> 32) as u32; + let elements = bytes as u32; + + let mut items = Vec::with_capacity(length as usize); + + for i in 0..length { + let item = ::decode( + memory, + elements + i * ::SIZE_OF_WASM as u32, + ); + items.push(item); + } + + RocList::from_slice(&items) + } +} + +impl FromWasmMemory for &'_ [T] { + const SIZE_OF_WASM: usize = 8; + const ALIGN_OF_WASM: usize = 4; + + fn decode(memory: &wasmer::Memory, offset: u32) -> Self { + let bytes = ::decode(memory, offset); + + let length = (bytes >> 32) as u32; + let elements = bytes as u32; + + let ptr: wasmer::WasmPtr = wasmer::WasmPtr::new(elements); + let width = ::SIZE_OF_WASM as u32 * length; + let foobar = (ptr.deref(memory, 0, width)).unwrap(); + let wasm_slice = + unsafe { std::slice::from_raw_parts(foobar as *const _ as *const _, length as usize) }; + + wasm_slice + } +} + +impl FromWasmMemory for &'_ T { + const SIZE_OF_WASM: usize = 4; + const ALIGN_OF_WASM: usize = 4; + + fn decode(memory: &wasmer::Memory, offset: u32) -> Self { + let elements = ::decode(memory, offset); + + let actual = ::decode(memory, elements); + + let b = Box::new(actual); + + std::boxed::Box::::leak(b) + } +} + +impl FromWasmMemory for [T; N] { + const SIZE_OF_WASM: usize = N * T::SIZE_OF_WASM; + const ALIGN_OF_WASM: usize = T::ALIGN_OF_WASM; + + fn decode(memory: &wasmer::Memory, offset: u32) -> Self { + let ptr: wasmer::WasmPtr = wasmer::WasmPtr::new(offset); + let width = ::SIZE_OF_WASM as u32 * N as u32; + let foobar = (ptr.deref(memory, 0, width)).unwrap(); + let wasm_slice: &[T; N] = unsafe { &*(foobar as *const _ as *const [T; N]) }; + + wasm_slice.clone() + } +} + +impl FromWasmMemory for usize { + const SIZE_OF_WASM: usize = 4; + const ALIGN_OF_WASM: usize = 4; + + fn decode(memory: &wasmer::Memory, offset: u32) -> Self { + ::decode(memory, offset) as usize + } +} + +impl FromWasmMemory for (T, U) { + const SIZE_OF_WASM: usize = T::SIZE_OF_WASM + U::SIZE_OF_WASM; + const ALIGN_OF_WASM: usize = max2(T::SIZE_OF_WASM, U::SIZE_OF_WASM); + + fn decode(memory: &wasmer::Memory, offset: u32) -> Self { + assert!( + T::ALIGN_OF_WASM >= U::ALIGN_OF_WASM, + "this function does not handle alignment" + ); + + let t = ::decode(memory, offset); + + let u = ::decode(memory, offset + T::ACTUAL_WIDTH as u32); + + (t, u) + } +} + +const fn max2(a: usize, b: usize) -> usize { + if a > b { + a + } else { + b + } +} + +const fn max3(a: usize, b: usize, c: usize) -> usize { + max2(max2(a, b), c) +} + +impl FromWasmMemory for (T, U, V) { + const SIZE_OF_WASM: usize = T::SIZE_OF_WASM + U::SIZE_OF_WASM + V::SIZE_OF_WASM; + const ALIGN_OF_WASM: usize = max3(T::SIZE_OF_WASM, U::SIZE_OF_WASM, V::SIZE_OF_WASM); + + fn decode(memory: &wasmer::Memory, offset: u32) -> Self { + assert!( + T::ALIGN_OF_WASM >= U::ALIGN_OF_WASM, + "this function does not handle alignment" + ); + + assert!( + U::ALIGN_OF_WASM >= V::ALIGN_OF_WASM, + "this function does not handle alignment" + ); + + let t = ::decode(memory, offset); + + let u = ::decode(memory, offset + T::ACTUAL_WIDTH as u32); + + let v = ::decode( + memory, + offset + T::ACTUAL_WIDTH as u32 + U::ACTUAL_WIDTH as u32, + ); + + (t, u, v) + } +} diff --git a/compiler/gen_wasm/tests/helpers/mod.rs b/compiler/gen_wasm/tests/helpers/mod.rs new file mode 100644 index 0000000000..7e538193f7 --- /dev/null +++ b/compiler/gen_wasm/tests/helpers/mod.rs @@ -0,0 +1,44 @@ +extern crate bumpalo; + +#[macro_use] +pub mod eval; + +/// Used in the with_larger_debug_stack() function, for tests that otherwise +/// run out of stack space in debug builds (but don't in --release builds) +#[allow(dead_code)] +const EXPANDED_STACK_SIZE: usize = 8 * 1024 * 1024; + +/// Without this, some tests pass in `cargo test --release` but fail without +/// the --release flag because they run out of stack space. This increases +/// stack size for debug builds only, while leaving the stack space at the default +/// amount for release builds. +#[allow(dead_code)] +#[cfg(debug_assertions)] +pub fn with_larger_debug_stack(run_test: F) +where + F: FnOnce(), + F: Send, + F: 'static, +{ + std::thread::Builder::new() + .stack_size(EXPANDED_STACK_SIZE) + .spawn(run_test) + .expect("Error while spawning expanded dev stack size thread") + .join() + .expect("Error while joining expanded dev stack size thread") +} + +/// In --release builds, don't increase the stack size. Run the test normally. +/// This way, we find out if any of our tests are blowing the stack even after +/// optimizations in release builds. +#[allow(dead_code)] +#[cfg(not(debug_assertions))] +#[inline(always)] +pub fn with_larger_debug_stack(run_test: F) +where + F: FnOnce() -> (), + F: Send, + F: 'static, +{ + run_test() +} diff --git a/compiler/gen_wasm/tests/wasm_num.rs b/compiler/gen_wasm/tests/wasm_num.rs new file mode 100644 index 0000000000..d1c0ae0d75 --- /dev/null +++ b/compiler/gen_wasm/tests/wasm_num.rs @@ -0,0 +1,863 @@ +#[macro_use] +extern crate pretty_assertions; + +#[macro_use] +extern crate indoc; + +extern crate bumpalo; +extern crate libc; + +#[macro_use] +mod helpers; + +#[cfg(all(test, any(target_os = "linux", target_os = "macos"), any(target_arch = "x86_64"/*, target_arch = "aarch64"*/)))] +mod dev_num { + #[test] + fn i64_values() { + assert_evals_to!("0", 0, i64); + assert_evals_to!("-0", 0, i64); + assert_evals_to!("-1", -1, i64); + assert_evals_to!("1", 1, i64); + assert_evals_to!("9_000_000_000_000", 9_000_000_000_000, i64); + assert_evals_to!("-9_000_000_000_000", -9_000_000_000_000, i64); + assert_evals_to!("0b1010", 0b1010, i64); + assert_evals_to!("0o17", 0o17, i64); + assert_evals_to!("0x1000_0000_0000_0000", 0x1000_0000_0000_0000, i64); + } + + #[test] + fn f64_values() { + assert_evals_to!("0.0", 0.0, f64); + assert_evals_to!("-0.0", 0.0, f64); + assert_evals_to!("1.0", 1.0, f64); + assert_evals_to!("-1.0", -1.0, f64); + assert_evals_to!("3.1415926535897932", 3.141_592_653_589_793, f64); + assert_evals_to!(&format!("{:0.1}", f64::MIN), f64::MIN, f64); + assert_evals_to!(&format!("{:0.1}", f64::MAX), f64::MAX, f64); + } + + #[test] + fn gen_add_i64() { + assert_evals_to!( + indoc!( + r#" + 1 + 2 + 3 + "# + ), + 6, + i64 + ); + } + + #[test] + fn gen_add_f64() { + assert_evals_to!( + indoc!( + r#" + 1.1 + 2.4 + 3 + "# + ), + 6.5, + f64 + ); + } + + #[test] + fn gen_sub_i64() { + assert_evals_to!( + indoc!( + r#" + 1 - 2 - 3 + "# + ), + -4, + i64 + ); + } + + #[test] + fn gen_mul_i64() { + assert_evals_to!( + indoc!( + r#" + 2 * 4 * 6 + "# + ), + 48, + i64 + ); + } + + #[test] + fn i64_force_stack() { + // This claims 33 registers. One more than Arm and RISC-V, and many more than x86-64. + assert_evals_to!( + indoc!( + r#" + a = 0 + b = 1 + c = 2 + d = 3 + e = 4 + f = 5 + g = 6 + h = 7 + i = 8 + j = 9 + k = 10 + l = 11 + m = 12 + n = 13 + o = 14 + p = 15 + q = 16 + r = 17 + s = 18 + t = 19 + u = 20 + v = 21 + w = 22 + x = 23 + y = 24 + z = 25 + aa = 26 + ab = 27 + ac = 28 + ad = 29 + ae = 30 + af = 31 + ag = 32 + + a + b + c + d + e + f + g + h + i + j + k + l + m + n + o + p + q + r + s + t + u + v + w + x + y + z + aa + ab + ac + ad + ae + af + ag + "# + ), + 528, + i64 + ); + } + + #[test] + fn i64_abs() { + assert_evals_to!("Num.abs -6", 6, i64); + assert_evals_to!("Num.abs 7", 7, i64); + assert_evals_to!("Num.abs 0", 0, i64); + assert_evals_to!("Num.abs -0", 0, i64); + assert_evals_to!("Num.abs -1", 1, i64); + assert_evals_to!("Num.abs 1", 1, i64); + assert_evals_to!("Num.abs 9_000_000_000_000", 9_000_000_000_000, i64); + assert_evals_to!("Num.abs -9_000_000_000_000", 9_000_000_000_000, i64); + } + + #[test] + fn gen_int_eq() { + assert_evals_to!( + indoc!( + r#" + 4 == 4 + "# + ), + true, + bool + ); + + assert_evals_to!( + indoc!( + r#" + 3 == 4 + "# + ), + false, + bool + ); + } + + #[test] + fn gen_basic_fn() { + assert_evals_to!( + indoc!( + r#" + always42 : Num.Num (Num.Integer Num.Signed64) -> Num.Num (Num.Integer Num.Signed64) + always42 = \_ -> 42 + + always42 5 + "# + ), + 42, + i64 + ); + } + + #[test] + fn gen_wrap_add_nums() { + assert_evals_to!( + indoc!( + r#" + add2 = \num1, num2 -> num1 + num2 + + add2 4 5 + "# + ), + 9, + i64 + ); + } + + #[test] + fn gen_wrap_add_nums_force_stack() { + assert_evals_to!( + indoc!( + r#" + add9 = \num1, num2, num3, num4, num5, num6, num7, num8, num9 -> num1 + num2 + num3 + num4 + num5 + num6 + num7 + num8 + num9 + + add9 1 2 3 4 5 6 7 8 9 + "# + ), + 45, + i64 + ); + } + + #[test] + fn pow_int() { + assert_evals_to!("Num.powInt 2 3", 8, i64); + } + + #[test] + fn acos() { + assert_evals_to!("Num.acos 0.5", 1.0471975511965979, f64); + } + + #[test] + fn asin() { + assert_evals_to!("Num.asin 0.5", 0.5235987755982989, f64); + } + + #[test] + fn atan() { + assert_evals_to!("Num.atan 10", 1.4711276743037347, f64); + } + + #[test] + fn gen_if_fn() { + assert_evals_to!( + indoc!( + r#" + limitedNegate = \num -> + x = + if num == 1 then + -1 + else if num == -1 then + 1 + else + num + x + + limitedNegate 1 + "# + ), + -1, + i64 + ); + } + + #[test] + fn gen_fib_fn() { + assert_evals_to!( + indoc!( + r#" + fib = \n -> + if n == 0 then + 0 + else if n == 1 then + 1 + else + (fib (n - 1)) + (fib (n - 2)) + + fib 10 + "# + ), + 55, + i64 + ); + } + + #[test] + fn f64_abs() { + assert_evals_to!("Num.abs -4.7", 4.7, f64); + assert_evals_to!("Num.abs 5.8", 5.8, f64); + } + + #[test] + fn f64_round() { + assert_evals_to!("Num.round 3.6", 4, i64); + assert_evals_to!("Num.round 3.4", 3, i64); + assert_evals_to!("Num.round 2.5", 3, i64); + assert_evals_to!("Num.round -2.3", -2, i64); + assert_evals_to!("Num.round -2.5", -3, i64); + } + + // #[test] + // fn f64_sqrt() { + // // FIXME this works with normal types, but fails when checking uniqueness types + // assert_evals_to!( + // indoc!( + // r#" + // when Num.sqrt 100 is + // Ok val -> val + // Err _ -> -1 + // "# + // ), + // 10.0, + // f64 + // ); + // } + + // #[test] + // fn gen_float_eq() { + // assert_evals_to!( + // indoc!( + // r#" + // 1.0 == 1.0 + // "# + // ), + // true, + // bool + // ); + // } + + // #[test] + // fn gen_div_f64() { + // // FIXME this works with normal types, but fails when checking uniqueness types + // assert_evals_to!( + // indoc!( + // r#" + // when 48 / 2 is + // Ok val -> val + // Err _ -> -1 + // "# + // ), + // 24.0, + // f64 + // ); + // } + + // #[test] + // fn gen_int_neq() { + // assert_evals_to!( + // indoc!( + // r#" + // 4 != 5 + // "# + // ), + // true, + // bool + // ); + // } + + // #[test] + // fn gen_wrap_int_neq() { + // assert_evals_to!( + // indoc!( + // r#" + // wrappedNotEq : a, a -> Bool + // wrappedNotEq = \num1, num2 -> + // num1 != num2 + + // wrappedNotEq 2 3 + // "# + // ), + // true, + // bool + // ); + // } + + // #[test] + // fn gen_sub_f64() { + // assert_evals_to!( + // indoc!( + // r#" + // 1.5 - 2.4 - 3 + // "# + // ), + // -3.9, + // f64 + // ); + // } + + // #[test] + // fn gen_div_i64() { + // assert_evals_to!( + // indoc!( + // r#" + // when 1000 // 10 is + // Ok val -> val + // Err _ -> -1 + // "# + // ), + // 100, + // i64 + // ); + // } + + // #[test] + // fn gen_div_by_zero_i64() { + // assert_evals_to!( + // indoc!( + // r#" + // when 1000 // 0 is + // Err DivByZero -> 99 + // _ -> -24 + // "# + // ), + // 99, + // i64 + // ); + // } + + // #[test] + // fn gen_rem_i64() { + // assert_evals_to!( + // indoc!( + // r#" + // when Num.rem 8 3 is + // Ok val -> val + // Err _ -> -1 + // "# + // ), + // 2, + // i64 + // ); + // } + + // #[test] + // fn gen_rem_div_by_zero_i64() { + // assert_evals_to!( + // indoc!( + // r#" + // when Num.rem 8 0 is + // Err DivByZero -> 4 + // Ok _ -> -23 + // "# + // ), + // 4, + // i64 + // ); + // } + + // #[test] + // fn gen_is_zero_i64() { + // assert_evals_to!("Num.isZero 0", true, bool); + // assert_evals_to!("Num.isZero 1", false, bool); + // } + + // #[test] + // fn gen_is_positive_i64() { + // assert_evals_to!("Num.isPositive 0", false, bool); + // assert_evals_to!("Num.isPositive 1", true, bool); + // assert_evals_to!("Num.isPositive -5", false, bool); + // } + + // #[test] + // fn gen_is_negative_i64() { + // assert_evals_to!("Num.isNegative 0", false, bool); + // assert_evals_to!("Num.isNegative 3", false, bool); + // assert_evals_to!("Num.isNegative -2", true, bool); + // } + + // #[test] + // fn gen_is_positive_f64() { + // assert_evals_to!("Num.isPositive 0.0", false, bool); + // assert_evals_to!("Num.isPositive 4.7", true, bool); + // assert_evals_to!("Num.isPositive -8.5", false, bool); + // } + + // #[test] + // fn gen_is_negative_f64() { + // assert_evals_to!("Num.isNegative 0.0", false, bool); + // assert_evals_to!("Num.isNegative 9.9", false, bool); + // assert_evals_to!("Num.isNegative -4.4", true, bool); + // } + + // #[test] + // fn gen_is_zero_f64() { + // assert_evals_to!("Num.isZero 0", true, bool); + // assert_evals_to!("Num.isZero 0_0", true, bool); + // assert_evals_to!("Num.isZero 0.0", true, bool); + // assert_evals_to!("Num.isZero 1", false, bool); + // } + + // #[test] + // fn gen_is_odd() { + // assert_evals_to!("Num.isOdd 4", false, bool); + // assert_evals_to!("Num.isOdd 5", true, bool); + // } + + // #[test] + // fn gen_is_even() { + // assert_evals_to!("Num.isEven 6", true, bool); + // assert_evals_to!("Num.isEven 7", false, bool); + // } + + // #[test] + // fn sin() { + // assert_evals_to!("Num.sin 0", 0.0, f64); + // assert_evals_to!("Num.sin 1.41421356237", 0.9877659459922529, f64); + // } + + // #[test] + // fn cos() { + // assert_evals_to!("Num.cos 0", 1.0, f64); + // assert_evals_to!("Num.cos 3.14159265359", -1.0, f64); + // } + + // #[test] + // fn tan() { + // assert_evals_to!("Num.tan 0", 0.0, f64); + // assert_evals_to!("Num.tan 1", 1.557407724654902, f64); + // } + + // #[test] + // fn lt_i64() { + // assert_evals_to!("1 < 2", true, bool); + // assert_evals_to!("1 < 1", false, bool); + // assert_evals_to!("2 < 1", false, bool); + // assert_evals_to!("0 < 0", false, bool); + // } + + // #[test] + // fn lte_i64() { + // assert_evals_to!("1 <= 1", true, bool); + // assert_evals_to!("2 <= 1", false, bool); + // assert_evals_to!("1 <= 2", true, bool); + // assert_evals_to!("0 <= 0", true, bool); + // } + + // #[test] + // fn gt_i64() { + // assert_evals_to!("2 > 1", true, bool); + // assert_evals_to!("2 > 2", false, bool); + // assert_evals_to!("1 > 1", false, bool); + // assert_evals_to!("0 > 0", false, bool); + // } + + // #[test] + // fn gte_i64() { + // assert_evals_to!("1 >= 1", true, bool); + // assert_evals_to!("1 >= 2", false, bool); + // assert_evals_to!("2 >= 1", true, bool); + // assert_evals_to!("0 >= 0", true, bool); + // } + + // #[test] + // fn lt_f64() { + // assert_evals_to!("1.1 < 1.2", true, bool); + // assert_evals_to!("1.1 < 1.1", false, bool); + // assert_evals_to!("1.2 < 1.1", false, bool); + // assert_evals_to!("0.0 < 0.0", false, bool); + // } + + // #[test] + // fn lte_f64() { + // assert_evals_to!("1.1 <= 1.1", true, bool); + // assert_evals_to!("1.2 <= 1.1", false, bool); + // assert_evals_to!("1.1 <= 1.2", true, bool); + // assert_evals_to!("0.0 <= 0.0", true, bool); + // } + + // #[test] + // fn gt_f64() { + // assert_evals_to!("2.2 > 1.1", true, bool); + // assert_evals_to!("2.2 > 2.2", false, bool); + // assert_evals_to!("1.1 > 2.2", false, bool); + // assert_evals_to!("0.0 > 0.0", false, bool); + // } + + // #[test] + // fn gte_f64() { + // assert_evals_to!("1.1 >= 1.1", true, bool); + // assert_evals_to!("1.1 >= 1.2", false, bool); + // assert_evals_to!("1.2 >= 1.1", true, bool); + // assert_evals_to!("0.0 >= 0.0", true, bool); + // } + + // #[test] + // fn gen_order_of_arithmetic_ops() { + // assert_evals_to!( + // indoc!( + // r#" + // 1 + 3 * 7 - 2 + // "# + // ), + // 20, + // i64 + // ); + // } + + // #[test] + // fn gen_order_of_arithmetic_ops_complex_float() { + // assert_evals_to!( + // indoc!( + // r#" + // 3 - 48 * 2.0 + // "# + // ), + // -93.0, + // f64 + // ); + // } + + // #[test] + // fn if_guard_bind_variable_false() { + // assert_evals_to!( + // indoc!( + // r#" + // wrapper = \{} -> + // when 10 is + // x if x == 5 -> 0 + // _ -> 42 + + // wrapper {} + // "# + // ), + // 42, + // i64 + // ); + // } + + // #[test] + // fn if_guard_bind_variable_true() { + // assert_evals_to!( + // indoc!( + // r#" + // wrapper = \{} -> + // when 10 is + // x if x == 10 -> 42 + // _ -> 0 + + // wrapper {} + // "# + // ), + // 42, + // i64 + // ); + // } + + // #[test] + // fn tail_call_elimination() { + // assert_evals_to!( + // indoc!( + // r#" + // sum = \n, accum -> + // when n is + // 0 -> accum + // _ -> sum (n - 1) (n + accum) + + // sum 1_000_000 0 + // "# + // ), + // 500000500000, + // i64 + // ); + // } + + // #[test] + // fn int_negate() { + // assert_evals_to!("Num.neg 123", -123, i64); + // } + + // #[test] + // fn gen_wrap_int_neg() { + // assert_evals_to!( + // indoc!( + // r#" + // wrappedNeg = \num -> -num + + // wrappedNeg 3 + // "# + // ), + // -3, + // i64 + // ); + // } + + // #[test] + // fn int_to_float() { + // assert_evals_to!("Num.toFloat 0x9", 9.0, f64); + // } + + // #[test] + // fn num_to_float() { + // assert_evals_to!("Num.toFloat 9", 9.0, f64); + // } + + // #[test] + // fn float_to_float() { + // assert_evals_to!("Num.toFloat 0.5", 0.5, f64); + // } + + // #[test] + // fn int_compare() { + // assert_evals_to!("Num.compare 0 1", RocOrder::Lt, RocOrder); + // assert_evals_to!("Num.compare 1 1", RocOrder::Eq, RocOrder); + // assert_evals_to!("Num.compare 1 0", RocOrder::Gt, RocOrder); + // } + + // #[test] + // fn float_compare() { + // assert_evals_to!("Num.compare 0.01 3.14", RocOrder::Lt, RocOrder); + // assert_evals_to!("Num.compare 3.14 3.14", RocOrder::Eq, RocOrder); + // assert_evals_to!("Num.compare 3.14 0.01", RocOrder::Gt, RocOrder); + // } + + // #[test] + // fn pow() { + // assert_evals_to!("Num.pow 2.0 2.0", 4.0, f64); + // } + + // #[test] + // fn ceiling() { + // assert_evals_to!("Num.ceiling 1.1", 2, i64); + // } + + // #[test] + // fn floor() { + // assert_evals_to!("Num.floor 1.9", 1, i64); + // } + + // // #[test] + // // #[should_panic(expected = r#"Roc failed with message: "integer addition overflowed!"#)] + // // fn int_overflow() { + // // assert_evals_to!( + // // indoc!( + // // r#" + // // 9_223_372_036_854_775_807 + 1 + // // "# + // // ), + // // 0, + // // i64 + // // ); + // // } + + // #[test] + // fn int_add_checked() { + // assert_evals_to!( + // indoc!( + // r#" + // when Num.addChecked 1 2 is + // Ok v -> v + // _ -> -1 + // "# + // ), + // 3, + // i64 + // ); + + // assert_evals_to!( + // indoc!( + // r#" + // when Num.addChecked 9_223_372_036_854_775_807 1 is + // Err Overflow -> -1 + // Ok v -> v + // "# + // ), + // -1, + // i64 + // ); + // } + + // #[test] + // fn int_add_wrap() { + // assert_evals_to!( + // indoc!( + // r#" + // Num.addWrap 9_223_372_036_854_775_807 1 + // "# + // ), + // std::i64::MIN, + // i64 + // ); + // } + + // #[test] + // fn float_add_checked_pass() { + // assert_evals_to!( + // indoc!( + // r#" + // when Num.addChecked 1.0 0.0 is + // Ok v -> v + // Err Overflow -> -1.0 + // "# + // ), + // 1.0, + // f64 + // ); + // } + + // #[test] + // fn float_add_checked_fail() { + // assert_evals_to!( + // indoc!( + // r#" + // when Num.addChecked 1.7976931348623157e308 1.7976931348623157e308 is + // Err Overflow -> -1 + // Ok v -> v + // "# + // ), + // -1.0, + // f64 + // ); + // } + + // // #[test] + // // #[should_panic(expected = r#"Roc failed with message: "float addition overflowed!"#)] + // // fn float_overflow() { + // // assert_evals_to!( + // // indoc!( + // // r#" + // // 1.7976931348623157e308 + 1.7976931348623157e308 + // // "# + // // ), + // // 0.0, + // // f64 + // // ); + // // } + + // #[test] + // fn max_i128() { + // assert_evals_to!( + // indoc!( + // r#" + // Num.maxI128 + // "# + // ), + // i128::MAX, + // i128 + // ); + // } + + // #[test] + // fn num_max_int() { + // assert_evals_to!( + // indoc!( + // r#" + // Num.maxInt + // "# + // ), + // i64::MAX, + // i64 + // ); + // } + + // #[test] + // fn num_min_int() { + // assert_evals_to!( + // indoc!( + // r#" + // Num.minInt + // "# + // ), + // i64::MIN, + // i64 + // ); + // } +} diff --git a/compiler/gen_wasm/tests/wasm_records.rs b/compiler/gen_wasm/tests/wasm_records.rs new file mode 100644 index 0000000000..2fcebe8c97 --- /dev/null +++ b/compiler/gen_wasm/tests/wasm_records.rs @@ -0,0 +1,937 @@ +#[macro_use] +extern crate indoc; + +#[macro_use] +mod helpers; + +#[cfg(all(test, target_os = "linux", any(target_arch = "x86_64"/*, target_arch = "aarch64"*/)))] +mod dev_records { + #[test] + fn basic_record() { + assert_evals_to!( + indoc!( + r#" + { y: 17, x: 15, z: 19 }.x + "# + ), + 15, + i64 + ); + + assert_evals_to!( + indoc!( + r#" + { x: 15, y: 17, z: 19 }.y + "# + ), + 17, + i64 + ); + + assert_evals_to!( + indoc!( + r#" + { x: 15, y: 17, z: 19 }.z + "# + ), + 19, + i64 + ); + } + + #[test] + fn nested_record() { + assert_evals_to!( + indoc!( + r#" + { x: 15, y: { a: 12, b: 15, c: 2}, z: 19 }.x + "# + ), + 15, + i64 + ); + + assert_evals_to!( + indoc!( + r#" + { x: 15, y: { a: 12, b: 15, c: 2}, z: 19 }.y.a + "# + ), + 12, + i64 + ); + + assert_evals_to!( + indoc!( + r#" + { x: 15, y: { a: 12, b: 15, c: 2}, z: 19 }.y.b + "# + ), + 15, + i64 + ); + + assert_evals_to!( + indoc!( + r#" + { x: 15, y: { a: 12, b: 15, c: 2}, z: 19 }.y.c + "# + ), + 2, + i64 + ); + + assert_evals_to!( + indoc!( + r#" + { x: 15, y: { a: 12, b: 15, c: 2}, z: 19 }.z + "# + ), + 19, + i64 + ); + } + + #[test] + fn f64_record() { + assert_evals_to!( + indoc!( + r#" + rec = { y: 17.2, x: 15.1, z: 19.3 } + + rec.x + "# + ), + 15.1, + f64 + ); + + assert_evals_to!( + indoc!( + r#" + rec = { y: 17.2, x: 15.1, z: 19.3 } + + rec.y + "# + ), + 17.2, + f64 + ); + + assert_evals_to!( + indoc!( + r#" + rec = { y: 17.2, x: 15.1, z: 19.3 } + + rec.z + "# + ), + 19.3, + f64 + ); + } + + // #[test] + // fn fn_record() { + // assert_evals_to!( + // indoc!( + // r#" + // getRec = \x -> { y: 17, x, z: 19 } + + // (getRec 15).x + // "# + // ), + // 15, + // i64 + // ); + + // assert_evals_to!( + // indoc!( + // r#" + // rec = { x: 15, y: 17, z: 19 } + + // rec.y + // "# + // ), + // 17, + // i64 + // ); + + // assert_evals_to!( + // indoc!( + // r#" + // rec = { x: 15, y: 17, z: 19 } + + // rec.z + // "# + // ), + // 19, + // i64 + // ); + + // assert_evals_to!( + // indoc!( + // r#" + // rec = { x: 15, y: 17, z: 19 } + + // rec.z + rec.x + // "# + // ), + // 34, + // i64 + // ); + // } + + #[test] + fn def_record() { + assert_evals_to!( + indoc!( + r#" + rec = { y: 17, x: 15, z: 19 } + + rec.x + "# + ), + 15, + i64 + ); + + assert_evals_to!( + indoc!( + r#" + rec = { x: 15, y: 17, z: 19 } + + rec.y + "# + ), + 17, + i64 + ); + + assert_evals_to!( + indoc!( + r#" + rec = { x: 15, y: 17, z: 19 } + + rec.z + "# + ), + 19, + i64 + ); + } + + #[test] + fn when_on_record() { + assert_evals_to!( + indoc!( + r#" + when { x: 0x2 } is + { x } -> x + 3 + "# + ), + 5, + i64 + ); + } + + #[test] + fn when_record_with_guard_pattern() { + assert_evals_to!( + indoc!( + r#" + when { x: 0x2, y: 3.14 } is + { x: var } -> var + 3 + "# + ), + 5, + i64 + ); + } + + #[test] + fn let_with_record_pattern() { + assert_evals_to!( + indoc!( + r#" + { x } = { x: 0x2, y: 3.14 } + + x + "# + ), + 2, + i64 + ); + } + + #[test] + fn record_guard_pattern() { + assert_evals_to!( + indoc!( + r#" + when { x: 0x2, y: 3.14 } is + { x: 0x4 } -> 5 + { x } -> x + 3 + "# + ), + 5, + i64 + ); + } + + #[test] + fn twice_record_access() { + assert_evals_to!( + indoc!( + r#" + x = {a: 0x2, b: 0x3 } + + x.a + x.b + "# + ), + 5, + i64 + ); + } + #[test] + fn empty_record() { + assert_evals_to!( + indoc!( + r#" + v = {} + + v + "# + ), + (), + () + ); + } + + #[test] + fn i64_record1_literal() { + assert_evals_to!( + indoc!( + r#" + { x: 3 } + "# + ), + 3, + i64 + ); + } + + // #[test] + // fn i64_record2_literal() { + // assert_evals_to!( + // indoc!( + // r#" + // { x: 3, y: 5 } + // "# + // ), + // (3, 5), + // (i64, i64) + // ); + // } + + // // #[test] + // // fn i64_record3_literal() { + // // assert_evals_to!( + // // indoc!( + // // r#" + // // { x: 3, y: 5, z: 17 } + // // "# + // // ), + // // (3, 5, 17), + // // (i64, i64, i64) + // // ); + // // } + + // #[test] + // fn f64_record2_literal() { + // assert_evals_to!( + // indoc!( + // r#" + // { x: 3.1, y: 5.1 } + // "# + // ), + // (3.1, 5.1), + // (f64, f64) + // ); + // } + + // // #[test] + // // fn f64_record3_literal() { + // // assert_evals_to!( + // // indoc!( + // // r#" + // // { x: 3.1, y: 5.1, z: 17.1 } + // // "# + // // ), + // // (3.1, 5.1, 17.1), + // // (f64, f64, f64) + // // ); + // // } + + // // #[test] + // // fn bool_record4_literal() { + // // assert_evals_to!( + // // indoc!( + // // r#" + // // record : { a : Bool, b : Bool, c : Bool, d : Bool } + // // record = { a: True, b: True, c : True, d : Bool } + + // // record + // // "# + // // ), + // // (true, false, false, true), + // // (bool, bool, bool, bool) + // // ); + // // } + + // #[test] + // fn i64_record1_literal() { + // assert_evals_to!( + // indoc!( + // r#" + // { a: 3 } + // "# + // ), + // 3, + // i64 + // ); + // } + + // // #[test] + // // fn i64_record9_literal() { + // // assert_evals_to!( + // // indoc!( + // // r#" + // // { a: 3, b: 5, c: 17, d: 1, e: 9, f: 12, g: 13, h: 14, i: 15 } + // // "# + // // ), + // // (3, 5, 17, 1, 9, 12, 13, 14, 15), + // // (i64, i64, i64, i64, i64, i64, i64, i64, i64) + // // ); + // // } + + // // #[test] + // // fn f64_record3_literal() { + // // assert_evals_to!( + // // indoc!( + // // r#" + // // { x: 3.1, y: 5.1, z: 17.1 } + // // "# + // // ), + // // (3.1, 5.1, 17.1), + // // (f64, f64, f64) + // // ); + // // } + + // #[test] + // fn bool_literal() { + // assert_evals_to!( + // indoc!( + // r#" + // x : Bool + // x = True + + // x + // "# + // ), + // true, + // bool + // ); + // } + + // #[test] + // fn optional_field_when_use_default() { + // assert_evals_to!( + // indoc!( + // r#" + // app "test" provides [ main ] to "./platform" + + // f = \r -> + // when r is + // { x: Blue, y ? 3 } -> y + // { x: Red, y ? 5 } -> y + + // main = + // a = f { x: Blue, y: 7 } + // b = f { x: Blue } + // c = f { x: Red, y: 11 } + // d = f { x: Red } + + // a * b * c * d + // "# + // ), + // 3 * 5 * 7 * 11, + // i64 + // ); + // } + + // #[test] + // fn optional_field_when_use_default_nested() { + // assert_evals_to!( + // indoc!( + // r#" + // f = \r -> + // when r is + // { x: Blue, y ? 3 } -> y + // { x: Red, y ? 5 } -> y + + // a = f { x: Blue, y: 7 } + // b = f { x: Blue } + // c = f { x: Red, y: 11 } + // d = f { x: Red } + + // a * b * c * d + // "# + // ), + // 3 * 5 * 7 * 11, + // i64 + // ); + // } + + // #[test] + // fn optional_field_when_no_use_default() { + // assert_evals_to!( + // indoc!( + // r#" + // app "test" provides [ main ] to "./platform" + + // f = \r -> + // { x ? 10, y } = r + // x + y + + // main = + // f { x: 4, y: 9 } + // "# + // ), + // 13, + // i64 + // ); + // } + + // #[test] + // fn optional_field_when_no_use_default_nested() { + // assert_evals_to!( + // indoc!( + // r#" + // f = \r -> + // { x ? 10, y } = r + // x + y + + // f { x: 4, y: 9 } + // "# + // ), + // 13, + // i64 + // ); + // } + + // #[test] + // fn optional_field_let_use_default() { + // assert_evals_to!( + // indoc!( + // r#" + // app "test" provides [ main ] to "./platform" + + // f = \r -> + // { x ? 10, y } = r + // x + y + + // main = + // f { y: 9 } + // "# + // ), + // 19, + // i64 + // ); + // } + + // #[test] + // fn optional_field_let_no_use_default() { + // assert_evals_to!( + // indoc!( + // r#" + // app "test" provides [ main ] to "./platform" + + // f = \r -> + // { x ? 10, y } = r + // x + y + + // main = + // f { x: 4, y: 9 } + // "# + // ), + // 13, + // i64 + // ); + // } + + // #[test] + // fn optional_field_let_no_use_default_nested() { + // assert_evals_to!( + // indoc!( + // r#" + // f = \r -> + // { x ? 10, y } = r + // x + y + + // f { x: 4, y: 9 } + // "# + // ), + // 13, + // i64 + // ); + // } + + // #[test] + // fn optional_field_function_use_default() { + // assert_evals_to!( + // indoc!( + // r#" + // f = \{ x ? 10, y } -> x + y + + // f { y: 9 } + // "# + // ), + // 19, + // i64 + // ); + // } + + // #[test] + // #[ignore] + // fn optional_field_function_no_use_default() { + // // blocked on https://github.com/rtfeldman/roc/issues/786 + // assert_evals_to!( + // indoc!( + // r#" + // app "test" provides [ main ] to "./platform" + + // f = \{ x ? 10, y } -> x + y + + // main = + // f { x: 4, y: 9 } + // "# + // ), + // 13, + // i64 + // ); + // } + + // #[test] + // #[ignore] + // fn optional_field_function_no_use_default_nested() { + // // blocked on https://github.com/rtfeldman/roc/issues/786 + // assert_evals_to!( + // indoc!( + // r#" + // f = \{ x ? 10, y } -> x + y + + // f { x: 4, y: 9 } + // "# + // ), + // 13, + // i64 + // ); + // } + + // #[test] + // fn optional_field_singleton_record() { + // assert_evals_to!( + // indoc!( + // r#" + // when { x : 4 } is + // { x ? 3 } -> x + // "# + // ), + // 4, + // i64 + // ); + // } + + // #[test] + // fn optional_field_empty_record() { + // assert_evals_to!( + // indoc!( + // r#" + // when { } is + // { x ? 3 } -> x + // "# + // ), + // 3, + // i64 + // ); + // } + + // #[test] + // fn return_record_2() { + // assert_evals_to!( + // indoc!( + // r#" + // { x: 3, y: 5 } + // "# + // ), + // [3, 5], + // [i64; 2] + // ); + // } + + // #[test] + // fn return_record_3() { + // assert_evals_to!( + // indoc!( + // r#" + // { x: 3, y: 5, z: 4 } + // "# + // ), + // (3, 5, 4), + // (i64, i64, i64) + // ); + // } + + // #[test] + // fn return_record_4() { + // assert_evals_to!( + // indoc!( + // r#" + // { a: 3, b: 5, c: 4, d: 2 } + // "# + // ), + // [3, 5, 4, 2], + // [i64; 4] + // ); + // } + + // #[test] + // fn return_record_5() { + // assert_evals_to!( + // indoc!( + // r#" + // { a: 3, b: 5, c: 4, d: 2, e: 1 } + // "# + // ), + // [3, 5, 4, 2, 1], + // [i64; 5] + // ); + // } + + // #[test] + // fn return_record_6() { + // assert_evals_to!( + // indoc!( + // r#" + // { a: 3, b: 5, c: 4, d: 2, e: 1, f: 7 } + // "# + // ), + // [3, 5, 4, 2, 1, 7], + // [i64; 6] + // ); + // } + + // #[test] + // fn return_record_7() { + // assert_evals_to!( + // indoc!( + // r#" + // { a: 3, b: 5, c: 4, d: 2, e: 1, f: 7, g: 8 } + // "# + // ), + // [3, 5, 4, 2, 1, 7, 8], + // [i64; 7] + // ); + // } + + // #[test] + // fn return_record_float_int() { + // assert_evals_to!( + // indoc!( + // r#" + // { a: 3.14, b: 0x1 } + // "# + // ), + // (3.14, 0x1), + // (f64, i64) + // ); + // } + + // #[test] + // fn return_record_int_float() { + // assert_evals_to!( + // indoc!( + // r#" + // { a: 0x1, b: 3.14 } + // "# + // ), + // (0x1, 3.14), + // (i64, f64) + // ); + // } + + // #[test] + // fn return_record_float_float() { + // assert_evals_to!( + // indoc!( + // r#" + // { a: 6.28, b: 3.14 } + // "# + // ), + // (6.28, 3.14), + // (f64, f64) + // ); + // } + + // #[test] + // fn return_record_float_float_float() { + // assert_evals_to!( + // indoc!( + // r#" + // { a: 6.28, b: 3.14, c: 0.1 } + // "# + // ), + // (6.28, 3.14, 0.1), + // (f64, f64, f64) + // ); + // } + + // #[test] + // fn return_nested_record() { + // assert_evals_to!( + // indoc!( + // r#" + // { flag: 0x0, payload: { a: 6.28, b: 3.14, c: 0.1 } } + // "# + // ), + // (0x0, (6.28, 3.14, 0.1)), + // (i64, (f64, f64, f64)) + // ); + // } + + // #[test] + // fn accessor() { + // assert_evals_to!( + // indoc!( + // r#" + // .foo { foo: 4 } + .foo { bar: 6.28, foo: 3 } + // "# + // ), + // 7, + // i64 + // ); + // } + + // #[test] + // fn accessor_single_element_record() { + // assert_evals_to!( + // indoc!( + // r#" + // .foo { foo: 4 } + // "# + // ), + // 4, + // i64 + // ); + // } + + // #[test] + // fn update_record() { + // assert_evals_to!( + // indoc!( + // r#" + // rec = { foo: 42, bar: 6 } + + // { rec & foo: rec.foo + 1 } + // "# + // ), + // (6, 43), + // (i64, i64) + // ); + // } + + #[test] + fn update_single_element_record() { + assert_evals_to!( + indoc!( + r#" + rec = { foo: 42} + + { rec & foo: rec.foo + 1 } + "# + ), + 43, + i64 + ); + } + + // #[test] + // fn booleans_in_record() { + // assert_evals_to!( + // indoc!("{ x: 1 == 1, y: 1 == 1 }"), + // (true, true), + // (bool, bool) + // ); + // assert_evals_to!( + // indoc!("{ x: 1 != 1, y: 1 == 1 }"), + // (false, true), + // (bool, bool) + // ); + // assert_evals_to!( + // indoc!("{ x: 1 == 1, y: 1 != 1 }"), + // (true, false), + // (bool, bool) + // ); + // assert_evals_to!( + // indoc!("{ x: 1 != 1, y: 1 != 1 }"), + // (false, false), + // (bool, bool) + // ); + // } + + // #[test] + // fn alignment_in_record() { + // assert_evals_to!( + // indoc!("{ c: 32, b: if True then Red else if True then Green else Blue, a: 1 == 1 }"), + // (32i64, true, 2u8), + // (i64, bool, u8) + // ); + // } + + // #[test] + // fn blue_and_present() { + // assert_evals_to!( + // indoc!( + // r#" + // f = \r -> + // when r is + // { x: Blue, y ? 3 } -> y + // { x: Red, y ? 5 } -> y + + // f { x: Blue, y: 7 } + // "# + // ), + // 7, + // i64 + // ); + // } + + // #[test] + // fn blue_and_absent() { + // assert_evals_to!( + // indoc!( + // r#" + // f = \r -> + // when r is + // { x: Blue, y ? 3 } -> y + // { x: Red, y ? 5 } -> y + + // f { x: Blue } + // "# + // ), + // 3, + // i64 + // ); + // } +} From 08e242967a83ac249c6716a1530774eb01f3c267 Mon Sep 17 00:00:00 2001 From: Folkert Date: Wed, 1 Sep 2021 22:36:34 +0200 Subject: [PATCH 13/42] function must end with an End instruction --- compiler/gen_wasm/src/backend.rs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/compiler/gen_wasm/src/backend.rs b/compiler/gen_wasm/src/backend.rs index c27ea37000..2b9920d780 100644 --- a/compiler/gen_wasm/src/backend.rs +++ b/compiler/gen_wasm/src/backend.rs @@ -120,11 +120,15 @@ impl<'a> WasmBackend<'a> { .with_result(self.ret_type) .build_sig(); + // functions must end with an End instruction/opcode + let mut instructions = self.instructions.clone(); + instructions.push(Instruction::End); + let function_def = builder::function() .with_signature(signature) .body() .with_locals(self.locals.clone()) - .with_instructions(Instructions::new(self.instructions.clone())) + .with_instructions(Instructions::new(instructions)) .build() // body .build(); // function From 13a969a2387645189e6c30be69dcbd49150e84c1 Mon Sep 17 00:00:00 2001 From: Brian Carroll Date: Fri, 3 Sep 2021 21:54:57 +0100 Subject: [PATCH 14/42] Bugfixes: generate valid wasm for gen_add_i64 Still need to create test_wrapper --- compiler/gen_wasm/.gitignore | 3 +++ compiler/gen_wasm/src/backend.rs | 25 ++++++++----------------- compiler/gen_wasm/src/lib.rs | 18 ++++++++++++++++-- compiler/gen_wasm/tests/helpers/eval.rs | 21 +++++++++++++++++++-- 4 files changed, 46 insertions(+), 21 deletions(-) create mode 100644 compiler/gen_wasm/.gitignore diff --git a/compiler/gen_wasm/.gitignore b/compiler/gen_wasm/.gitignore new file mode 100644 index 0000000000..64bbb919fa --- /dev/null +++ b/compiler/gen_wasm/.gitignore @@ -0,0 +1,3 @@ +*.wasm +*.wat +/notes.md diff --git a/compiler/gen_wasm/src/backend.rs b/compiler/gen_wasm/src/backend.rs index 2b9920d780..32c1f80fb9 100644 --- a/compiler/gen_wasm/src/backend.rs +++ b/compiler/gen_wasm/src/backend.rs @@ -12,14 +12,16 @@ use roc_mono::layout::{Builtin, Layout}; // Follow Emscripten's example by using 1kB (4 bytes would probably do) const UNUSED_DATA_SECTION_BYTES: u32 = 1024; -#[derive(Clone, Copy)] +#[derive(Clone, Copy, Debug)] struct LocalId(u32); -#[derive(Clone, Copy)] +#[derive(Clone, Copy, Debug)] struct LabelId(u32); +#[derive(Debug)] struct SymbolStorage(LocalId, WasmLayout); +#[derive(Debug)] struct WasmLayout { value_type: ValueType, stack_memory: u32, @@ -154,7 +156,7 @@ impl<'a> WasmBackend<'a> { fn get_symbol_storage(&self, sym: &Symbol) -> Result<&SymbolStorage, String> { self.symbol_storage_map .get(sym) - .ok_or(format!("Symbol not found in function scope {:?}", sym)) + .ok_or_else(|| format!("Symbol {:?} not found in function scope:\n{:?}", sym, self.symbol_storage_map)) } fn load_from_symbol(&mut self, sym: &Symbol) -> Result<(), String> { @@ -164,21 +166,13 @@ impl<'a> WasmBackend<'a> { Ok(()) } - // Store whatever value is on top of the VM's stack - fn store_to_symbol(&mut self, sym: &Symbol) -> Result<(), String> { - let SymbolStorage(LocalId(local_id), _) = self.get_symbol_storage(sym)?; - let id: u32 = *local_id; - self.instructions.push(SetLocal(id)); - Ok(()) - } - fn build_stmt(&mut self, stmt: &Stmt<'a>, ret_layout: &Layout<'a>) -> Result<(), String> { match stmt { Stmt::Let(sym, expr, layout, following) => { - self.build_expr(sym, expr, layout)?; - let wasm_layout = WasmLayout::new(layout)?; let local_id = self.insert_local(wasm_layout, *sym); + + self.build_expr(sym, expr, layout)?; self.instructions.push(SetLocal(local_id.0)); self.build_stmt(following, ret_layout)?; @@ -222,12 +216,11 @@ impl<'a> WasmBackend<'a> { func_sym, sym ))?; self.instructions.push(Call(function_location.body)); - self.store_to_symbol(sym)?; Ok(()) } CallType::LowLevel { op: lowlevel, .. } => { - self.build_call_low_level(sym, lowlevel, arguments, layout) + self.build_call_low_level(lowlevel, arguments, layout) } x => Err(format!("the call type, {:?}, is not yet implemented", x)), }, @@ -253,7 +246,6 @@ impl<'a> WasmBackend<'a> { fn build_call_low_level( &mut self, - sym: &Symbol, lowlevel: &LowLevel, args: &'a [Symbol], layout: &Layout<'a>, @@ -263,7 +255,6 @@ impl<'a> WasmBackend<'a> { } let wasm_layout = WasmLayout::new(layout)?; self.build_instructions_lowlevel(lowlevel, wasm_layout.value_type)?; - self.store_to_symbol(sym)?; Ok(()) } diff --git a/compiler/gen_wasm/src/lib.rs b/compiler/gen_wasm/src/lib.rs index ce0f5d48cd..70e8c1c964 100644 --- a/compiler/gen_wasm/src/lib.rs +++ b/compiler/gen_wasm/src/lib.rs @@ -24,7 +24,6 @@ pub fn build_module<'a>( let mut backend = WasmBackend::new(); let mut layout_ids = LayoutIds::default(); - let mut exports = std::vec::Vec::new(); for ((sym, layout), proc) in procedures { let function_index = backend.build_proc(proc, sym)?; if env.exposed_to_host.contains(&sym) { @@ -37,9 +36,24 @@ pub fn build_module<'a>( .with_internal(Internal::Function(function_index)) .build(); - exports.push(export); + backend.builder.push_export(export); } } + + const MIN_MEMORY_SIZE_KB: u32 = 1024; + const PAGE_SIZE_KB: u32 = 64; + + let memory = builder::MemoryBuilder::new() + .with_min(MIN_MEMORY_SIZE_KB / PAGE_SIZE_KB) + .build(); + backend.builder.push_memory(memory); + + let memory_export = builder::export() + .field("memory") + .with_internal(Internal::Memory(0)) + .build(); + backend.builder.push_export(memory_export); + let module = backend.builder.build(); module .to_bytes() diff --git a/compiler/gen_wasm/tests/helpers/eval.rs b/compiler/gen_wasm/tests/helpers/eval.rs index b11eda739a..8a5408e53c 100644 --- a/compiler/gen_wasm/tests/helpers/eval.rs +++ b/compiler/gen_wasm/tests/helpers/eval.rs @@ -67,6 +67,22 @@ pub fn helper_wasm<'a>( procedures.insert(key, proc); } + // You can comment and uncomment this block out to get more useful information + // while you're working on the wasm backend! + // { + // println!("=========== Procedures =========="); + // println!("{:?}", procedures); + // println!("=================================\n"); + + // println!("=========== Interns =========="); + // println!("{:?}", interns); + // println!("=================================\n"); + + // println!("=========== Exposed =========="); + // println!("{:?}", exposed_to_host); + // println!("=================================\n"); + // } + let exposed_to_host = exposed_to_host.keys().copied().collect::>(); let env = gen_wasm::Env { @@ -80,7 +96,8 @@ pub fn helper_wasm<'a>( // for debugging (e.g. with wasm2wat) if false { use std::io::Write; - let mut file = std::fs::File::create("/home/folkertdev/roc/wasm/manual.wasm").unwrap(); + let mut file = + std::fs::File::create("/home/brian/Documents/roc/compiler/gen_wasm/debug.wasm").unwrap(); file.write_all(&module_bytes).unwrap(); } @@ -90,7 +107,7 @@ pub fn helper_wasm<'a>( let store = Store::default(); // let module = Module::from_file(&store, &test_wasm_path).unwrap(); - let module = Module::new(&store, &module_bytes).unwrap(); + let module = Module::from_binary(&store, &module_bytes).unwrap(); // First, we create the `WasiEnv` use wasmer_wasi::WasiState; From bf7b1cdc637280898e17556810e762206f2a0202 Mon Sep 17 00:00:00 2001 From: Brian Carroll Date: Sat, 4 Sep 2021 13:34:04 +0100 Subject: [PATCH 15/42] Don't double-count args as locals --- compiler/gen_wasm/src/backend.rs | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/compiler/gen_wasm/src/backend.rs b/compiler/gen_wasm/src/backend.rs index 32c1f80fb9..2c5929be25 100644 --- a/compiler/gen_wasm/src/backend.rs +++ b/compiler/gen_wasm/src/backend.rs @@ -143,13 +143,10 @@ impl<'a> WasmBackend<'a> { } fn insert_local(&mut self, layout: WasmLayout, symbol: Symbol) -> LocalId { - let local_id = LocalId(self.locals.len() as u32); - self.locals.push(Local::new(1, layout.value_type)); self.stack_memory += layout.stack_memory; - + let local_id = LocalId(self.locals.len() as u32); let storage = SymbolStorage(local_id, layout); self.symbol_storage_map.insert(symbol, storage); - local_id } @@ -170,6 +167,7 @@ impl<'a> WasmBackend<'a> { match stmt { Stmt::Let(sym, expr, layout, following) => { let wasm_layout = WasmLayout::new(layout)?; + self.locals.push(Local::new(1, wasm_layout.value_type)); let local_id = self.insert_local(wasm_layout, *sym); self.build_expr(sym, expr, layout)?; From 1d17a21d1f38ca73d9dd193f77bff7c365f1de9d Mon Sep 17 00:00:00 2001 From: Folkert Date: Sat, 4 Sep 2021 15:18:37 +0200 Subject: [PATCH 16/42] higher alignment requirement on rocstr/roclist --- compiler/builtins/bitcode/src/str.zig | 2 +- compiler/gen_llvm/src/llvm/build_str.rs | 4 ++-- compiler/mono/src/layout.rs | 14 +++++++++----- 3 files changed, 12 insertions(+), 8 deletions(-) diff --git a/compiler/builtins/bitcode/src/str.zig b/compiler/builtins/bitcode/src/str.zig index 2172e693d7..801550663c 100644 --- a/compiler/builtins/bitcode/src/str.zig +++ b/compiler/builtins/bitcode/src/str.zig @@ -1150,8 +1150,8 @@ fn strToBytes(arg: RocStr) RocList { } const FromUtf8Result = extern struct { - byte_index: usize, string: RocStr, + byte_index: usize, is_ok: bool, problem_code: Utf8ByteProblem, }; diff --git a/compiler/gen_llvm/src/llvm/build_str.rs b/compiler/gen_llvm/src/llvm/build_str.rs index 3b35d6d9a9..d143d06da6 100644 --- a/compiler/gen_llvm/src/llvm/build_str.rs +++ b/compiler/gen_llvm/src/llvm/build_str.rs @@ -295,8 +295,8 @@ pub fn str_from_utf8_range<'a, 'ctx, 'env>( let record_type = env.context.struct_type( &[ - env.ptr_int().into(), super::convert::zig_str_type(env).into(), + env.ptr_int().into(), env.context.bool_type().into(), ctx.i8_type().into(), ], @@ -343,8 +343,8 @@ pub fn str_from_utf8<'a, 'ctx, 'env>( let record_type = env.context.struct_type( &[ - env.ptr_int().into(), super::convert::zig_str_type(env).into(), + env.ptr_int().into(), env.context.bool_type().into(), ctx.i8_type().into(), ], diff --git a/compiler/mono/src/layout.rs b/compiler/mono/src/layout.rs index 21d50f2715..0afcae5d15 100644 --- a/compiler/mono/src/layout.rs +++ b/compiler/mono/src/layout.rs @@ -1151,10 +1151,13 @@ impl<'a> Builtin<'a> { Float64 => align_of::() as u32, Float32 => align_of::() as u32, Float16 => align_of::() as u32, - Str | EmptyStr => pointer_size, Dict(_, _) | EmptyDict => pointer_size, Set(_) | EmptySet => pointer_size, - List(_) | EmptyList => pointer_size, + // we often treat these as i128 (64-bit systems) + // or i64 (32-bit systems). For that to be safe + // they must be aligned to allow such access + List(_) | EmptyList => 2 * pointer_size, + Str | EmptyStr => 2 * pointer_size, } } @@ -1240,9 +1243,10 @@ impl<'a> Builtin<'a> { Builtin::Str => pointer_size, Builtin::Dict(k, v) => k .alignment_bytes(pointer_size) - .max(v.alignment_bytes(pointer_size)), - Builtin::Set(k) => k.alignment_bytes(pointer_size), - Builtin::List(e) => e.alignment_bytes(pointer_size), + .max(v.alignment_bytes(pointer_size)) + .max(pointer_size), + Builtin::Set(k) => k.alignment_bytes(pointer_size).max(pointer_size), + Builtin::List(e) => e.alignment_bytes(pointer_size).max(pointer_size), Builtin::EmptyStr | Builtin::EmptyList | Builtin::EmptyDict | Builtin::EmptySet => { unreachable!("not heap-allocated") } From 9713645806167014ac27dd4e4feca2a2e2061b4f Mon Sep 17 00:00:00 2001 From: Folkert Date: Sat, 4 Sep 2021 16:00:22 +0200 Subject: [PATCH 17/42] only round up to 2*usize on 32-bit platforms --- compiler/mono/src/layout.rs | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/compiler/mono/src/layout.rs b/compiler/mono/src/layout.rs index 0afcae5d15..3568ce5045 100644 --- a/compiler/mono/src/layout.rs +++ b/compiler/mono/src/layout.rs @@ -1154,10 +1154,12 @@ impl<'a> Builtin<'a> { Dict(_, _) | EmptyDict => pointer_size, Set(_) | EmptySet => pointer_size, // we often treat these as i128 (64-bit systems) - // or i64 (32-bit systems). For that to be safe + // or i64 (32-bit systems). + // + // In webassembly, For that to be safe // they must be aligned to allow such access - List(_) | EmptyList => 2 * pointer_size, - Str | EmptyStr => 2 * pointer_size, + List(_) | EmptyList => pointer_size.max(8), + Str | EmptyStr => pointer_size.max(8), } } From 93817a38e2878ef458a70153629980a672fee1fc Mon Sep 17 00:00:00 2001 From: Folkert Date: Sat, 4 Sep 2021 16:41:29 +0200 Subject: [PATCH 18/42] convert zig struct to roc record --- compiler/gen_llvm/src/llvm/build_str.rs | 113 +++++++++++++++--------- 1 file changed, 70 insertions(+), 43 deletions(-) diff --git a/compiler/gen_llvm/src/llvm/build_str.rs b/compiler/gen_llvm/src/llvm/build_str.rs index d143d06da6..87a8c50c57 100644 --- a/compiler/gen_llvm/src/llvm/build_str.rs +++ b/compiler/gen_llvm/src/llvm/build_str.rs @@ -1,5 +1,5 @@ use crate::llvm::bitcode::{call_bitcode_fn, call_void_bitcode_fn}; -use crate::llvm::build::{complex_bitcast, Env, Scope}; +use crate::llvm::build::{complex_bitcast, struct_from_fields, Env, Scope}; use crate::llvm::build_list::{allocate_list, call_bitcode_fn_returns_list, store_list}; use inkwell::builder::Builder; use inkwell::values::{BasicValueEnum, FunctionValue, IntValue, PointerValue, StructValue}; @@ -260,6 +260,73 @@ pub fn str_to_utf8<'a, 'ctx, 'env>( call_bitcode_fn_returns_list(env, &[string], bitcode::STR_TO_UTF8) } +fn decode_from_utf8_result<'a, 'ctx, 'env>( + env: &Env<'a, 'ctx, 'env>, + pointer: PointerValue<'ctx>, +) -> StructValue<'ctx> { + let builder = env.builder; + let ctx = env.context; + + let fields = match env.ptr_bytes { + 8 => [ + env.ptr_int().into(), + super::convert::zig_str_type(env).into(), + env.context.bool_type().into(), + ctx.i8_type().into(), + ], + 4 => [ + super::convert::zig_str_type(env).into(), + env.ptr_int().into(), + env.context.bool_type().into(), + ctx.i8_type().into(), + ], + _ => unreachable!(), + }; + + let record_type = env.context.struct_type(&fields, false); + + match env.ptr_bytes { + 8 => { + let zig_struct = builder + .build_load(pointer, "load_utf8_validate_bytes_result") + .into_struct_value(); + + let string = builder + .build_extract_value(zig_struct, 0, "string") + .unwrap(); + + let byte_index = builder + .build_extract_value(zig_struct, 1, "byte_index") + .unwrap(); + + let is_ok = builder.build_extract_value(zig_struct, 2, "is_ok").unwrap(); + + let problem_code = builder + .build_extract_value(zig_struct, 3, "problem_code") + .unwrap(); + + let values = [byte_index, string, is_ok, problem_code]; + + struct_from_fields(env, record_type, values.iter().copied().enumerate()) + } + 4 => { + let result_ptr_cast = env + .builder + .build_bitcast( + pointer, + record_type.ptr_type(AddressSpace::Generic), + "to_unnamed", + ) + .into_pointer_value(); + + builder + .build_load(result_ptr_cast, "load_utf8_validate_bytes_result") + .into_struct_value() + } + _ => unreachable!(), + } +} + /// Str.fromUtf8 : List U8, { count : Nat, start : Nat } -> { a : Bool, b : Str, c : Nat, d : I8 } pub fn str_from_utf8_range<'a, 'ctx, 'env>( env: &Env<'a, 'ctx, 'env>, @@ -268,7 +335,6 @@ pub fn str_from_utf8_range<'a, 'ctx, 'env>( count_and_start: StructValue<'ctx>, ) -> BasicValueEnum<'ctx> { let builder = env.builder; - let ctx = env.context; let result_type = env.module.get_struct_type("str.FromUtf8Result").unwrap(); let result_ptr = builder.build_alloca(result_type, "alloca_utf8_validate_bytes_result"); @@ -293,26 +359,7 @@ pub fn str_from_utf8_range<'a, 'ctx, 'env>( bitcode::STR_FROM_UTF8_RANGE, ); - let record_type = env.context.struct_type( - &[ - super::convert::zig_str_type(env).into(), - env.ptr_int().into(), - env.context.bool_type().into(), - ctx.i8_type().into(), - ], - false, - ); - - let result_ptr_cast = env - .builder - .build_bitcast( - result_ptr, - record_type.ptr_type(AddressSpace::Generic), - "to_unnamed", - ) - .into_pointer_value(); - - builder.build_load(result_ptr_cast, "load_utf8_validate_bytes_result") + decode_from_utf8_result(env, result_ptr).into() } /// Str.fromUtf8 : List U8 -> { a : Bool, b : Str, c : Nat, d : I8 } @@ -322,7 +369,6 @@ pub fn str_from_utf8<'a, 'ctx, 'env>( original_wrapper: StructValue<'ctx>, ) -> BasicValueEnum<'ctx> { let builder = env.builder; - let ctx = env.context; let result_type = env.module.get_struct_type("str.FromUtf8Result").unwrap(); let result_ptr = builder.build_alloca(result_type, "alloca_utf8_validate_bytes_result"); @@ -341,26 +387,7 @@ pub fn str_from_utf8<'a, 'ctx, 'env>( bitcode::STR_FROM_UTF8, ); - let record_type = env.context.struct_type( - &[ - super::convert::zig_str_type(env).into(), - env.ptr_int().into(), - env.context.bool_type().into(), - ctx.i8_type().into(), - ], - false, - ); - - let result_ptr_cast = env - .builder - .build_bitcast( - result_ptr, - record_type.ptr_type(AddressSpace::Generic), - "to_unnamed", - ) - .into_pointer_value(); - - builder.build_load(result_ptr_cast, "load_utf8_validate_bytes_result") + decode_from_utf8_result(env, result_ptr).into() } /// Str.fromInt : Int -> Str From 2e6bf95fdaea9eba2af9d83d63913efe2232a60c Mon Sep 17 00:00:00 2001 From: Folkert Date: Sat, 4 Sep 2021 20:01:06 +0200 Subject: [PATCH 19/42] enable wasm TestBase64 --- cli/tests/cli_run.rs | 10 +++++++++- compiler/build/src/link.rs | 4 +++- 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/cli/tests/cli_run.rs b/cli/tests/cli_run.rs index 2b075bb660..a5d491d912 100644 --- a/cli/tests/cli_run.rs +++ b/cli/tests/cli_run.rs @@ -327,7 +327,7 @@ mod cli_run { // TODO fix QuicksortApp and then remove this! match benchmark.filename { - "QuicksortApp.roc" | "TestBase64.roc" => { + "QuicksortApp.roc" => { eprintln!("WARNING: skipping testing benchmark {} because the test is broken right now!", benchmark.filename); return; } @@ -608,6 +608,14 @@ fn run_with_wasmer(wasm_path: &std::path::Path, stdin: &[&str]) -> String { use std::io::Write; use wasmer::{Instance, Module, Store}; + // std::process::Command::new("cp") + // .args(&[ + // wasm_path.to_str().unwrap(), + // "/home/folkertdev/roc/wasm/nqueens.wasm", + // ]) + // .output() + // .unwrap(); + let store = Store::default(); let module = Module::from_file(&store, &wasm_path).unwrap(); diff --git a/compiler/build/src/link.rs b/compiler/build/src/link.rs index a2c1fc40de..86a5d5df4d 100644 --- a/compiler/build/src/link.rs +++ b/compiler/build/src/link.rs @@ -617,11 +617,13 @@ fn link_wasm32( // include libc "-lc", "-target", - "wasm32-wasi", + "wasm32-wasi-musl", "--pkg-begin", "str", zig_str_path.to_str().unwrap(), "--pkg-end", + "--strip", + // "-O", "ReleaseSmall", // useful for debugging // "-femit-llvm-ir=/home/folkertdev/roc/roc/examples/benchmarks/platform/host.ll", ]) From b445cea964ef8dc4569f2b864b780f0d47b9f793 Mon Sep 17 00:00:00 2001 From: Brian Carroll Date: Sat, 4 Sep 2021 21:35:23 +0100 Subject: [PATCH 20/42] Fix generation of params & locals --- compiler/gen_wasm/src/backend.rs | 25 ++++++++++++++++++++----- 1 file changed, 20 insertions(+), 5 deletions(-) diff --git a/compiler/gen_wasm/src/backend.rs b/compiler/gen_wasm/src/backend.rs index 2c5929be25..3f75256789 100644 --- a/compiler/gen_wasm/src/backend.rs +++ b/compiler/gen_wasm/src/backend.rs @@ -144,16 +144,23 @@ impl<'a> WasmBackend<'a> { fn insert_local(&mut self, layout: WasmLayout, symbol: Symbol) -> LocalId { self.stack_memory += layout.stack_memory; - let local_id = LocalId(self.locals.len() as u32); + let index = self.symbol_storage_map.len(); + if index >= self.arg_types.len() { + self.locals.push(Local::new(1, layout.value_type)); + } + let local_id = LocalId(index as u32); let storage = SymbolStorage(local_id, layout); self.symbol_storage_map.insert(symbol, storage); local_id } fn get_symbol_storage(&self, sym: &Symbol) -> Result<&SymbolStorage, String> { - self.symbol_storage_map - .get(sym) - .ok_or_else(|| format!("Symbol {:?} not found in function scope:\n{:?}", sym, self.symbol_storage_map)) + self.symbol_storage_map.get(sym).ok_or_else(|| { + format!( + "Symbol {:?} not found in function scope:\n{:?}", + sym, self.symbol_storage_map + ) + }) } fn load_from_symbol(&mut self, sym: &Symbol) -> Result<(), String> { @@ -165,9 +172,16 @@ impl<'a> WasmBackend<'a> { fn build_stmt(&mut self, stmt: &Stmt<'a>, ret_layout: &Layout<'a>) -> Result<(), String> { match stmt { + // This pattern is a simple optimisation to get rid of one local and two instructions per proc. + // If we are just returning the expression result, then don't SetLocal and immediately GetLocal + Stmt::Let(let_sym, expr, layout, Stmt::Ret(ret_sym)) if let_sym == ret_sym => { + self.build_expr(let_sym, expr, layout)?; + self.instructions.push(Return); + Ok(()) + } + Stmt::Let(sym, expr, layout, following) => { let wasm_layout = WasmLayout::new(layout)?; - self.locals.push(Local::new(1, wasm_layout.value_type)); let local_id = self.insert_local(wasm_layout, *sym); self.build_expr(sym, expr, layout)?; @@ -176,6 +190,7 @@ impl<'a> WasmBackend<'a> { self.build_stmt(following, ret_layout)?; Ok(()) } + Stmt::Ret(sym) => { if let Some(SymbolStorage(local_id, _)) = self.symbol_storage_map.get(sym) { self.instructions.push(GetLocal(local_id.0)); From 1b8d87d3e008d67eccff454bef2de12ebaec4e72 Mon Sep 17 00:00:00 2001 From: Brian Carroll Date: Sun, 5 Sep 2021 11:26:40 +0100 Subject: [PATCH 21/42] Initial README for Wasm backend --- compiler/gen_wasm/README.md | 91 +++++++++++++++++++++++++++++++++++++ 1 file changed, 91 insertions(+) create mode 100644 compiler/gen_wasm/README.md diff --git a/compiler/gen_wasm/README.md b/compiler/gen_wasm/README.md new file mode 100644 index 0000000000..51d9a147af --- /dev/null +++ b/compiler/gen_wasm/README.md @@ -0,0 +1,91 @@ +# Development backend for WebAssembly + +This document offers a summary of how WebAssembly differs from other targets and how those differences matter for Roc. + +## Stack machine vs register machine + +Wasm's instruction set is based on a stack-machine VM. Whereas CPU instructions have named registers that they operate on, Wasm has no named registers at all. The instructions don't contain register names. Instructions can oly operate on whatever data is at the top of the stack. + +For example the instruction `i64.add` takes two operands. It pops the top two arguments off the VM stack and pushes the result back. + +In the [spec][spec-instructions], every instruction has a type signature! This is not something you would see for CPU instructions. The type signature for i64.add is `[i64 i64]→[i64]` because it pushes two i64's and pops an i64. + +[spec-instructions]: https://webassembly.github.io/spec/core/appendix/index-instructions.html + +This means that WebAssembly has a concept of type checking. When you load a .wasm file as a chunk of bytes into a Wasm runtime (like a browser or [wasmer](https://wasmer.io/)), the runtime will first _validate_ those bytes. They have some fast way of checking whether the types being pushed and popped are consistent. So if you try to do the i64.add instruction when you have floats on the stack, it will fail validation. + +Note that the instruction makes no mention of any source or destination registers, because there is no such thing. It just pops two values and pushes one. + + +Implications of the stack machine for Roc: + +- There is no such thing as register allocation, since there are no registers! There is no reason to maintain hashmaps of what registers are free or not. And there is not much point in doing a pass over the IR to find the "last seen" occurrence of a symbol in the IR. That means we don't need the `Backend` methods `scan_ast`, `scan_ast_call`, `set_last_seen`, `last_seen_map`, `free_map`, `free_symbols`, `free_symbol`, `set_free_map`. + +- There is no random access to the stack. All instructions operate on the data at the _top_ of the stack. There is no instruction that says "get the value at index 17 in the stack". If such an instruction did exist, it wouldn't be a stack machine. And there is no way to "free up some of the slots in the stack". You have to consume the stuff at the top, then the stuff further down. However Wasm has a concept of local variables, which do allow random access. See below. + +## Local variables + +WebAssembly functions can have any number of local variables. They are declared at the beginning of the function, along with their types (just like C). WebAssembly has 4 value types: `i32`, `i64`, `f32`, `f64`. + +In this backend, each symbol in the Mono IR gets one WebAssembly local. To illustrate, let's translate a simple Roc example to WebAssembly text format. +The WebAssembly code below is completely unoptimised and uses far more locals than necessary. But that does help to illustrate the concept of locals. + +``` +app "test" provides [ main ] to "./platform" + +main = + 1 + 2 + 4 +``` + +The Mono IR contains two functions, `Num.add` and `main`, so we generate two corresponding WebAssembly functions. + +``` + (func (;0;) (param i64 i64) (result i64) ; declare function index 0 (Num.add) with two i64 parameters and an i64 result + local.get 0 ; load param 0 stack=[param0] + local.get 1 ; load param 1 stack=[param0, param1] + i64.add ; pop two values, add, and push result stack=[param0 + param1] + return) ; return the value at the top of the stack + + (func (;1;) (result i64) ; declare function index 1 (main) with no parameters and an i64 result + (local i64 i64 i64 i64) ; declare 4 local variables, all with type i64, one for each symbol in the Mono IR + i64.const 1 ; load constant of type i64 and value 1 stack=[1] + local.set 0 ; store top of stack to local0 stack=[] local0=1 + i64.const 2 ; load constant of type i64 and value 2 stack=[2] local0=1 + local.set 1 ; store top of stack to local1 stack=[] local0=1 local1=2 + local.get 0 ; load local0 to top of stack stack=[1] local0=1 local1=2 + local.get 1 ; load local1 to top of stack stack=[1,2] local0=1 local1=2 + call 0 ; call function index 0 (which pops 2 and pushes 1) stack=[3] local0=1 local1=2 + local.set 2 ; store top of stack to local2 stack=[] local0=1 local1=2 local2=3 + i64.const 4 ; load constant of type i64 and value 4 stack=[4] local0=1 local1=2 local2=3 + local.set 3 ; store top of stack to local3 stack=[] local0=1 local1=2 local2=3 local3=4 + local.get 2 ; load local2 to top of stack stack=[3] local0=1 local1=2 local2=3 local3=4 + local.get 3 ; load local3 to top of stack stack=[3,4] local0=1 local1=2 local2=3 local3=4 + call 0 ; call function index 0 (which pops 2 and pushes 1) stack=[7] local0=1 local1=2 local2=3 local3=4 + return) ; return the value at the top of the stack +``` + +If we run this code through the `wasm-opt` tool from the [binaryen toolkit](https://github.com/WebAssembly/binaryen/wiki/Compiling-to-WebAssembly-with-Binaryen), all of the locals get optimised away. But this optimised version is harder to generate directly from the Mono IR. + +``` + (func (;0;) (type 0) (param i64 i64) (result i64) + local.get 0 + local.get 1 + i64.add) ; return can be implicit, like in Rust. Only really needed from inside a branch. + (func (;1;) (type 1) (result i64) + i64.const 1 + i64.const 2 + call 0 + i64.const 4 + call 0) +``` + +## Stack machine vs stack memory +TODO + +## Structured control flow +TODO + +## Modules and objects +TODO + +https://webassembly.github.io/spec/core/binary/modules.html From 545fef307e6a194038fee2ce38560bb77865d43c Mon Sep 17 00:00:00 2001 From: Brian Carroll Date: Sun, 5 Sep 2021 18:12:58 +0100 Subject: [PATCH 22/42] More Wasm info in README --- compiler/gen_wasm/README.md | 75 +++++++++++++++++++++++++++++++------ 1 file changed, 63 insertions(+), 12 deletions(-) diff --git a/compiler/gen_wasm/README.md b/compiler/gen_wasm/README.md index 51d9a147af..3e379de8e6 100644 --- a/compiler/gen_wasm/README.md +++ b/compiler/gen_wasm/README.md @@ -8,18 +8,17 @@ Wasm's instruction set is based on a stack-machine VM. Whereas CPU instructions For example the instruction `i64.add` takes two operands. It pops the top two arguments off the VM stack and pushes the result back. -In the [spec][spec-instructions], every instruction has a type signature! This is not something you would see for CPU instructions. The type signature for i64.add is `[i64 i64]→[i64]` because it pushes two i64's and pops an i64. +In the [spec][spec-instructions], every instruction has a type signature! This is not something you would see for CPU instructions. The type signature for i64.add is `[i64 i64] → [i64]` because it pushes two i64's and pops an i64. [spec-instructions]: https://webassembly.github.io/spec/core/appendix/index-instructions.html This means that WebAssembly has a concept of type checking. When you load a .wasm file as a chunk of bytes into a Wasm runtime (like a browser or [wasmer](https://wasmer.io/)), the runtime will first _validate_ those bytes. They have some fast way of checking whether the types being pushed and popped are consistent. So if you try to do the i64.add instruction when you have floats on the stack, it will fail validation. -Note that the instruction makes no mention of any source or destination registers, because there is no such thing. It just pops two values and pushes one. - +Note that the instruction makes no mention of any source or destination registers, because there is no such thing. It just pops two values and pushes one. (This architecture choice helps to keep WebAssembly programs quite compact. There are no extra bytes specifying source and destination registers.) Implications of the stack machine for Roc: -- There is no such thing as register allocation, since there are no registers! There is no reason to maintain hashmaps of what registers are free or not. And there is not much point in doing a pass over the IR to find the "last seen" occurrence of a symbol in the IR. That means we don't need the `Backend` methods `scan_ast`, `scan_ast_call`, `set_last_seen`, `last_seen_map`, `free_map`, `free_symbols`, `free_symbol`, `set_free_map`. +- There is no such thing as register allocation, since there are no registers! There is no reason to maintain hashmaps of what registers are free or not. And there is no need to do a pass over the IR to find the "last seen" occurrence of a symbol in the IR. That means we don't need the `Backend` methods `scan_ast`, `scan_ast_call`, `set_last_seen`, `last_seen_map`, `free_map`, `free_symbols`, `free_symbol`, `set_free_map`. - There is no random access to the stack. All instructions operate on the data at the _top_ of the stack. There is no instruction that says "get the value at index 17 in the stack". If such an instruction did exist, it wouldn't be a stack machine. And there is no way to "free up some of the slots in the stack". You have to consume the stuff at the top, then the stuff further down. However Wasm has a concept of local variables, which do allow random access. See below. @@ -64,28 +63,80 @@ The Mono IR contains two functions, `Num.add` and `main`, so we generate two cor return) ; return the value at the top of the stack ``` -If we run this code through the `wasm-opt` tool from the [binaryen toolkit](https://github.com/WebAssembly/binaryen/wiki/Compiling-to-WebAssembly-with-Binaryen), all of the locals get optimised away. But this optimised version is harder to generate directly from the Mono IR. +If we run this code through the `wasm-opt` tool from the [binaryen toolkit](https://github.com/WebAssembly/binaryen#tools), all of the locals get optimised away. But this optimised version is harder to generate directly from the Mono IR. ``` - (func (;0;) (type 0) (param i64 i64) (result i64) + (func (;0;) (param i64 i64) (result i64) local.get 0 local.get 1 i64.add) ; return can be implicit, like in Rust. Only really needed from inside a branch. - (func (;1;) (type 1) (result i64) + (func (;1;) (result i64) i64.const 1 i64.const 2 - call 0 - i64.const 4 + call 0 ; the result of the first addition is at the top of the stack. No need to set a local and get it again. + i64.const 4 ; no need to store the constant to a local and get it again call 0) ``` +## Memory + +WebAssembly programs have a "linear memory" for storing data, which is a block of memory assigned to it by the host. You can assign a min and max size to the memory, and the WebAssembly program can request 64kB pages from the host, just like a "normal" program would request pages from the OS. Addresses start at zero and go up to whatever the current size is. Zero is a perfectly normal address like any other, and dereferencing it is not a segfault. But addresses beyond the current memory size are out of bounds and dereferencing them will cause a panic. + +The program has full read/write access to the memory and can divide it into whatever sections it wants. Most programs will want to do the traditional split of static memory, stack memory and heap memory. + +The WebAssembly module structure includes a data section that will be copied into the linear memory at a specified offset on initialisation, so you can use that for string literals etc. But the division of the rest of memory into "stack" and "heap" areas is not a first-class concept. It is up to the compiler to generate instructions to do whatever it wants with that memory. + ## Stack machine vs stack memory -TODO + +**There are two entirely different meanings of the word "stack" that are relevant to the WebAssembly backend.** It's unfortunate that the word "stack" is so overloaded. I guess it's just a useful data structure. The worst thing is that both of them tend to be referred to as just "the stack"! We need more precise terms. + +When we are talking about the instruction set, I'll use the term _machine stack_ or _VM stack_. This is the implicit data structure that WebAssembly instructions operate on. In the examples above, it's where `i64.add` gets its arguments and stores its result. I think of it as an abstraction over CPU registers, that WebAssembly uses in order to be portable and compact. + +When we are talking about how we store values in _memory_, I'll use the term _stack memory_ rather than just "the stack". It feels clunky but it's the best I can think of. + +Of course our program can use another area of memory as a heap as well. WebAssembly doesn't mind how you divide up your memory. It just gives you some memory and some instructions for loading and storing. + +## Function calls + +In WebAssembly you call a function by pushing arguments to the stack and then issuing a `call` instruction, which specifies a function index. The VM knows how many values to pop off the stack by examining the _type_ of the function. In our example earlier, `Num.add` had the type `[i64 i64] → [i64]` so it expects to find two i64's on the stack and pushes one i64 back as the result. Remember, the runtime engine will validate the module before running it, and if your generated code is trying to call a function at a point in the program where the wrong value types are on the stack, it will fail validation. + +Function arguments are restricted to the four value types, `i32`, `i64`, `f32` and `f64`. If those are all we need, then there is _no need for any stack memory_, stack pointer, etc. We saw this in our example earlier. We just said `call 0`. We didn't need any instructions to create a stack frame with a return address, and there was no "jump" instruction. Essentially, WebAssembly has a first-class concept of function calls, so you don't build it up from lower-level primitives. You could think of this as an abstraction over calling conventions. + +That's all great for primitive values but what happens when we want to pass more complex data structures between functions? + +Well, remember, "stack memory" is not a special kind of memory in WebAssembly, it's just an area of our memory where we _decide_ that we want to implement a stack data structure. So we can implement it however we want. A good choice would be to make our stack frame look the same as it would when we're targeting a CPU, except without the return address (since there's no need for one). We can also decide to pass numbers through the machine stack rather than in stack memory, since that takes fewer instructions. + +The only other thing we need is a stack pointer. On CPU targets, there's often have a specific "stack pointer" register. WebAssembly has no equivalent to that, but we can use a `global` variable. + +The system I've outlined above is based on my experience of compiling C to WebAssembly via the Emscripten toolchain (which is built on top of clang). It's also in line with what the WebAssembly project describes [here](https://github.com/WebAssembly/design/blob/main/Rationale.md#locals). ## Structured control flow -TODO -## Modules and objects +One of the security features of WebAssembly is that it does not allow unrestricted "jumps" to anywhere you like. It does not have an instruction for that. All of the [control instructions][control-inst] can only implement "structured" control flow, and have names like `if`, `loop`, `block` that you'd normally associate with high-level languages. There are branch (`br`) instructions that can jump to labelled blocks within the same function, but the blocks have to be nested in sensible ways. + +[control-inst]: https://webassembly.github.io/spec/core/syntax/instructions.html#control-instructions + +Implications: + +Roc, like most modern languages, is already enforcing structured control flow in the source program. Constructs from the Roc AST like `When`, `If` and `LetRec` all have corresponding Wasm constructs. + +However the Mono IR converts this to jumps and join points, which are more of a Control Flow Graph than a tree. That doesn't map so directly to the Wasm structures. This is such a common issue for compiler back-ends that the WebAssembly compiler toolkit `binaryen` has an algorithm to solve it, called the "[Relooper][relooper]". We're not using `binaryen` right now. It's a C++ library, though it does have a (very thin and somewhat hard-to-use) [Rust wrapper][binaryen-rs]. + +[relooper]: https://github.com/WebAssembly/binaryen/wiki/Compiling-to-WebAssembly-with-Binaryen#cfg-api +[binaryen-rs]: https://crates.io/crates/binaryen + +## Modules vs Instances + +What's the difference between a Module and an Instance in WebAssembly? + +Well, if I compare it to running a program on Linux, it's like the difference between an ELF binary and the executable image in memory that you get when you _load_ that ELF file. The ELF file is essentially a _specification_ for how to create the executable image. In order to start executing the program, the OS has to actually allocate a stack and a heap, and load the text and data. If you run multiple copies of the same program, they will each have their own memory and their own execution state. (More detail [here](https://wiki.osdev.org/ELF#Loading_ELF_Binaries)). + +The Module is like the ELF file, and the Instance is like the executable image. + +The Module is a _specification_ for how to create an Instance of the program. The Module says how much memory the program needs, but the Instance actually _contains_ that memory. In order to run the Wasm program, the VM needs to create an instance, allocate some memory for it, and copy the data section into that memory. If you run many copies of the same Wasm program, you will have one Module but many Instances. Each instance will have its own separate area of memory, and its own execution state. + +## Modules and object files + TODO https://webassembly.github.io/spec/core/binary/modules.html From ec9b60368fbf5faa88aa1feee4fe0109c9d68ce4 Mon Sep 17 00:00:00 2001 From: Brian Carroll Date: Mon, 6 Sep 2021 08:39:54 +0100 Subject: [PATCH 23/42] Add plan and linking info to readme, and highlight control flow stuff --- compiler/gen_wasm/README.md | 58 +++++++++++++++++++++++++------------ 1 file changed, 39 insertions(+), 19 deletions(-) diff --git a/compiler/gen_wasm/README.md b/compiler/gen_wasm/README.md index 3e379de8e6..2565b315b8 100644 --- a/compiler/gen_wasm/README.md +++ b/compiler/gen_wasm/README.md @@ -1,6 +1,39 @@ # Development backend for WebAssembly -This document offers a summary of how WebAssembly differs from other targets and how those differences matter for Roc. +## Plan + +- Initial bringup + - Get a wasm backend working for some of the number tests. + - Use a separate `gen_wasm` directory for now, to avoid trying to do bringup and integration at the same time. +- Integration + - Move wasm files to `gen_dev/src/wasm` + - Share tests between wasm and x64, with some way of saying which tests work on which backends, and dispatching to different eval helpers based on that. + - Get `build_module` in object_builder.rs to dispatch to the wasm generator (adding some Wasm options to the `Triple` struct) + - Get `build_module` to write to a file, or maybe return `Vec`, instead of returning an Object structure +- Code sharing + - Try to ensure that both Wasm and x64 use the same `Backend` trait so that we can share code. + - We need to work towards this after we've progressed a bit more with Wasm and gained more understanding and experience of the differences. + - We will have to think about how to deal with the `Backend` code that doesn't apply to Wasm. Perhaps we will end up with more traits like `RegisterBackend` / `StackBackend` or `NativeBackend` / `WasmBackend`, and perhaps even some traits to do with backends that support jumps and those that don't. + +## Structured control flow + +🚨 **This is an area that could be tricky** 🚨 + +One of the security features of WebAssembly is that it does not allow unrestricted "jumps" to anywhere you like. It does not have an instruction for that. All of the [control instructions][control-inst] can only implement "structured" control flow, and have names like `if`, `loop`, `block` that you'd normally associate with high-level languages. There are branch (`br`) instructions that can jump to labelled blocks within the same function, but the blocks have to be nested in sensible ways. + +[control-inst]: https://webassembly.github.io/spec/core/syntax/instructions.html#control-instructions + +Implications: + +Roc, like most modern languages, is already enforcing structured control flow in the source program. Constructs from the Roc AST like `When`, `If` and `LetRec` can all be converted straightforwardly to Wasm constructs. + +However the Mono IR converts this to jumps and join points, which are more of a Control Flow Graph than a tree. That doesn't map so directly to the Wasm structures. This is such a common issue for compiler back-ends that the WebAssembly compiler toolkit `binaryen` has an algorithm to solve it, called the "[Relooper][relooper]". We're not using `binaryen` right now. It's a C++ library, though it does have a (very thin and somewhat hard-to-use) [Rust wrapper][binaryen-rs]. We should probably investigate this area sooner rather than later. If relooping turns out to be necessary or difficult, we might need to switch from parity_wasm to binaryen. + +> By the way, it's not obvious how to pronounce "binaryen" but apparently it rhymes with "Targaryen", the family name from Game of Thrones + +[relooper]: https://github.com/WebAssembly/binaryen/wiki/Compiling-to-WebAssembly-with-Binaryen#cfg-api +[binaryen-rs]: https://crates.io/crates/binaryen + ## Stack machine vs register machine @@ -110,21 +143,6 @@ The only other thing we need is a stack pointer. On CPU targets, there's often h The system I've outlined above is based on my experience of compiling C to WebAssembly via the Emscripten toolchain (which is built on top of clang). It's also in line with what the WebAssembly project describes [here](https://github.com/WebAssembly/design/blob/main/Rationale.md#locals). -## Structured control flow - -One of the security features of WebAssembly is that it does not allow unrestricted "jumps" to anywhere you like. It does not have an instruction for that. All of the [control instructions][control-inst] can only implement "structured" control flow, and have names like `if`, `loop`, `block` that you'd normally associate with high-level languages. There are branch (`br`) instructions that can jump to labelled blocks within the same function, but the blocks have to be nested in sensible ways. - -[control-inst]: https://webassembly.github.io/spec/core/syntax/instructions.html#control-instructions - -Implications: - -Roc, like most modern languages, is already enforcing structured control flow in the source program. Constructs from the Roc AST like `When`, `If` and `LetRec` all have corresponding Wasm constructs. - -However the Mono IR converts this to jumps and join points, which are more of a Control Flow Graph than a tree. That doesn't map so directly to the Wasm structures. This is such a common issue for compiler back-ends that the WebAssembly compiler toolkit `binaryen` has an algorithm to solve it, called the "[Relooper][relooper]". We're not using `binaryen` right now. It's a C++ library, though it does have a (very thin and somewhat hard-to-use) [Rust wrapper][binaryen-rs]. - -[relooper]: https://github.com/WebAssembly/binaryen/wiki/Compiling-to-WebAssembly-with-Binaryen#cfg-api -[binaryen-rs]: https://crates.io/crates/binaryen - ## Modules vs Instances What's the difference between a Module and an Instance in WebAssembly? @@ -135,8 +153,10 @@ The Module is like the ELF file, and the Instance is like the executable image. The Module is a _specification_ for how to create an Instance of the program. The Module says how much memory the program needs, but the Instance actually _contains_ that memory. In order to run the Wasm program, the VM needs to create an instance, allocate some memory for it, and copy the data section into that memory. If you run many copies of the same Wasm program, you will have one Module but many Instances. Each instance will have its own separate area of memory, and its own execution state. -## Modules and object files +## Modules, object files, and linking -TODO +A WebAssembly module is equivalent to an executable file. It doesn't normally need relocations since at the WebAssembly layer, there is no Address Space Layout Randomisation. If it has relocations then it's an object file. -https://webassembly.github.io/spec/core/binary/modules.html +The [official spec](https://webassembly.github.io/spec/core/binary/modules.html#sections) lists the sections that are part of the final module. It doesn't mention any sections for relocations or symbol names, but it has room for "custom sections" that in practice seem to be used for that. + +The WebAssembly `tool-conventions` repo has a document on [linking](https://github.com/WebAssembly/tool-conventions/blob/main/Linking.md), and the `parity_wasm` crate supports "name" and "relocation" [sections](https://docs.rs/parity-wasm/0.42.2/parity_wasm/elements/enum.Section.html). From 889abaa3b4c91ab875300a79d03341bd210afe92 Mon Sep 17 00:00:00 2001 From: Folkert Date: Mon, 6 Sep 2021 22:23:14 +0200 Subject: [PATCH 24/42] cargo lock --- Cargo.lock | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 3cf44245dc..b53b0d9b05 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1829,13 +1829,13 @@ dependencies = [ name = "inkwell" version = "0.1.0" dependencies = [ - "inkwell 0.1.0 (git+https://github.com/rtfeldman/inkwell?tag=llvm12-0.release6)", + "inkwell 0.1.0 (git+https://github.com/rtfeldman/inkwell?tag=llvm12-0.release8)", ] [[package]] name = "inkwell" version = "0.1.0" -source = "git+https://github.com/rtfeldman/inkwell?tag=llvm12-0.release6#b1b464aabaf259b42a88d8c7506619b9d9b56510" +source = "git+https://github.com/rtfeldman/inkwell?tag=llvm12-0.release8#14b78d96d2dbc95694e181be66e4cd53df3fc02f" dependencies = [ "either", "inkwell_internals", @@ -1849,7 +1849,7 @@ dependencies = [ [[package]] name = "inkwell_internals" version = "0.3.0" -source = "git+https://github.com/rtfeldman/inkwell?tag=llvm12-0.release6#b1b464aabaf259b42a88d8c7506619b9d9b56510" +source = "git+https://github.com/rtfeldman/inkwell?tag=llvm12-0.release8#14b78d96d2dbc95694e181be66e4cd53df3fc02f" dependencies = [ "proc-macro2 1.0.27", "quote 1.0.9", @@ -2034,9 +2034,9 @@ checksum = "7fb9b38af92608140b86b693604b9ffcc5824240a484d1ecd4795bacb2fe88f3" [[package]] name = "llvm-sys" -version = "120.2.0" +version = "120.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7cd0739fb23e5d801f6ff11a9d587448bdd86dea2459ba2b57fbed90a9ae1b5a" +checksum = "b4a810627ac62b396f5fd2214ba9bbd8748d4d6efdc4d2c1c1303ea7a75763ce" dependencies = [ "cc", "lazy_static", From 3fb6736f7c328f94dc7bf20f1caa520ec0792230 Mon Sep 17 00:00:00 2001 From: Folkert Date: Mon, 6 Sep 2021 22:23:23 +0200 Subject: [PATCH 25/42] clarify comment --- compiler/gen_llvm/src/llvm/build.rs | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/compiler/gen_llvm/src/llvm/build.rs b/compiler/gen_llvm/src/llvm/build.rs index ebf0ecbc29..b8c9b922e8 100644 --- a/compiler/gen_llvm/src/llvm/build.rs +++ b/compiler/gen_llvm/src/llvm/build.rs @@ -2189,8 +2189,15 @@ fn list_literal<'a, 'ctx, 'env>( let global = { let mut global_elements = Vec::with_capacity_in(list_length, env.arena); - // insert NULL bytes for the refcount - // these elements are (dropped again if the list contains non-constants) + // Add zero bytes that represent the refcount + // + // - if all elements are const, then we store the whole list as a constant. + // It then needs a refcount before the first element. + // - but if the list is not all constants, then we will just copy the constant values, + // and we do not need that refcount at the start + // + // In the latter case, we won't store the zeros in the globals + // (we slice them off again below) for _ in 0..zero_elements { global_elements.push(element_type.const_zero()); } From ea9b23cda88e67cd658136d77e205e019bdac115 Mon Sep 17 00:00:00 2001 From: Folkert Date: Mon, 6 Sep 2021 22:25:35 +0200 Subject: [PATCH 26/42] start using zig9 as the name for trunk zig --- compiler/build/src/link.rs | 43 +++++++++++++-------------- compiler/test_gen/src/helpers/eval.rs | 2 +- 2 files changed, 22 insertions(+), 23 deletions(-) diff --git a/compiler/build/src/link.rs b/compiler/build/src/link.rs index 86a5d5df4d..0be0ac00d6 100644 --- a/compiler/build/src/link.rs +++ b/compiler/build/src/link.rs @@ -606,28 +606,27 @@ fn link_wasm32( ) -> io::Result<(Child, PathBuf)> { let zig_str_path = find_zig_str_path(); - let child = - Command::new("/home/folkertdev/Downloads/zig-linux-x86_64-0.9.0-dev.848+d5ef5da59/zig") - // .env_clear() - // .env("PATH", &env_path) - .args(&["build-exe"]) - .args(input_paths) - .args([ - &format!("-femit-bin={}", output_path.to_str().unwrap()), - // include libc - "-lc", - "-target", - "wasm32-wasi-musl", - "--pkg-begin", - "str", - zig_str_path.to_str().unwrap(), - "--pkg-end", - "--strip", - // "-O", "ReleaseSmall", - // useful for debugging - // "-femit-llvm-ir=/home/folkertdev/roc/roc/examples/benchmarks/platform/host.ll", - ]) - .spawn()?; + let child = Command::new("zig9") + // .env_clear() + // .env("PATH", &env_path) + .args(&["build-exe"]) + .args(input_paths) + .args([ + &format!("-femit-bin={}", output_path.to_str().unwrap()), + // include libc + "-lc", + "-target", + "wasm32-wasi-musl", + "--pkg-begin", + "str", + zig_str_path.to_str().unwrap(), + "--pkg-end", + "--strip", + // "-O", "ReleaseSmall", + // useful for debugging + // "-femit-llvm-ir=/home/folkertdev/roc/roc/examples/benchmarks/platform/host.ll", + ]) + .spawn()?; Ok((child, output_path)) } diff --git a/compiler/test_gen/src/helpers/eval.rs b/compiler/test_gen/src/helpers/eval.rs index 10c770a3d7..dc4c377c84 100644 --- a/compiler/test_gen/src/helpers/eval.rs +++ b/compiler/test_gen/src/helpers/eval.rs @@ -366,7 +366,7 @@ pub fn helper_wasm<'a>( use std::process::Command; - Command::new("/home/folkertdev/Downloads/zig-linux-x86_64-0.9.0-dev.848+d5ef5da59/zig") + Command::new("zig9") .current_dir(dir_path) .args(&[ "wasm-ld", From e90588d1565fb57cfb2594e3fa9c313575ab8edc Mon Sep 17 00:00:00 2001 From: Brian Carroll Date: Mon, 6 Sep 2021 22:39:29 +0100 Subject: [PATCH 27/42] Notes on control flow, binaryen, and optimisation --- compiler/gen_wasm/README.md | 24 ++++++++++++++++-------- 1 file changed, 16 insertions(+), 8 deletions(-) diff --git a/compiler/gen_wasm/README.md b/compiler/gen_wasm/README.md index 2565b315b8..68cb38474c 100644 --- a/compiler/gen_wasm/README.md +++ b/compiler/gen_wasm/README.md @@ -27,13 +27,17 @@ Implications: Roc, like most modern languages, is already enforcing structured control flow in the source program. Constructs from the Roc AST like `When`, `If` and `LetRec` can all be converted straightforwardly to Wasm constructs. -However the Mono IR converts this to jumps and join points, which are more of a Control Flow Graph than a tree. That doesn't map so directly to the Wasm structures. This is such a common issue for compiler back-ends that the WebAssembly compiler toolkit `binaryen` has an algorithm to solve it, called the "[Relooper][relooper]". We're not using `binaryen` right now. It's a C++ library, though it does have a (very thin and somewhat hard-to-use) [Rust wrapper][binaryen-rs]. We should probably investigate this area sooner rather than later. If relooping turns out to be necessary or difficult, we might need to switch from parity_wasm to binaryen. +However the Mono IR converts this to jumps and join points, which are more of a Control Flow Graph than a tree. That doesn't map so directly to the Wasm structures. This is such a common issue for compiler back-ends that the WebAssembly compiler toolkit `binaryen` has an [API for control-flow graphs][cfg-api]. We're not using `binaryen` right now. It's a C++ library, though it does have a (very thin and somewhat hard-to-use) [Rust wrapper][binaryen-rs]. We should probably investigate this area sooner rather than later. If relooping turns out to be necessary or difficult, we might need to switch from parity_wasm to binaryen. -> By the way, it's not obvious how to pronounce "binaryen" but apparently it rhymes with "Targaryen", the family name from Game of Thrones +> By the way, it's not obvious how to pronounce "binaryen" but apparently it rhymes with "Targaryen", the family name from the "Game of Thrones" TV series -[relooper]: https://github.com/WebAssembly/binaryen/wiki/Compiling-to-WebAssembly-with-Binaryen#cfg-api +[cfg-api]: https://github.com/WebAssembly/binaryen/wiki/Compiling-to-WebAssembly-with-Binaryen#cfg-api [binaryen-rs]: https://crates.io/crates/binaryen +Binaryen's control-flow graph API implements the "Relooper" algorithm developed by the Emscripten project and decribed in [this paper](https://github.com/emscripten-core/emscripten/blob/main/docs/paper.pdf). + +There is an alternative algorithm that is supposed to be an improvement on Relooper, called ["Stackifier"](https://medium.com/leaningtech/solving-the-structured-control-flow-problem-once-and-for-all-5123117b1ee2). + ## Stack machine vs register machine @@ -96,19 +100,23 @@ The Mono IR contains two functions, `Num.add` and `main`, so we generate two cor return) ; return the value at the top of the stack ``` -If we run this code through the `wasm-opt` tool from the [binaryen toolkit](https://github.com/WebAssembly/binaryen#tools), all of the locals get optimised away. But this optimised version is harder to generate directly from the Mono IR. +If we run this code through the `wasm-opt` tool from the [binaryen toolkit](https://github.com/WebAssembly/binaryen#tools), the unnecessary locals get optimised away. The command line below runs the minimum number of passes to achieve this (`--simplify-locals` must come first). +``` +$ wasm-opt --simplify-locals --reorder-locals --vacuum example.wasm > opt.wasm +``` + +The optimised functions have no local variables, and the code shrinks to about 60% of its original size. ``` (func (;0;) (param i64 i64) (result i64) local.get 0 local.get 1 - i64.add) ; return can be implicit, like in Rust. Only really needed from inside a branch. + i64.add) (func (;1;) (result i64) i64.const 1 i64.const 2 - call 0 ; the result of the first addition is at the top of the stack. No need to set a local and get it again. - i64.const 4 ; no need to store the constant to a local and get it again - call 0) + call 0 + i64.const 4) ``` ## Memory From ba0826cbfd8046a12f1695d3a9aa1ff2d9d016f6 Mon Sep 17 00:00:00 2001 From: Brian Carroll Date: Tue, 7 Sep 2021 08:03:41 +0100 Subject: [PATCH 28/42] First three tests passing with Wasm dev backend! Only i64 values. Next step is generalising to all types. --- .../tests/helpers/{eval.rs => eval_full.rs} | 14 +- .../gen_wasm/tests/helpers/eval_simple.rs | 197 +++++++++ compiler/gen_wasm/tests/helpers/mod.rs | 2 +- compiler/gen_wasm/tests/wasm_num.rs | 374 +++++++++--------- 4 files changed, 392 insertions(+), 195 deletions(-) rename compiler/gen_wasm/tests/helpers/{eval.rs => eval_full.rs} (97%) create mode 100644 compiler/gen_wasm/tests/helpers/eval_simple.rs diff --git a/compiler/gen_wasm/tests/helpers/eval.rs b/compiler/gen_wasm/tests/helpers/eval_full.rs similarity index 97% rename from compiler/gen_wasm/tests/helpers/eval.rs rename to compiler/gen_wasm/tests/helpers/eval_full.rs index 8a5408e53c..065fe0d05b 100644 --- a/compiler/gen_wasm/tests/helpers/eval.rs +++ b/compiler/gen_wasm/tests/helpers/eval_full.rs @@ -94,7 +94,7 @@ pub fn helper_wasm<'a>( let module_bytes = gen_wasm::build_module(&env, procedures).unwrap(); // for debugging (e.g. with wasm2wat) - if false { + if true { use std::io::Write; let mut file = std::fs::File::create("/home/brian/Documents/roc/compiler/gen_wasm/debug.wasm").unwrap(); @@ -188,11 +188,11 @@ where let is_gen_test = true; let instance = - crate::helpers::eval::helper_wasm(&arena, src, stdlib, is_gen_test, ignore_problems); + crate::helpers::eval_full::helper_wasm(&arena, src, stdlib, is_gen_test, ignore_problems); let memory = instance.exports.get_memory("memory").unwrap(); - crate::helpers::eval::MEMORY.with(|f| { + crate::helpers::eval_full::MEMORY.with(|f| { *f.borrow_mut() = Some(unsafe { std::mem::transmute(memory) }); }); @@ -206,7 +206,7 @@ where _ => panic!(), }; - let output = ::decode( + let output = ::decode( memory, // skip the RocCallResult tag id address as u32 + 8, @@ -220,7 +220,7 @@ where #[macro_export] macro_rules! assert_wasm_evals_to { ($src:expr, $expected:expr, $ty:ty, $transform:expr, $ignore_problems:expr) => { - match $crate::helpers::eval::assert_wasm_evals_to_help::<$ty>($src, $ignore_problems) { + match $crate::helpers::eval_full::assert_wasm_evals_to_help::<$ty>($src, $ignore_problems) { Err(msg) => println!("{:?}", msg), Ok(actual) => { #[allow(clippy::bool_assert_comparison)] @@ -230,7 +230,7 @@ macro_rules! assert_wasm_evals_to { }; ($src:expr, $expected:expr, $ty:ty) => { - $crate::assert_wasm_evals_to!($src, $expected, $ty, $crate::helpers::eval::identity, false); + $crate::assert_wasm_evals_to!($src, $expected, $ty, $crate::helpers::eval_full::identity, false); }; ($src:expr, $expected:expr, $ty:ty, $transform:expr) => { @@ -241,7 +241,7 @@ macro_rules! assert_wasm_evals_to { #[macro_export] macro_rules! assert_evals_to { ($src:expr, $expected:expr, $ty:ty) => {{ - assert_evals_to!($src, $expected, $ty, $crate::helpers::eval::identity); + assert_evals_to!($src, $expected, $ty, $crate::helpers::eval_full::identity); }}; ($src:expr, $expected:expr, $ty:ty, $transform:expr) => { // Same as above, except with an additional transformation argument. diff --git a/compiler/gen_wasm/tests/helpers/eval_simple.rs b/compiler/gen_wasm/tests/helpers/eval_simple.rs new file mode 100644 index 0000000000..172217acb4 --- /dev/null +++ b/compiler/gen_wasm/tests/helpers/eval_simple.rs @@ -0,0 +1,197 @@ +use roc_can::builtins::builtin_defs_map; +use roc_collections::all::{MutMap, MutSet}; +// use roc_std::{RocDec, RocList, RocOrder, RocStr}; + +fn promote_expr_to_module(src: &str) -> String { + let mut buffer = String::from("app \"test\" provides [ main ] to \"./platform\"\n\nmain =\n"); + + for line in src.lines() { + // indent the body! + buffer.push_str(" "); + buffer.push_str(line); + buffer.push('\n'); + } + + buffer +} + +#[allow(dead_code)] +pub fn helper_wasm<'a>( + arena: &'a bumpalo::Bump, + src: &str, + stdlib: &'a roc_builtins::std::StdLib, + _is_gen_test: bool, + _ignore_problems: bool, +) -> wasmer::Instance { + use std::path::{Path, PathBuf}; + + let filename = PathBuf::from("Test.roc"); + let src_dir = Path::new("fake/test/path"); + + let module_src; + let temp; + if src.starts_with("app") { + // this is already a module + module_src = src; + } else { + // this is an expression, promote it to a module + temp = promote_expr_to_module(src); + module_src = &temp; + } + + let exposed_types = MutMap::default(); + let loaded = roc_load::file::load_and_monomorphize_from_str( + arena, + filename, + module_src, + stdlib, + src_dir, + exposed_types, + 8, + builtin_defs_map, + ); + + let loaded = loaded.expect("failed to load module"); + + use roc_load::file::MonomorphizedModule; + let MonomorphizedModule { + procedures: top_procedures, + interns, + exposed_to_host, + .. + } = loaded; + + let mut procedures = MutMap::default(); + + for (key, proc) in top_procedures { + procedures.insert(key, proc); + } + + // You can comment and uncomment this block out to get more useful information + // while you're working on the wasm backend! + // { + // println!("=========== Procedures =========="); + // println!("{:?}", procedures); + // println!("=================================\n"); + + // println!("=========== Interns =========="); + // println!("{:?}", interns); + // println!("=================================\n"); + + // println!("=========== Exposed =========="); + // println!("{:?}", exposed_to_host); + // println!("=================================\n"); + // } + + let exposed_to_host = exposed_to_host.keys().copied().collect::>(); + + let env = gen_wasm::Env { + arena, + interns, + exposed_to_host, + }; + + let module_bytes = gen_wasm::build_module(&env, procedures).unwrap(); + + // for debugging (e.g. with wasm2wat) + if true { + use std::io::Write; + let mut file = + std::fs::File::create("/home/brian/Documents/roc/compiler/gen_wasm/debug.wasm").unwrap(); + file.write_all(&module_bytes).unwrap(); + } + + // now, do wasmer stuff + + use wasmer::{Instance, Module, Store}; + + let store = Store::default(); + // let module = Module::from_file(&store, &test_wasm_path).unwrap(); + let module = Module::from_binary(&store, &module_bytes).unwrap(); + + // First, we create the `WasiEnv` + use wasmer_wasi::WasiState; + let mut wasi_env = WasiState::new("hello") + .finalize() + .unwrap(); + + // Then, we get the import object related to our WASI + // and attach it to the Wasm instance. + let import_object = wasi_env + .import_object(&module) + .unwrap_or_else(|_| wasmer::imports!()); + + Instance::new(&module, &import_object).unwrap() +} + +#[allow(dead_code)] +pub fn assert_wasm_evals_to_help(src: &str, ignore_problems: bool) -> Result +where T: Copy +{ + let arena = bumpalo::Bump::new(); + + // NOTE the stdlib must be in the arena; just taking a reference will segfault + let stdlib = arena.alloc(roc_builtins::std::standard_stdlib()); + + let is_gen_test = true; + let instance = + crate::helpers::eval_simple::helper_wasm(&arena, src, stdlib, is_gen_test, ignore_problems); + + let main_function = instance.exports.get_function("#UserApp_main_1").unwrap(); + + match main_function.call(&[]) { + Err(e) => Err(format!("{:?}", e)), + Ok(result) => { + let integer = match result[0] { + wasmer::Value::I64(a) => a, + _ => panic!(), + }; + + let output_ptr: &T; + unsafe { + output_ptr = std::mem::transmute::<&i64, &T>(&integer); + } + + Ok(*output_ptr) + } + } +} + +#[macro_export] +macro_rules! assert_wasm_evals_to { + ($src:expr, $expected:expr, $ty:ty, $transform:expr, $ignore_problems:expr) => { + match $crate::helpers::eval_simple::assert_wasm_evals_to_help::<$ty>($src, $ignore_problems) { + Err(msg) => println!("{:?}", msg), + Ok(actual) => { + #[allow(clippy::bool_assert_comparison)] + assert_eq!($transform(actual), $expected) + } + } + }; + + ($src:expr, $expected:expr, $ty:ty) => { + $crate::assert_wasm_evals_to!($src, $expected, $ty, $crate::helpers::eval_simple::identity, false); + }; + + ($src:expr, $expected:expr, $ty:ty, $transform:expr) => { + $crate::assert_wasm_evals_to!($src, $expected, $ty, $transform, false); + }; +} + +#[macro_export] +macro_rules! assert_evals_to { + ($src:expr, $expected:expr, $ty:ty) => {{ + assert_evals_to!($src, $expected, $ty, $crate::helpers::eval_simple::identity); + }}; + ($src:expr, $expected:expr, $ty:ty, $transform:expr) => { + // Same as above, except with an additional transformation argument. + { + $crate::assert_wasm_evals_to!($src, $expected, $ty, $transform, false); + } + }; +} + +#[allow(dead_code)] +pub fn identity(value: T) -> T { + value +} diff --git a/compiler/gen_wasm/tests/helpers/mod.rs b/compiler/gen_wasm/tests/helpers/mod.rs index 7e538193f7..4d22ed81a3 100644 --- a/compiler/gen_wasm/tests/helpers/mod.rs +++ b/compiler/gen_wasm/tests/helpers/mod.rs @@ -1,7 +1,7 @@ extern crate bumpalo; #[macro_use] -pub mod eval; +pub mod eval_simple; /// Used in the with_larger_debug_stack() function, for tests that otherwise /// run out of stack space in debug builds (but don't in --release builds) diff --git a/compiler/gen_wasm/tests/wasm_num.rs b/compiler/gen_wasm/tests/wasm_num.rs index d1c0ae0d75..f09299198d 100644 --- a/compiler/gen_wasm/tests/wasm_num.rs +++ b/compiler/gen_wasm/tests/wasm_num.rs @@ -25,16 +25,16 @@ mod dev_num { assert_evals_to!("0x1000_0000_0000_0000", 0x1000_0000_0000_0000, i64); } - #[test] - fn f64_values() { - assert_evals_to!("0.0", 0.0, f64); - assert_evals_to!("-0.0", 0.0, f64); - assert_evals_to!("1.0", 1.0, f64); - assert_evals_to!("-1.0", -1.0, f64); - assert_evals_to!("3.1415926535897932", 3.141_592_653_589_793, f64); - assert_evals_to!(&format!("{:0.1}", f64::MIN), f64::MIN, f64); - assert_evals_to!(&format!("{:0.1}", f64::MAX), f64::MAX, f64); - } + // #[test] + // fn f64_values() { + // assert_evals_to!("0.0", 0.0, f64); + // assert_evals_to!("-0.0", 0.0, f64); + // assert_evals_to!("1.0", 1.0, f64); + // assert_evals_to!("-1.0", -1.0, f64); + // assert_evals_to!("3.1415926535897932", 3.141_592_653_589_793, f64); + // assert_evals_to!(&format!("{:0.1}", f64::MIN), f64::MIN, f64); + // assert_evals_to!(&format!("{:0.1}", f64::MAX), f64::MAX, f64); + // } #[test] fn gen_add_i64() { @@ -49,44 +49,44 @@ mod dev_num { ); } - #[test] - fn gen_add_f64() { - assert_evals_to!( - indoc!( - r#" - 1.1 + 2.4 + 3 - "# - ), - 6.5, - f64 - ); - } + // #[test] + // fn gen_add_f64() { + // assert_evals_to!( + // indoc!( + // r#" + // 1.1 + 2.4 + 3 + // "# + // ), + // 6.5, + // f64 + // ); + // } - #[test] - fn gen_sub_i64() { - assert_evals_to!( - indoc!( - r#" - 1 - 2 - 3 - "# - ), - -4, - i64 - ); - } + // #[test] + // fn gen_sub_i64() { + // assert_evals_to!( + // indoc!( + // r#" + // 1 - 2 - 3 + // "# + // ), + // -4, + // i64 + // ); + // } - #[test] - fn gen_mul_i64() { - assert_evals_to!( - indoc!( - r#" - 2 * 4 * 6 - "# - ), - 48, - i64 - ); - } + // #[test] + // fn gen_mul_i64() { + // assert_evals_to!( + // indoc!( + // r#" + // 2 * 4 * 6 + // "# + // ), + // 48, + // i64 + // ); + // } #[test] fn i64_force_stack() { @@ -136,165 +136,165 @@ mod dev_num { ); } - #[test] - fn i64_abs() { - assert_evals_to!("Num.abs -6", 6, i64); - assert_evals_to!("Num.abs 7", 7, i64); - assert_evals_to!("Num.abs 0", 0, i64); - assert_evals_to!("Num.abs -0", 0, i64); - assert_evals_to!("Num.abs -1", 1, i64); - assert_evals_to!("Num.abs 1", 1, i64); - assert_evals_to!("Num.abs 9_000_000_000_000", 9_000_000_000_000, i64); - assert_evals_to!("Num.abs -9_000_000_000_000", 9_000_000_000_000, i64); - } + // #[test] + // fn i64_abs() { + // assert_evals_to!("Num.abs -6", 6, i64); + // assert_evals_to!("Num.abs 7", 7, i64); + // assert_evals_to!("Num.abs 0", 0, i64); + // assert_evals_to!("Num.abs -0", 0, i64); + // assert_evals_to!("Num.abs -1", 1, i64); + // assert_evals_to!("Num.abs 1", 1, i64); + // assert_evals_to!("Num.abs 9_000_000_000_000", 9_000_000_000_000, i64); + // assert_evals_to!("Num.abs -9_000_000_000_000", 9_000_000_000_000, i64); + // } - #[test] - fn gen_int_eq() { - assert_evals_to!( - indoc!( - r#" - 4 == 4 - "# - ), - true, - bool - ); + // #[test] + // fn gen_int_eq() { + // assert_evals_to!( + // indoc!( + // r#" + // 4 == 4 + // "# + // ), + // true, + // bool + // ); - assert_evals_to!( - indoc!( - r#" - 3 == 4 - "# - ), - false, - bool - ); - } + // assert_evals_to!( + // indoc!( + // r#" + // 3 == 4 + // "# + // ), + // false, + // bool + // ); + // } - #[test] - fn gen_basic_fn() { - assert_evals_to!( - indoc!( - r#" - always42 : Num.Num (Num.Integer Num.Signed64) -> Num.Num (Num.Integer Num.Signed64) - always42 = \_ -> 42 + // #[test] + // fn gen_basic_fn() { + // assert_evals_to!( + // indoc!( + // r#" + // always42 : Num.Num (Num.Integer Num.Signed64) -> Num.Num (Num.Integer Num.Signed64) + // always42 = \_ -> 42 - always42 5 - "# - ), - 42, - i64 - ); - } + // always42 5 + // "# + // ), + // 42, + // i64 + // ); + // } - #[test] - fn gen_wrap_add_nums() { - assert_evals_to!( - indoc!( - r#" - add2 = \num1, num2 -> num1 + num2 + // #[test] + // fn gen_wrap_add_nums() { + // assert_evals_to!( + // indoc!( + // r#" + // add2 = \num1, num2 -> num1 + num2 - add2 4 5 - "# - ), - 9, - i64 - ); - } + // add2 4 5 + // "# + // ), + // 9, + // i64 + // ); + // } - #[test] - fn gen_wrap_add_nums_force_stack() { - assert_evals_to!( - indoc!( - r#" - add9 = \num1, num2, num3, num4, num5, num6, num7, num8, num9 -> num1 + num2 + num3 + num4 + num5 + num6 + num7 + num8 + num9 + // #[test] + // fn gen_wrap_add_nums_force_stack() { + // assert_evals_to!( + // indoc!( + // r#" + // add9 = \num1, num2, num3, num4, num5, num6, num7, num8, num9 -> num1 + num2 + num3 + num4 + num5 + num6 + num7 + num8 + num9 - add9 1 2 3 4 5 6 7 8 9 - "# - ), - 45, - i64 - ); - } + // add9 1 2 3 4 5 6 7 8 9 + // "# + // ), + // 45, + // i64 + // ); + // } - #[test] - fn pow_int() { - assert_evals_to!("Num.powInt 2 3", 8, i64); - } + // #[test] + // fn pow_int() { + // assert_evals_to!("Num.powInt 2 3", 8, i64); + // } - #[test] - fn acos() { - assert_evals_to!("Num.acos 0.5", 1.0471975511965979, f64); - } + // #[test] + // fn acos() { + // assert_evals_to!("Num.acos 0.5", 1.0471975511965979, f64); + // } - #[test] - fn asin() { - assert_evals_to!("Num.asin 0.5", 0.5235987755982989, f64); - } + // #[test] + // fn asin() { + // assert_evals_to!("Num.asin 0.5", 0.5235987755982989, f64); + // } - #[test] - fn atan() { - assert_evals_to!("Num.atan 10", 1.4711276743037347, f64); - } + // #[test] + // fn atan() { + // assert_evals_to!("Num.atan 10", 1.4711276743037347, f64); + // } - #[test] - fn gen_if_fn() { - assert_evals_to!( - indoc!( - r#" - limitedNegate = \num -> - x = - if num == 1 then - -1 - else if num == -1 then - 1 - else - num - x + // #[test] + // fn gen_if_fn() { + // assert_evals_to!( + // indoc!( + // r#" + // limitedNegate = \num -> + // x = + // if num == 1 then + // -1 + // else if num == -1 then + // 1 + // else + // num + // x - limitedNegate 1 - "# - ), - -1, - i64 - ); - } + // limitedNegate 1 + // "# + // ), + // -1, + // i64 + // ); + // } - #[test] - fn gen_fib_fn() { - assert_evals_to!( - indoc!( - r#" - fib = \n -> - if n == 0 then - 0 - else if n == 1 then - 1 - else - (fib (n - 1)) + (fib (n - 2)) + // #[test] + // fn gen_fib_fn() { + // assert_evals_to!( + // indoc!( + // r#" + // fib = \n -> + // if n == 0 then + // 0 + // else if n == 1 then + // 1 + // else + // (fib (n - 1)) + (fib (n - 2)) - fib 10 - "# - ), - 55, - i64 - ); - } + // fib 10 + // "# + // ), + // 55, + // i64 + // ); + // } - #[test] - fn f64_abs() { - assert_evals_to!("Num.abs -4.7", 4.7, f64); - assert_evals_to!("Num.abs 5.8", 5.8, f64); - } + // #[test] + // fn f64_abs() { + // assert_evals_to!("Num.abs -4.7", 4.7, f64); + // assert_evals_to!("Num.abs 5.8", 5.8, f64); + // } - #[test] - fn f64_round() { - assert_evals_to!("Num.round 3.6", 4, i64); - assert_evals_to!("Num.round 3.4", 3, i64); - assert_evals_to!("Num.round 2.5", 3, i64); - assert_evals_to!("Num.round -2.3", -2, i64); - assert_evals_to!("Num.round -2.5", -3, i64); - } + // #[test] + // fn f64_round() { + // assert_evals_to!("Num.round 3.6", 4, i64); + // assert_evals_to!("Num.round 3.4", 3, i64); + // assert_evals_to!("Num.round 2.5", 3, i64); + // assert_evals_to!("Num.round -2.3", -2, i64); + // assert_evals_to!("Num.round -2.5", -3, i64); + // } // #[test] // fn f64_sqrt() { From edf39be4c9de0bf8459e6164bf777258f0745080 Mon Sep 17 00:00:00 2001 From: Brian Carroll Date: Tue, 7 Sep 2021 09:02:17 +0100 Subject: [PATCH 29/42] Prepare to pull from trunk --- Cargo.lock | 46 ++-- compiler/gen_wasm/Cargo.toml | 9 +- compiler/gen_wasm/src/from_wasm32_memory.rs | 210 ++++++++++++++++ compiler/gen_wasm/src/lib.rs | 1 + compiler/gen_wasm/tests/helpers/eval_full.rs | 232 +----------------- .../gen_wasm/tests/helpers/eval_simple.rs | 6 +- 6 files changed, 244 insertions(+), 260 deletions(-) create mode 100644 compiler/gen_wasm/src/from_wasm32_memory.rs diff --git a/Cargo.lock b/Cargo.lock index d2d122f76c..589e1d4428 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1340,29 +1340,6 @@ dependencies = [ "byteorder", ] -[[package]] -name = "gen_wasm" -version = "0.1.0" -dependencies = [ - "bumpalo", - "indoc 0.3.6", - "libc", - "parity-wasm", - "pretty_assertions 0.5.1", - "roc_builtins", - "roc_can", - "roc_collections", - "roc_load", - "roc_module", - "roc_mono", - "roc_std", - "roc_types", - "target-lexicon", - "tempfile", - "wasmer", - "wasmer-wasi", -] - [[package]] name = "generational-arena" version = "0.2.8" @@ -3672,6 +3649,29 @@ dependencies = [ "tokio", ] +[[package]] +name = "roc_gen_wasm" +version = "0.1.0" +dependencies = [ + "bumpalo", + "indoc 0.3.6", + "libc", + "parity-wasm", + "pretty_assertions 0.5.1", + "roc_builtins", + "roc_can", + "roc_collections", + "roc_load", + "roc_module", + "roc_mono", + "roc_std", + "roc_types", + "target-lexicon", + "tempfile", + "wasmer", + "wasmer-wasi", +] + [[package]] name = "roc_ident" version = "0.1.0" diff --git a/compiler/gen_wasm/Cargo.toml b/compiler/gen_wasm/Cargo.toml index 14e2be583d..2804be6eab 100644 --- a/compiler/gen_wasm/Cargo.toml +++ b/compiler/gen_wasm/Cargo.toml @@ -1,5 +1,5 @@ [package] -name = "gen_wasm" +name = "roc_gen_wasm" version = "0.1.0" edition = "2018" @@ -12,17 +12,18 @@ roc_mono = { path = "../mono" } bumpalo = { version = "3.6.1", features = ["collections"] } parity-wasm = "0.42" +roc_std = { path = "../../roc_std" } +wasmer = "2.0.0" +wasmer-wasi = "2.0.0" + [dev-dependencies] roc_can = { path = "../can" } roc_builtins = { path = "../builtins" } roc_load = { path = "../load" } roc_types = { path = "../types" } -roc_std = { path = "../../roc_std" } roc_module = { path = "../module" } indoc = "0.3.3" pretty_assertions = "0.5.1" libc = "0.2" target-lexicon = "0.12.2" -wasmer = "2.0.0" -wasmer-wasi = "2.0.0" tempfile = "3.1.0" diff --git a/compiler/gen_wasm/src/from_wasm32_memory.rs b/compiler/gen_wasm/src/from_wasm32_memory.rs new file mode 100644 index 0000000000..db59b8ef95 --- /dev/null +++ b/compiler/gen_wasm/src/from_wasm32_memory.rs @@ -0,0 +1,210 @@ +use roc_std::{RocDec, RocList, RocOrder, RocStr}; + +pub trait FromWasm32Memory: Sized { + const SIZE_OF_WASM: usize; + const ALIGN_OF_WASM: usize; + const ACTUAL_WIDTH: usize = if (Self::SIZE_OF_WASM % Self::ALIGN_OF_WASM) == 0 { + Self::SIZE_OF_WASM + } else { + Self::SIZE_OF_WASM + (Self::ALIGN_OF_WASM - (Self::SIZE_OF_WASM % Self::ALIGN_OF_WASM)) + }; + + fn decode(memory: &wasmer::Memory, offset: u32) -> Self; +} + +macro_rules! from_wasm_memory_primitive_decode { + ($type_name:ident) => { + const SIZE_OF_WASM: usize = core::mem::size_of::<$type_name>(); + const ALIGN_OF_WASM: usize = core::mem::align_of::<$type_name>(); + + fn decode(memory: &wasmer::Memory, offset: u32) -> Self { + use core::mem::MaybeUninit; + + let mut output: MaybeUninit = MaybeUninit::uninit(); + let width = std::mem::size_of::(); + + let ptr = output.as_mut_ptr(); + let raw_ptr = ptr as *mut u8; + let slice = unsafe { std::slice::from_raw_parts_mut(raw_ptr, width) }; + + let ptr: wasmer::WasmPtr = wasmer::WasmPtr::new(offset as u32); + let foobar = (ptr.deref(memory, 0, width as u32)).unwrap(); + let wasm_slice = unsafe { std::mem::transmute(foobar) }; + + slice.copy_from_slice(wasm_slice); + + unsafe { output.assume_init() } + } + }; +} + +macro_rules! from_wasm_memory_primitive { + ($($type_name:ident ,)+) => { + $( + impl FromWasm32Memory for $type_name { + from_wasm_memory_primitive_decode!($type_name); + } + )* + } +} + +from_wasm_memory_primitive!( + u8, i8, u16, i16, u32, i32, u64, i64, u128, i128, f32, f64, bool, RocDec, RocOrder, +); + +impl FromWasm32Memory for () { + const SIZE_OF_WASM: usize = 0; + const ALIGN_OF_WASM: usize = 0; + + fn decode(_: &wasmer::Memory, _: u32) -> Self {} +} + +impl FromWasm32Memory for RocStr { + const SIZE_OF_WASM: usize = 8; + const ALIGN_OF_WASM: usize = 4; + + fn decode(memory: &wasmer::Memory, offset: u32) -> Self { + let bytes = ::decode(memory, offset); + + let length = (bytes >> 32) as u32; + let elements = bytes as u32; + + if length == 0 { + RocStr::default() + } else if (length as i32) < 0 { + // this is a small string + let last_byte = bytes.to_ne_bytes()[7]; + let actual_length = (last_byte ^ 0b1000_0000) as usize; + + let slice = &bytes.to_ne_bytes()[..actual_length as usize]; + RocStr::from_slice(slice) + } else { + // this is a big string + let ptr: wasmer::WasmPtr = wasmer::WasmPtr::new(elements); + let foobar = (ptr.deref(memory, 0, length)).unwrap(); + let wasm_slice = unsafe { std::mem::transmute(foobar) }; + + RocStr::from_slice(wasm_slice) + } + } +} + +impl FromWasm32Memory for RocList { + const SIZE_OF_WASM: usize = 8; + const ALIGN_OF_WASM: usize = 4; + + fn decode(memory: &wasmer::Memory, offset: u32) -> Self { + let bytes = ::decode(memory, offset); + + let length = (bytes >> 32) as u32; + let elements = bytes as u32; + + let mut items = Vec::with_capacity(length as usize); + + for i in 0..length { + let item = ::decode( + memory, + elements + i * ::SIZE_OF_WASM as u32, + ); + items.push(item); + } + + RocList::from_slice(&items) + } +} + +impl FromWasm32Memory for &'_ T { + const SIZE_OF_WASM: usize = 4; + const ALIGN_OF_WASM: usize = 4; + + fn decode(memory: &wasmer::Memory, offset: u32) -> Self { + let elements = ::decode(memory, offset); + + let actual = ::decode(memory, elements); + + let b = Box::new(actual); + + std::boxed::Box::::leak(b) + } +} + +impl FromWasm32Memory for [T; N] { + const SIZE_OF_WASM: usize = N * T::SIZE_OF_WASM; + const ALIGN_OF_WASM: usize = T::ALIGN_OF_WASM; + + fn decode(memory: &wasmer::Memory, offset: u32) -> Self { + let ptr: wasmer::WasmPtr = wasmer::WasmPtr::new(offset); + let width = ::SIZE_OF_WASM as u32 * N as u32; + let foobar = (ptr.deref(memory, 0, width)).unwrap(); + let wasm_slice: &[T; N] = unsafe { &*(foobar as *const _ as *const [T; N]) }; + + wasm_slice.clone() + } +} + +impl FromWasm32Memory for usize { + const SIZE_OF_WASM: usize = 4; + const ALIGN_OF_WASM: usize = 4; + + fn decode(memory: &wasmer::Memory, offset: u32) -> Self { + ::decode(memory, offset) as usize + } +} + +impl FromWasm32Memory for (T, U) { + const SIZE_OF_WASM: usize = T::SIZE_OF_WASM + U::SIZE_OF_WASM; + const ALIGN_OF_WASM: usize = max2(T::SIZE_OF_WASM, U::SIZE_OF_WASM); + + fn decode(memory: &wasmer::Memory, offset: u32) -> Self { + debug_assert!( + T::ALIGN_OF_WASM >= U::ALIGN_OF_WASM, + "this function does not handle alignment" + ); + + let t = ::decode(memory, offset); + + let u = ::decode(memory, offset + T::ACTUAL_WIDTH as u32); + + (t, u) + } +} + +const fn max2(a: usize, b: usize) -> usize { + if a > b { + a + } else { + b + } +} + +const fn max3(a: usize, b: usize, c: usize) -> usize { + max2(max2(a, b), c) +} + +impl FromWasm32Memory for (T, U, V) { + const SIZE_OF_WASM: usize = T::SIZE_OF_WASM + U::SIZE_OF_WASM + V::SIZE_OF_WASM; + const ALIGN_OF_WASM: usize = max3(T::SIZE_OF_WASM, U::SIZE_OF_WASM, V::SIZE_OF_WASM); + + fn decode(memory: &wasmer::Memory, offset: u32) -> Self { + debug_assert!( + T::ALIGN_OF_WASM >= U::ALIGN_OF_WASM, + "this function does not handle alignment" + ); + + debug_assert!( + U::ALIGN_OF_WASM >= V::ALIGN_OF_WASM, + "this function does not handle alignment" + ); + + let t = ::decode(memory, offset); + + let u = ::decode(memory, offset + T::ACTUAL_WIDTH as u32); + + let v = ::decode( + memory, + offset + T::ACTUAL_WIDTH as u32 + U::ACTUAL_WIDTH as u32, + ); + + (t, u, v) + } +} diff --git a/compiler/gen_wasm/src/lib.rs b/compiler/gen_wasm/src/lib.rs index 70e8c1c964..f43c3efe1b 100644 --- a/compiler/gen_wasm/src/lib.rs +++ b/compiler/gen_wasm/src/lib.rs @@ -1,3 +1,4 @@ +pub mod from_wasm32_memory; mod backend; use bumpalo::Bump; diff --git a/compiler/gen_wasm/tests/helpers/eval_full.rs b/compiler/gen_wasm/tests/helpers/eval_full.rs index 065fe0d05b..d0f3ef715d 100644 --- a/compiler/gen_wasm/tests/helpers/eval_full.rs +++ b/compiler/gen_wasm/tests/helpers/eval_full.rs @@ -1,6 +1,7 @@ use roc_can::builtins::builtin_defs_map; use roc_collections::all::{MutMap, MutSet}; use roc_std::{RocDec, RocList, RocOrder, RocStr}; +use crate::from_wasm32_memory::FromWasmMemory fn promote_expr_to_module(src: &str) -> String { let mut buffer = String::from("app \"test\" provides [ main ] to \"./platform\"\n\nmain =\n"); @@ -206,7 +207,7 @@ where _ => panic!(), }; - let output = ::decode( + let output = ::decode( memory, // skip the RocCallResult tag id address as u32 + 8, @@ -255,232 +256,3 @@ macro_rules! assert_evals_to { pub fn identity(value: T) -> T { value } - -pub trait FromWasmMemory: Sized { - const SIZE_OF_WASM: usize; - const ALIGN_OF_WASM: usize; - const ACTUAL_WIDTH: usize = if (Self::SIZE_OF_WASM % Self::ALIGN_OF_WASM) == 0 { - Self::SIZE_OF_WASM - } else { - Self::SIZE_OF_WASM + (Self::ALIGN_OF_WASM - (Self::SIZE_OF_WASM % Self::ALIGN_OF_WASM)) - }; - - fn decode(memory: &wasmer::Memory, offset: u32) -> Self; -} - -macro_rules! from_wasm_memory_primitive_decode { - ($type_name:ident) => { - const SIZE_OF_WASM: usize = core::mem::size_of::<$type_name>(); - const ALIGN_OF_WASM: usize = core::mem::align_of::<$type_name>(); - - fn decode(memory: &wasmer::Memory, offset: u32) -> Self { - use core::mem::MaybeUninit; - - let mut output: MaybeUninit = MaybeUninit::uninit(); - let width = std::mem::size_of::(); - - let ptr = output.as_mut_ptr(); - let raw_ptr = ptr as *mut u8; - let slice = unsafe { std::slice::from_raw_parts_mut(raw_ptr, width) }; - - let ptr: wasmer::WasmPtr = wasmer::WasmPtr::new(offset as u32); - let foobar = (ptr.deref(memory, 0, width as u32)).unwrap(); - let wasm_slice = unsafe { std::mem::transmute(foobar) }; - - slice.copy_from_slice(wasm_slice); - - unsafe { output.assume_init() } - } - }; -} - -macro_rules! from_wasm_memory_primitive { - ($($type_name:ident ,)+) => { - $( - impl FromWasmMemory for $type_name { - from_wasm_memory_primitive_decode!($type_name); - } - )* - } -} - -from_wasm_memory_primitive!( - u8, i8, u16, i16, u32, i32, u64, i64, u128, i128, f32, f64, bool, RocDec, RocOrder, -); - -impl FromWasmMemory for () { - const SIZE_OF_WASM: usize = 0; - const ALIGN_OF_WASM: usize = 0; - - fn decode(_: &wasmer::Memory, _: u32) -> Self {} -} - -impl FromWasmMemory for RocStr { - const SIZE_OF_WASM: usize = 8; - const ALIGN_OF_WASM: usize = 4; - - fn decode(memory: &wasmer::Memory, offset: u32) -> Self { - let bytes = ::decode(memory, offset); - - let length = (bytes >> 32) as u32; - let elements = bytes as u32; - - if length == 0 { - RocStr::default() - } else if (length as i32) < 0 { - // this is a small string - let last_byte = bytes.to_ne_bytes()[7]; - let actual_length = (last_byte ^ 0b1000_0000) as usize; - - let slice = &bytes.to_ne_bytes()[..actual_length as usize]; - RocStr::from_slice(slice) - } else { - // this is a big string - let ptr: wasmer::WasmPtr = wasmer::WasmPtr::new(elements); - let foobar = (ptr.deref(memory, 0, length)).unwrap(); - let wasm_slice = unsafe { std::mem::transmute(foobar) }; - - RocStr::from_slice(wasm_slice) - } - } -} - -impl FromWasmMemory for RocList { - const SIZE_OF_WASM: usize = 8; - const ALIGN_OF_WASM: usize = 4; - - fn decode(memory: &wasmer::Memory, offset: u32) -> Self { - let bytes = ::decode(memory, offset); - - let length = (bytes >> 32) as u32; - let elements = bytes as u32; - - let mut items = Vec::with_capacity(length as usize); - - for i in 0..length { - let item = ::decode( - memory, - elements + i * ::SIZE_OF_WASM as u32, - ); - items.push(item); - } - - RocList::from_slice(&items) - } -} - -impl FromWasmMemory for &'_ [T] { - const SIZE_OF_WASM: usize = 8; - const ALIGN_OF_WASM: usize = 4; - - fn decode(memory: &wasmer::Memory, offset: u32) -> Self { - let bytes = ::decode(memory, offset); - - let length = (bytes >> 32) as u32; - let elements = bytes as u32; - - let ptr: wasmer::WasmPtr = wasmer::WasmPtr::new(elements); - let width = ::SIZE_OF_WASM as u32 * length; - let foobar = (ptr.deref(memory, 0, width)).unwrap(); - let wasm_slice = - unsafe { std::slice::from_raw_parts(foobar as *const _ as *const _, length as usize) }; - - wasm_slice - } -} - -impl FromWasmMemory for &'_ T { - const SIZE_OF_WASM: usize = 4; - const ALIGN_OF_WASM: usize = 4; - - fn decode(memory: &wasmer::Memory, offset: u32) -> Self { - let elements = ::decode(memory, offset); - - let actual = ::decode(memory, elements); - - let b = Box::new(actual); - - std::boxed::Box::::leak(b) - } -} - -impl FromWasmMemory for [T; N] { - const SIZE_OF_WASM: usize = N * T::SIZE_OF_WASM; - const ALIGN_OF_WASM: usize = T::ALIGN_OF_WASM; - - fn decode(memory: &wasmer::Memory, offset: u32) -> Self { - let ptr: wasmer::WasmPtr = wasmer::WasmPtr::new(offset); - let width = ::SIZE_OF_WASM as u32 * N as u32; - let foobar = (ptr.deref(memory, 0, width)).unwrap(); - let wasm_slice: &[T; N] = unsafe { &*(foobar as *const _ as *const [T; N]) }; - - wasm_slice.clone() - } -} - -impl FromWasmMemory for usize { - const SIZE_OF_WASM: usize = 4; - const ALIGN_OF_WASM: usize = 4; - - fn decode(memory: &wasmer::Memory, offset: u32) -> Self { - ::decode(memory, offset) as usize - } -} - -impl FromWasmMemory for (T, U) { - const SIZE_OF_WASM: usize = T::SIZE_OF_WASM + U::SIZE_OF_WASM; - const ALIGN_OF_WASM: usize = max2(T::SIZE_OF_WASM, U::SIZE_OF_WASM); - - fn decode(memory: &wasmer::Memory, offset: u32) -> Self { - assert!( - T::ALIGN_OF_WASM >= U::ALIGN_OF_WASM, - "this function does not handle alignment" - ); - - let t = ::decode(memory, offset); - - let u = ::decode(memory, offset + T::ACTUAL_WIDTH as u32); - - (t, u) - } -} - -const fn max2(a: usize, b: usize) -> usize { - if a > b { - a - } else { - b - } -} - -const fn max3(a: usize, b: usize, c: usize) -> usize { - max2(max2(a, b), c) -} - -impl FromWasmMemory for (T, U, V) { - const SIZE_OF_WASM: usize = T::SIZE_OF_WASM + U::SIZE_OF_WASM + V::SIZE_OF_WASM; - const ALIGN_OF_WASM: usize = max3(T::SIZE_OF_WASM, U::SIZE_OF_WASM, V::SIZE_OF_WASM); - - fn decode(memory: &wasmer::Memory, offset: u32) -> Self { - assert!( - T::ALIGN_OF_WASM >= U::ALIGN_OF_WASM, - "this function does not handle alignment" - ); - - assert!( - U::ALIGN_OF_WASM >= V::ALIGN_OF_WASM, - "this function does not handle alignment" - ); - - let t = ::decode(memory, offset); - - let u = ::decode(memory, offset + T::ACTUAL_WIDTH as u32); - - let v = ::decode( - memory, - offset + T::ACTUAL_WIDTH as u32 + U::ACTUAL_WIDTH as u32, - ); - - (t, u, v) - } -} diff --git a/compiler/gen_wasm/tests/helpers/eval_simple.rs b/compiler/gen_wasm/tests/helpers/eval_simple.rs index 172217acb4..d6180eec58 100644 --- a/compiler/gen_wasm/tests/helpers/eval_simple.rs +++ b/compiler/gen_wasm/tests/helpers/eval_simple.rs @@ -85,16 +85,16 @@ pub fn helper_wasm<'a>( let exposed_to_host = exposed_to_host.keys().copied().collect::>(); - let env = gen_wasm::Env { + let env = roc_gen_wasm::Env { arena, interns, exposed_to_host, }; - let module_bytes = gen_wasm::build_module(&env, procedures).unwrap(); + let module_bytes = roc_gen_wasm::build_module(&env, procedures).unwrap(); // for debugging (e.g. with wasm2wat) - if true { + if false { use std::io::Write; let mut file = std::fs::File::create("/home/brian/Documents/roc/compiler/gen_wasm/debug.wasm").unwrap(); From 28c608e692ccef6806267f5d7513c07c006e8529 Mon Sep 17 00:00:00 2001 From: Folkert Date: Tue, 7 Sep 2021 16:47:10 +0200 Subject: [PATCH 30/42] remove duplication of FromWasm32Memory --- compiler/gen_wasm/tests/helpers/eval_full.rs | 246 +------------------ 1 file changed, 12 insertions(+), 234 deletions(-) diff --git a/compiler/gen_wasm/tests/helpers/eval_full.rs b/compiler/gen_wasm/tests/helpers/eval_full.rs index 065fe0d05b..3e44e0d7cd 100644 --- a/compiler/gen_wasm/tests/helpers/eval_full.rs +++ b/compiler/gen_wasm/tests/helpers/eval_full.rs @@ -1,6 +1,6 @@ use roc_can::builtins::builtin_defs_map; use roc_collections::all::{MutMap, MutSet}; -use roc_std::{RocDec, RocList, RocOrder, RocStr}; +use roc_gen_wasm::from_wasm32_memory::FromWasm32Memory; fn promote_expr_to_module(src: &str) -> String { let mut buffer = String::from("app \"test\" provides [ main ] to \"./platform\"\n\nmain =\n"); @@ -97,7 +97,8 @@ pub fn helper_wasm<'a>( if true { use std::io::Write; let mut file = - std::fs::File::create("/home/brian/Documents/roc/compiler/gen_wasm/debug.wasm").unwrap(); + std::fs::File::create("/home/brian/Documents/roc/compiler/gen_wasm/debug.wasm") + .unwrap(); file.write_all(&module_bytes).unwrap(); } @@ -179,7 +180,7 @@ fn fake_wasm_main_function(_: u32, _: u32) -> u32 { #[allow(dead_code)] pub fn assert_wasm_evals_to_help(src: &str, ignore_problems: bool) -> Result where - T: FromWasmMemory, + T: FromWasm32Memory, { let arena = bumpalo::Bump::new(); @@ -206,7 +207,7 @@ where _ => panic!(), }; - let output = ::decode( + let output = ::decode( memory, // skip the RocCallResult tag id address as u32 + 8, @@ -230,7 +231,13 @@ macro_rules! assert_wasm_evals_to { }; ($src:expr, $expected:expr, $ty:ty) => { - $crate::assert_wasm_evals_to!($src, $expected, $ty, $crate::helpers::eval_full::identity, false); + $crate::assert_wasm_evals_to!( + $src, + $expected, + $ty, + $crate::helpers::eval_full::identity, + false + ); }; ($src:expr, $expected:expr, $ty:ty, $transform:expr) => { @@ -255,232 +262,3 @@ macro_rules! assert_evals_to { pub fn identity(value: T) -> T { value } - -pub trait FromWasmMemory: Sized { - const SIZE_OF_WASM: usize; - const ALIGN_OF_WASM: usize; - const ACTUAL_WIDTH: usize = if (Self::SIZE_OF_WASM % Self::ALIGN_OF_WASM) == 0 { - Self::SIZE_OF_WASM - } else { - Self::SIZE_OF_WASM + (Self::ALIGN_OF_WASM - (Self::SIZE_OF_WASM % Self::ALIGN_OF_WASM)) - }; - - fn decode(memory: &wasmer::Memory, offset: u32) -> Self; -} - -macro_rules! from_wasm_memory_primitive_decode { - ($type_name:ident) => { - const SIZE_OF_WASM: usize = core::mem::size_of::<$type_name>(); - const ALIGN_OF_WASM: usize = core::mem::align_of::<$type_name>(); - - fn decode(memory: &wasmer::Memory, offset: u32) -> Self { - use core::mem::MaybeUninit; - - let mut output: MaybeUninit = MaybeUninit::uninit(); - let width = std::mem::size_of::(); - - let ptr = output.as_mut_ptr(); - let raw_ptr = ptr as *mut u8; - let slice = unsafe { std::slice::from_raw_parts_mut(raw_ptr, width) }; - - let ptr: wasmer::WasmPtr = wasmer::WasmPtr::new(offset as u32); - let foobar = (ptr.deref(memory, 0, width as u32)).unwrap(); - let wasm_slice = unsafe { std::mem::transmute(foobar) }; - - slice.copy_from_slice(wasm_slice); - - unsafe { output.assume_init() } - } - }; -} - -macro_rules! from_wasm_memory_primitive { - ($($type_name:ident ,)+) => { - $( - impl FromWasmMemory for $type_name { - from_wasm_memory_primitive_decode!($type_name); - } - )* - } -} - -from_wasm_memory_primitive!( - u8, i8, u16, i16, u32, i32, u64, i64, u128, i128, f32, f64, bool, RocDec, RocOrder, -); - -impl FromWasmMemory for () { - const SIZE_OF_WASM: usize = 0; - const ALIGN_OF_WASM: usize = 0; - - fn decode(_: &wasmer::Memory, _: u32) -> Self {} -} - -impl FromWasmMemory for RocStr { - const SIZE_OF_WASM: usize = 8; - const ALIGN_OF_WASM: usize = 4; - - fn decode(memory: &wasmer::Memory, offset: u32) -> Self { - let bytes = ::decode(memory, offset); - - let length = (bytes >> 32) as u32; - let elements = bytes as u32; - - if length == 0 { - RocStr::default() - } else if (length as i32) < 0 { - // this is a small string - let last_byte = bytes.to_ne_bytes()[7]; - let actual_length = (last_byte ^ 0b1000_0000) as usize; - - let slice = &bytes.to_ne_bytes()[..actual_length as usize]; - RocStr::from_slice(slice) - } else { - // this is a big string - let ptr: wasmer::WasmPtr = wasmer::WasmPtr::new(elements); - let foobar = (ptr.deref(memory, 0, length)).unwrap(); - let wasm_slice = unsafe { std::mem::transmute(foobar) }; - - RocStr::from_slice(wasm_slice) - } - } -} - -impl FromWasmMemory for RocList { - const SIZE_OF_WASM: usize = 8; - const ALIGN_OF_WASM: usize = 4; - - fn decode(memory: &wasmer::Memory, offset: u32) -> Self { - let bytes = ::decode(memory, offset); - - let length = (bytes >> 32) as u32; - let elements = bytes as u32; - - let mut items = Vec::with_capacity(length as usize); - - for i in 0..length { - let item = ::decode( - memory, - elements + i * ::SIZE_OF_WASM as u32, - ); - items.push(item); - } - - RocList::from_slice(&items) - } -} - -impl FromWasmMemory for &'_ [T] { - const SIZE_OF_WASM: usize = 8; - const ALIGN_OF_WASM: usize = 4; - - fn decode(memory: &wasmer::Memory, offset: u32) -> Self { - let bytes = ::decode(memory, offset); - - let length = (bytes >> 32) as u32; - let elements = bytes as u32; - - let ptr: wasmer::WasmPtr = wasmer::WasmPtr::new(elements); - let width = ::SIZE_OF_WASM as u32 * length; - let foobar = (ptr.deref(memory, 0, width)).unwrap(); - let wasm_slice = - unsafe { std::slice::from_raw_parts(foobar as *const _ as *const _, length as usize) }; - - wasm_slice - } -} - -impl FromWasmMemory for &'_ T { - const SIZE_OF_WASM: usize = 4; - const ALIGN_OF_WASM: usize = 4; - - fn decode(memory: &wasmer::Memory, offset: u32) -> Self { - let elements = ::decode(memory, offset); - - let actual = ::decode(memory, elements); - - let b = Box::new(actual); - - std::boxed::Box::::leak(b) - } -} - -impl FromWasmMemory for [T; N] { - const SIZE_OF_WASM: usize = N * T::SIZE_OF_WASM; - const ALIGN_OF_WASM: usize = T::ALIGN_OF_WASM; - - fn decode(memory: &wasmer::Memory, offset: u32) -> Self { - let ptr: wasmer::WasmPtr = wasmer::WasmPtr::new(offset); - let width = ::SIZE_OF_WASM as u32 * N as u32; - let foobar = (ptr.deref(memory, 0, width)).unwrap(); - let wasm_slice: &[T; N] = unsafe { &*(foobar as *const _ as *const [T; N]) }; - - wasm_slice.clone() - } -} - -impl FromWasmMemory for usize { - const SIZE_OF_WASM: usize = 4; - const ALIGN_OF_WASM: usize = 4; - - fn decode(memory: &wasmer::Memory, offset: u32) -> Self { - ::decode(memory, offset) as usize - } -} - -impl FromWasmMemory for (T, U) { - const SIZE_OF_WASM: usize = T::SIZE_OF_WASM + U::SIZE_OF_WASM; - const ALIGN_OF_WASM: usize = max2(T::SIZE_OF_WASM, U::SIZE_OF_WASM); - - fn decode(memory: &wasmer::Memory, offset: u32) -> Self { - assert!( - T::ALIGN_OF_WASM >= U::ALIGN_OF_WASM, - "this function does not handle alignment" - ); - - let t = ::decode(memory, offset); - - let u = ::decode(memory, offset + T::ACTUAL_WIDTH as u32); - - (t, u) - } -} - -const fn max2(a: usize, b: usize) -> usize { - if a > b { - a - } else { - b - } -} - -const fn max3(a: usize, b: usize, c: usize) -> usize { - max2(max2(a, b), c) -} - -impl FromWasmMemory for (T, U, V) { - const SIZE_OF_WASM: usize = T::SIZE_OF_WASM + U::SIZE_OF_WASM + V::SIZE_OF_WASM; - const ALIGN_OF_WASM: usize = max3(T::SIZE_OF_WASM, U::SIZE_OF_WASM, V::SIZE_OF_WASM); - - fn decode(memory: &wasmer::Memory, offset: u32) -> Self { - assert!( - T::ALIGN_OF_WASM >= U::ALIGN_OF_WASM, - "this function does not handle alignment" - ); - - assert!( - U::ALIGN_OF_WASM >= V::ALIGN_OF_WASM, - "this function does not handle alignment" - ); - - let t = ::decode(memory, offset); - - let u = ::decode(memory, offset + T::ACTUAL_WIDTH as u32); - - let v = ::decode( - memory, - offset + T::ACTUAL_WIDTH as u32 + U::ACTUAL_WIDTH as u32, - ); - - (t, u, v) - } -} From e316bfca7237003e837f2ac38476f521dd3d9af7 Mon Sep 17 00:00:00 2001 From: Folkert Date: Tue, 7 Sep 2021 16:48:11 +0200 Subject: [PATCH 31/42] make mut --- compiler/gen_wasm/tests/helpers/eval_simple.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/gen_wasm/tests/helpers/eval_simple.rs b/compiler/gen_wasm/tests/helpers/eval_simple.rs index 00d7bc4663..ba460139a6 100644 --- a/compiler/gen_wasm/tests/helpers/eval_simple.rs +++ b/compiler/gen_wasm/tests/helpers/eval_simple.rs @@ -100,7 +100,7 @@ pub fn helper_wasm<'a>( match std::fs::File::create(path) { Err(e) => eprintln!("Problem creating wasm debug file: {:?}", e), - Ok(file) => { + Ok(mut file) => { file.write_all(&module_bytes).unwrap(); } } From afd7553e7a48281ebfc68d7266bbc3e5f8d9237d Mon Sep 17 00:00:00 2001 From: Folkert Date: Tue, 7 Sep 2021 17:42:31 +0200 Subject: [PATCH 32/42] enable F64 --- compiler/gen_wasm/src/backend.rs | 4 ++++ .../gen_wasm/tests/helpers/eval_simple.rs | 1 + compiler/gen_wasm/tests/wasm_num.rs | 20 +++++++++---------- 3 files changed, 15 insertions(+), 10 deletions(-) diff --git a/compiler/gen_wasm/src/backend.rs b/compiler/gen_wasm/src/backend.rs index 3f75256789..715902a0d8 100644 --- a/compiler/gen_wasm/src/backend.rs +++ b/compiler/gen_wasm/src/backend.rs @@ -34,6 +34,10 @@ impl WasmLayout { value_type: ValueType::I64, stack_memory: 0, }), + Layout::Builtin(Builtin::Float64) => Ok(Self { + value_type: ValueType::F64, + stack_memory: 0, + }), x => Err(format!("layout, {:?}, not implemented yet", x)), } } diff --git a/compiler/gen_wasm/tests/helpers/eval_simple.rs b/compiler/gen_wasm/tests/helpers/eval_simple.rs index ba460139a6..ede52522b3 100644 --- a/compiler/gen_wasm/tests/helpers/eval_simple.rs +++ b/compiler/gen_wasm/tests/helpers/eval_simple.rs @@ -148,6 +148,7 @@ where Ok(result) => { let integer = match result[0] { wasmer::Value::I64(a) => a, + wasmer::Value::F64(a) => a.to_bits() as i64, _ => panic!(), }; diff --git a/compiler/gen_wasm/tests/wasm_num.rs b/compiler/gen_wasm/tests/wasm_num.rs index f09299198d..57ef682f76 100644 --- a/compiler/gen_wasm/tests/wasm_num.rs +++ b/compiler/gen_wasm/tests/wasm_num.rs @@ -25,16 +25,16 @@ mod dev_num { assert_evals_to!("0x1000_0000_0000_0000", 0x1000_0000_0000_0000, i64); } - // #[test] - // fn f64_values() { - // assert_evals_to!("0.0", 0.0, f64); - // assert_evals_to!("-0.0", 0.0, f64); - // assert_evals_to!("1.0", 1.0, f64); - // assert_evals_to!("-1.0", -1.0, f64); - // assert_evals_to!("3.1415926535897932", 3.141_592_653_589_793, f64); - // assert_evals_to!(&format!("{:0.1}", f64::MIN), f64::MIN, f64); - // assert_evals_to!(&format!("{:0.1}", f64::MAX), f64::MAX, f64); - // } + #[test] + fn f64_values() { + assert_evals_to!("0.0", 0.0, f64); + assert_evals_to!("-0.0", 0.0, f64); + assert_evals_to!("1.0", 1.0, f64); + assert_evals_to!("-1.0", -1.0, f64); + assert_evals_to!("3.1415926535897932", 3.141_592_653_589_793, f64); + assert_evals_to!(&format!("{:0.1}", f64::MIN), f64::MIN, f64); + assert_evals_to!(&format!("{:0.1}", f64::MAX), f64::MAX, f64); + } #[test] fn gen_add_i64() { From 4c8ac253e4b8d5ede0d08ad71c3643e87ad2fd85 Mon Sep 17 00:00:00 2001 From: Folkert Date: Tue, 7 Sep 2021 17:45:10 +0200 Subject: [PATCH 33/42] fix typo --- compiler/gen_wasm/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/gen_wasm/README.md b/compiler/gen_wasm/README.md index 68cb38474c..3e453b21e2 100644 --- a/compiler/gen_wasm/README.md +++ b/compiler/gen_wasm/README.md @@ -34,7 +34,7 @@ However the Mono IR converts this to jumps and join points, which are more of a [cfg-api]: https://github.com/WebAssembly/binaryen/wiki/Compiling-to-WebAssembly-with-Binaryen#cfg-api [binaryen-rs]: https://crates.io/crates/binaryen -Binaryen's control-flow graph API implements the "Relooper" algorithm developed by the Emscripten project and decribed in [this paper](https://github.com/emscripten-core/emscripten/blob/main/docs/paper.pdf). +Binaryen's control-flow graph API implements the "Relooper" algorithm developed by the Emscripten project and described in [this paper](https://github.com/emscripten-core/emscripten/blob/main/docs/paper.pdf). There is an alternative algorithm that is supposed to be an improvement on Relooper, called ["Stackifier"](https://medium.com/leaningtech/solving-the-structured-control-flow-problem-once-and-for-all-5123117b1ee2). From 5e411bdda31f5a879c48f28f225d27aaaa3eba9f Mon Sep 17 00:00:00 2001 From: Anton-4 <17049058+Anton-4@users.noreply.github.com> Date: Tue, 7 Sep 2021 20:05:47 +0200 Subject: [PATCH 34/42] fix unable to find library -lxkbcommon --- Earthfile | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Earthfile b/Earthfile index 29973ffe70..3073021b6b 100644 --- a/Earthfile +++ b/Earthfile @@ -34,6 +34,8 @@ install-zig-llvm-valgrind-clippy-rustfmt: RUN rustup component add rustfmt # criterion RUN cargo install cargo-criterion + # wasm + RUN apt -y install libxkbcommon-dev # sccache RUN apt -y install libssl-dev RUN cargo install sccache From c888baccff16e42eb68a356e89007cf61b023b1a Mon Sep 17 00:00:00 2001 From: Folkert Date: Tue, 7 Sep 2021 20:55:05 +0200 Subject: [PATCH 35/42] rename layout -> return_layout --- compiler/gen_wasm/src/backend.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/compiler/gen_wasm/src/backend.rs b/compiler/gen_wasm/src/backend.rs index 715902a0d8..b66c4847d7 100644 --- a/compiler/gen_wasm/src/backend.rs +++ b/compiler/gen_wasm/src/backend.rs @@ -265,12 +265,12 @@ impl<'a> WasmBackend<'a> { &mut self, lowlevel: &LowLevel, args: &'a [Symbol], - layout: &Layout<'a>, + return_layout: &Layout<'a>, ) -> Result<(), String> { for arg in args { self.load_from_symbol(arg)?; } - let wasm_layout = WasmLayout::new(layout)?; + let wasm_layout = WasmLayout::new(return_layout)?; self.build_instructions_lowlevel(lowlevel, wasm_layout.value_type)?; Ok(()) } @@ -278,7 +278,7 @@ impl<'a> WasmBackend<'a> { fn build_instructions_lowlevel( &mut self, lowlevel: &LowLevel, - value_type: ValueType, + return_value_type: ValueType, ) -> Result<(), String> { // TODO: Find a way to organise all the lowlevel ops and layouts! There's lots! // @@ -287,7 +287,7 @@ impl<'a> WasmBackend<'a> { // so simple arrays of instructions won't work. But there are common patterns. let instructions: &[Instruction] = match lowlevel { // Wasm type might not be enough, may need to sign-extend i8 etc. Maybe in load_from_symbol? - LowLevel::NumAdd => match value_type { + LowLevel::NumAdd => match return_value_type { ValueType::I32 => &[I32Add], ValueType::I64 => &[I64Add], ValueType::F32 => &[F32Add], From 480cdea82cce285b46d0733a67e023578ad63363 Mon Sep 17 00:00:00 2001 From: Folkert Date: Wed, 8 Sep 2021 00:57:45 +0200 Subject: [PATCH 36/42] comment out record tests --- compiler/gen_wasm/tests/wasm_records.rs | 524 ++++++++++++------------ 1 file changed, 262 insertions(+), 262 deletions(-) diff --git a/compiler/gen_wasm/tests/wasm_records.rs b/compiler/gen_wasm/tests/wasm_records.rs index 2fcebe8c97..63f72357a2 100644 --- a/compiler/gen_wasm/tests/wasm_records.rs +++ b/compiler/gen_wasm/tests/wasm_records.rs @@ -6,130 +6,130 @@ mod helpers; #[cfg(all(test, target_os = "linux", any(target_arch = "x86_64"/*, target_arch = "aarch64"*/)))] mod dev_records { - #[test] - fn basic_record() { - assert_evals_to!( - indoc!( - r#" - { y: 17, x: 15, z: 19 }.x - "# - ), - 15, - i64 - ); - - assert_evals_to!( - indoc!( - r#" - { x: 15, y: 17, z: 19 }.y - "# - ), - 17, - i64 - ); - - assert_evals_to!( - indoc!( - r#" - { x: 15, y: 17, z: 19 }.z - "# - ), - 19, - i64 - ); - } - - #[test] - fn nested_record() { - assert_evals_to!( - indoc!( - r#" - { x: 15, y: { a: 12, b: 15, c: 2}, z: 19 }.x - "# - ), - 15, - i64 - ); - - assert_evals_to!( - indoc!( - r#" - { x: 15, y: { a: 12, b: 15, c: 2}, z: 19 }.y.a - "# - ), - 12, - i64 - ); - - assert_evals_to!( - indoc!( - r#" - { x: 15, y: { a: 12, b: 15, c: 2}, z: 19 }.y.b - "# - ), - 15, - i64 - ); - - assert_evals_to!( - indoc!( - r#" - { x: 15, y: { a: 12, b: 15, c: 2}, z: 19 }.y.c - "# - ), - 2, - i64 - ); - - assert_evals_to!( - indoc!( - r#" - { x: 15, y: { a: 12, b: 15, c: 2}, z: 19 }.z - "# - ), - 19, - i64 - ); - } - - #[test] - fn f64_record() { - assert_evals_to!( - indoc!( - r#" - rec = { y: 17.2, x: 15.1, z: 19.3 } - - rec.x - "# - ), - 15.1, - f64 - ); - - assert_evals_to!( - indoc!( - r#" - rec = { y: 17.2, x: 15.1, z: 19.3 } - - rec.y - "# - ), - 17.2, - f64 - ); - - assert_evals_to!( - indoc!( - r#" - rec = { y: 17.2, x: 15.1, z: 19.3 } - - rec.z - "# - ), - 19.3, - f64 - ); - } + // #[test] + // fn basic_record() { + // assert_evals_to!( + // indoc!( + // r#" + // { y: 17, x: 15, z: 19 }.x + // "# + // ), + // 15, + // i64 + // ); + // + // assert_evals_to!( + // indoc!( + // r#" + // { x: 15, y: 17, z: 19 }.y + // "# + // ), + // 17, + // i64 + // ); + // + // assert_evals_to!( + // indoc!( + // r#" + // { x: 15, y: 17, z: 19 }.z + // "# + // ), + // 19, + // i64 + // ); + // } + // + // #[test] + // fn nested_record() { + // assert_evals_to!( + // indoc!( + // r#" + // { x: 15, y: { a: 12, b: 15, c: 2}, z: 19 }.x + // "# + // ), + // 15, + // i64 + // ); + // + // assert_evals_to!( + // indoc!( + // r#" + // { x: 15, y: { a: 12, b: 15, c: 2}, z: 19 }.y.a + // "# + // ), + // 12, + // i64 + // ); + // + // assert_evals_to!( + // indoc!( + // r#" + // { x: 15, y: { a: 12, b: 15, c: 2}, z: 19 }.y.b + // "# + // ), + // 15, + // i64 + // ); + // + // assert_evals_to!( + // indoc!( + // r#" + // { x: 15, y: { a: 12, b: 15, c: 2}, z: 19 }.y.c + // "# + // ), + // 2, + // i64 + // ); + // + // assert_evals_to!( + // indoc!( + // r#" + // { x: 15, y: { a: 12, b: 15, c: 2}, z: 19 }.z + // "# + // ), + // 19, + // i64 + // ); + // } + // + // #[test] + // fn f64_record() { + // assert_evals_to!( + // indoc!( + // r#" + // rec = { y: 17.2, x: 15.1, z: 19.3 } + // + // rec.x + // "# + // ), + // 15.1, + // f64 + // ); + // + // assert_evals_to!( + // indoc!( + // r#" + // rec = { y: 17.2, x: 15.1, z: 19.3 } + // + // rec.y + // "# + // ), + // 17.2, + // f64 + // ); + // + // assert_evals_to!( + // indoc!( + // r#" + // rec = { y: 17.2, x: 15.1, z: 19.3 } + // + // rec.z + // "# + // ), + // 19.3, + // f64 + // ); + // } // #[test] // fn fn_record() { @@ -182,144 +182,144 @@ mod dev_records { // ); // } - #[test] - fn def_record() { - assert_evals_to!( - indoc!( - r#" - rec = { y: 17, x: 15, z: 19 } - - rec.x - "# - ), - 15, - i64 - ); - - assert_evals_to!( - indoc!( - r#" - rec = { x: 15, y: 17, z: 19 } - - rec.y - "# - ), - 17, - i64 - ); - - assert_evals_to!( - indoc!( - r#" - rec = { x: 15, y: 17, z: 19 } - - rec.z - "# - ), - 19, - i64 - ); - } - - #[test] - fn when_on_record() { - assert_evals_to!( - indoc!( - r#" - when { x: 0x2 } is - { x } -> x + 3 - "# - ), - 5, - i64 - ); - } - - #[test] - fn when_record_with_guard_pattern() { - assert_evals_to!( - indoc!( - r#" - when { x: 0x2, y: 3.14 } is - { x: var } -> var + 3 - "# - ), - 5, - i64 - ); - } - - #[test] - fn let_with_record_pattern() { - assert_evals_to!( - indoc!( - r#" - { x } = { x: 0x2, y: 3.14 } - - x - "# - ), - 2, - i64 - ); - } - - #[test] - fn record_guard_pattern() { - assert_evals_to!( - indoc!( - r#" - when { x: 0x2, y: 3.14 } is - { x: 0x4 } -> 5 - { x } -> x + 3 - "# - ), - 5, - i64 - ); - } - - #[test] - fn twice_record_access() { - assert_evals_to!( - indoc!( - r#" - x = {a: 0x2, b: 0x3 } - - x.a + x.b - "# - ), - 5, - i64 - ); - } - #[test] - fn empty_record() { - assert_evals_to!( - indoc!( - r#" - v = {} - - v - "# - ), - (), - () - ); - } - - #[test] - fn i64_record1_literal() { - assert_evals_to!( - indoc!( - r#" - { x: 3 } - "# - ), - 3, - i64 - ); - } + // #[test] + // fn def_record() { + // assert_evals_to!( + // indoc!( + // r#" + // rec = { y: 17, x: 15, z: 19 } + // + // rec.x + // "# + // ), + // 15, + // i64 + // ); + // + // assert_evals_to!( + // indoc!( + // r#" + // rec = { x: 15, y: 17, z: 19 } + // + // rec.y + // "# + // ), + // 17, + // i64 + // ); + // + // assert_evals_to!( + // indoc!( + // r#" + // rec = { x: 15, y: 17, z: 19 } + // + // rec.z + // "# + // ), + // 19, + // i64 + // ); + // } + // + // #[test] + // fn when_on_record() { + // assert_evals_to!( + // indoc!( + // r#" + // when { x: 0x2 } is + // { x } -> x + 3 + // "# + // ), + // 5, + // i64 + // ); + // } + // + // #[test] + // fn when_record_with_guard_pattern() { + // assert_evals_to!( + // indoc!( + // r#" + // when { x: 0x2, y: 3.14 } is + // { x: var } -> var + 3 + // "# + // ), + // 5, + // i64 + // ); + // } + // + // #[test] + // fn let_with_record_pattern() { + // assert_evals_to!( + // indoc!( + // r#" + // { x } = { x: 0x2, y: 3.14 } + // + // x + // "# + // ), + // 2, + // i64 + // ); + // } + // + // #[test] + // fn record_guard_pattern() { + // assert_evals_to!( + // indoc!( + // r#" + // when { x: 0x2, y: 3.14 } is + // { x: 0x4 } -> 5 + // { x } -> x + 3 + // "# + // ), + // 5, + // i64 + // ); + // } + // + // #[test] + // fn twice_record_access() { + // assert_evals_to!( + // indoc!( + // r#" + // x = {a: 0x2, b: 0x3 } + // + // x.a + x.b + // "# + // ), + // 5, + // i64 + // ); + // } + // #[test] + // fn empty_record() { + // assert_evals_to!( + // indoc!( + // r#" + // v = {} + // + // v + // "# + // ), + // (), + // () + // ); + // } + // + // #[test] + // fn i64_record1_literal() { + // assert_evals_to!( + // indoc!( + // r#" + // { x: 3 } + // "# + // ), + // 3, + // i64 + // ); + // } // #[test] // fn i64_record2_literal() { From b97035ec535a67d527f718f86cb4c5c823dd484d Mon Sep 17 00:00:00 2001 From: Brendan Hansknecht Date: Wed, 8 Sep 2021 09:24:32 -0700 Subject: [PATCH 37/42] Update dependencies --- Cargo.lock | 646 ++++++++++++++++++++++++++++------------------------- 1 file changed, 338 insertions(+), 308 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index b53b0d9b05..b3618fe502 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -9,7 +9,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "af0ac006645f86f20f6c6fa4dcaef920bf803df819123626f9440e35835e7d80" dependencies = [ "ab_glyph_rasterizer", - "owned_ttf_parser 0.12.0", + "owned_ttf_parser 0.12.1", ] [[package]] @@ -173,7 +173,7 @@ dependencies = [ "cfg-if 1.0.0", "libc", "miniz_oxide", - "object 0.26.1", + "object 0.26.2", "rustc-demangle", ] @@ -203,9 +203,9 @@ checksum = "349f9b6a179ed607305526ca489b34ad0a41aed5f7980fa90eb03160b69598fb" [[package]] name = "bitflags" -version = "1.2.1" +version = "1.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] name = "bitmaps" @@ -278,9 +278,9 @@ checksum = "e3b5ca7a04898ad4bcd41c90c5285445ff5b791899bb1b0abdd2a2aa791211d7" [[package]] name = "bytemuck" -version = "1.5.1" +version = "1.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bed57e2090563b83ba8f83366628ce535a7584c9afa4c9fc0612a03925c6df58" +checksum = "72957246c41db82b8ef88a5486143830adeb8227ef9837740bdec67724cf2c5b" dependencies = [ "bytemuck_derive", ] @@ -291,9 +291,9 @@ version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8e215f8c2f9f79cb53c8335e687ffd07d5bfcb6fe5fc80723762d0be46e7cc54" dependencies = [ - "proc-macro2 1.0.27", + "proc-macro2 1.0.29", "quote 1.0.9", - "syn 1.0.72", + "syn 1.0.76", ] [[package]] @@ -320,18 +320,18 @@ dependencies = [ [[package]] name = "cast" -version = "0.2.6" +version = "0.2.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "57cdfa5d50aad6cb4d44dcab6101a7f79925bd59d82ca42f38a9856a28865374" +checksum = "4c24dab4283a142afa2fdca129b80ad2c6284e073930f964c3a1293c225ee39a" dependencies = [ "rustc_version", ] [[package]] name = "cc" -version = "1.0.68" +version = "1.0.70" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4a72c244c1ff497a746a7e1fb3d14bd08420ecda70c8f25c7112f2781652d787" +checksum = "d26a6ce4b6a484fa3edb70f7efa6fc430fd2b87285fe8b84304fd0936faa0dc0" dependencies = [ "jobserver", ] @@ -399,9 +399,9 @@ source = "git+https://github.com/rtfeldman/clap?branch=master#e1d83a78804a271b05 dependencies = [ "heck", "proc-macro-error 0.4.12", - "proc-macro2 1.0.27", + "proc-macro2 1.0.29", "quote 1.0.9", - "syn 1.0.72", + "syn 1.0.76", ] [[package]] @@ -496,7 +496,7 @@ dependencies = [ [[package]] name = "confy" version = "0.4.0" -source = "git+https://github.com/rust-cli/confy#6ae700bb0e6e2f9f7138d0c1871f604013c8f59f" +source = "git+https://github.com/rust-cli/confy#664992aecd97b4af0eda8d9d2825885662e1c6b4" dependencies = [ "directories-next", "serde", @@ -505,9 +505,9 @@ dependencies = [ [[package]] name = "const_format" -version = "0.2.14" +version = "0.2.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c75ea7d6aeb2ebd1ee24f7b7e1b23242ef5a56b3a693733b99bfbe5ef31d0306" +checksum = "59c7d3aa11be45d56befebb10f4a8785fcb62aabddf5f33638efef922e505ec9" dependencies = [ "const_format_proc_macros", ] @@ -518,7 +518,7 @@ version = "0.2.14" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "29c36c619c422113552db4eb28cddba8faa757e33f758cc3415bd2885977b591" dependencies = [ - "proc-macro2 1.0.27", + "proc-macro2 1.0.29", "quote 1.0.9", "unicode-xid 0.2.2", ] @@ -627,9 +627,9 @@ dependencies = [ [[package]] name = "cpufeatures" -version = "0.1.4" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed00c67cb5d0a7d64a44f6ad2668db7e7530311dd53ea79bcd4fb022c64911c8" +checksum = "95059428f66df56b63431fdb4e1947ed2190586af5c5a8a8b71122bdf5a7f469" dependencies = [ "libc", ] @@ -706,14 +706,14 @@ dependencies = [ [[package]] name = "criterion" version = "0.3.5" -source = "git+https://github.com/Anton-4/criterion.rs#9bd532e35486a3b321d4012534d3e97751a53f85" +source = "git+https://github.com/Anton-4/criterion.rs#3e46ad2b234e36928fb5234d36cf53b5837cbb87" dependencies = [ "atty", "cast", "clap 2.33.3", "criterion-plot", "csv", - "itertools 0.10.0", + "itertools 0.10.1", "lazy_static", "num-traits", "oorandom", @@ -731,7 +731,7 @@ dependencies = [ [[package]] name = "criterion-plot" version = "0.4.3" -source = "git+https://github.com/Anton-4/criterion.rs#9bd532e35486a3b321d4012534d3e97751a53f85" +source = "git+https://github.com/Anton-4/criterion.rs#3e46ad2b234e36928fb5234d36cf53b5837cbb87" dependencies = [ "cast", "itertools 0.9.0", @@ -745,7 +745,7 @@ checksum = "69323bff1fb41c635347b8ead484a5ca6c3f11914d784170b158d8449ab07f8e" dependencies = [ "cfg-if 0.1.10", "crossbeam-channel 0.4.4", - "crossbeam-deque 0.7.3", + "crossbeam-deque 0.7.4", "crossbeam-epoch 0.8.2", "crossbeam-queue", "crossbeam-utils 0.7.2", @@ -773,9 +773,9 @@ dependencies = [ [[package]] name = "crossbeam-deque" -version = "0.7.3" +version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9f02af974daeee82218205558e51ec8768b48cf524bd01d550abe5573a608285" +checksum = "c20ff29ded3204c5106278a81a38f4b482636ed4fa1e6cfbeef193291beb29ed" dependencies = [ "crossbeam-epoch 0.8.2", "crossbeam-utils 0.7.2", @@ -784,9 +784,9 @@ dependencies = [ [[package]] name = "crossbeam-deque" -version = "0.8.0" +version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94af6efb46fef72616855b036a624cf27ba656ffc9be1b9a3c931cfc7749a9a9" +checksum = "6455c0ca19f0d2fbf751b908d5c55c1f5cbc65e03c4225427254b46890bdde1e" dependencies = [ "cfg-if 1.0.0", "crossbeam-epoch 0.9.5", @@ -877,19 +877,19 @@ dependencies = [ [[package]] name = "ctor" -version = "0.1.20" +version = "0.1.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5e98e2ad1a782e33928b96fc3948e7c355e5af34ba4de7670fe8bac2a3b2006d" +checksum = "ccc0a48a9b826acdf4028595adc9db92caea352f7af011a3034acd172a52a0aa" dependencies = [ "quote 1.0.9", - "syn 1.0.72", + "syn 1.0.76", ] [[package]] name = "d3d12" -version = "0.4.0" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "091ed1b25fe47c7ff129fc440c23650b6114f36aa00bc7212cc8041879294428" +checksum = "2daefd788d1e96e0a9d66dee4b828b883509bc3ea9ce30665f04c3246372690c" dependencies = [ "bitflags", "libloading 0.7.0", @@ -924,10 +924,10 @@ checksum = "f0c960ae2da4de88a91b2d920c2a7233b400bc33cb28453a2987822d8392519b" dependencies = [ "fnv", "ident_case", - "proc-macro2 1.0.27", + "proc-macro2 1.0.29", "quote 1.0.9", "strsim 0.9.3", - "syn 1.0.72", + "syn 1.0.76", ] [[package]] @@ -938,10 +938,10 @@ checksum = "2c34d8efb62d0c2d7f60ece80f75e5c63c1588ba68032740494b0b9a996466e3" dependencies = [ "fnv", "ident_case", - "proc-macro2 1.0.27", + "proc-macro2 1.0.29", "quote 1.0.9", "strsim 0.10.0", - "syn 1.0.72", + "syn 1.0.76", ] [[package]] @@ -952,7 +952,7 @@ checksum = "d9b5a2f4ac4969822c62224815d069952656cadc7084fdca9751e6d959189b72" dependencies = [ "darling_core 0.10.2", "quote 1.0.9", - "syn 1.0.72", + "syn 1.0.76", ] [[package]] @@ -963,7 +963,7 @@ checksum = "ade7bff147130fe5e6d39f089c6bd49ec0250f35d70b2eebf72afdfc919f15cc" dependencies = [ "darling_core 0.13.0", "quote 1.0.9", - "syn 1.0.72", + "syn 1.0.76", ] [[package]] @@ -972,9 +972,9 @@ version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fcc3dd5e9e9c0b295d6e1e4d811fb6f157d5ffd784b8d202fc62eac8035a770b" dependencies = [ - "proc-macro2 1.0.27", + "proc-macro2 1.0.29", "quote 1.0.9", - "syn 1.0.72", + "syn 1.0.76", ] [[package]] @@ -1076,9 +1076,9 @@ checksum = "9ea835d29036a4087793836fa931b08837ad5e957da9e23886b29586fb9b6650" [[package]] name = "drm-fourcc" -version = "2.1.1" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ebbf3a5ed4671aabffefce172ff43d69c1f27dd2c6aea28e5212a70f32ada0cf" +checksum = "0aafbcdb8afc29c1a7ee5fbe53b5d62f4565b35a042a662ca9fecd0b54dae6f4" dependencies = [ "serde", ] @@ -1117,9 +1117,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6451128aa6655d880755345d085494cf7561a6bee7c8dc821e5d77e6d267ecd4" dependencies = [ "darling 0.13.0", - "proc-macro2 1.0.27", + "proc-macro2 1.0.29", "quote 1.0.9", - "syn 1.0.72", + "syn 1.0.76", ] [[package]] @@ -1134,9 +1134,9 @@ dependencies = [ [[package]] name = "env_logger" -version = "0.8.3" +version = "0.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "17392a012ea30ef05a610aa97dfb49496e71c9f676b27879922ea5bdf60d9d3f" +checksum = "a19187fea3ac7e84da7dacf48de0c45d63c6a76f9490dae389aead16c243fce3" dependencies = [ "atty", "humantime", @@ -1184,9 +1184,9 @@ checksum = "37ab347416e802de484e4d03c7316c48f1ecb56574dfd4a46a80f173ce1de04d" [[package]] name = "flate2" -version = "1.0.20" +version = "1.0.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cd3aec53de10fe96d7d8c565eb17f2c687bb5518a2ec453b5b1252964526abe0" +checksum = "80edafed416a46fb378521624fab1cfa2eb514784fd8921adbe8a8d8321da811" dependencies = [ "cfg-if 1.0.0", "crc32fast", @@ -1239,9 +1239,9 @@ checksum = "3dcaa9ae7725d12cdb85b3ad99a434db70b468c09ded17e012d86b5c1010f7a7" [[package]] name = "futures" -version = "0.3.15" +version = "0.3.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0e7e43a803dae2fa37c1f6a8fe121e1f7bf9548b4dfc0522a42f34145dadfc27" +checksum = "a12aa0eb539080d55c3f2d45a67c3b58b6b0773c1a3ca2dfec66d58c97fd66ca" dependencies = [ "futures-channel", "futures-core", @@ -1254,9 +1254,9 @@ dependencies = [ [[package]] name = "futures-channel" -version = "0.3.15" +version = "0.3.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e682a68b29a882df0545c143dc3646daefe80ba479bcdede94d5a703de2871e2" +checksum = "5da6ba8c3bb3c165d3c7319fc1cc8304facf1fb8db99c5de877183c08a273888" dependencies = [ "futures-core", "futures-sink", @@ -1264,15 +1264,15 @@ dependencies = [ [[package]] name = "futures-core" -version = "0.3.15" +version = "0.3.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0402f765d8a89a26043b889b26ce3c4679d268fa6bb22cd7c6aad98340e179d1" +checksum = "88d1c26957f23603395cd326b0ffe64124b818f4449552f960d815cfba83a53d" [[package]] name = "futures-executor" -version = "0.3.15" +version = "0.3.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "badaa6a909fac9e7236d0620a2f57f7664640c56575b71a7552fbd68deafab79" +checksum = "45025be030969d763025784f7f355043dc6bc74093e4ecc5000ca4dc50d8745c" dependencies = [ "futures-core", "futures-task", @@ -1281,40 +1281,40 @@ dependencies = [ [[package]] name = "futures-io" -version = "0.3.15" +version = "0.3.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "acc499defb3b348f8d8f3f66415835a9131856ff7714bf10dadfc4ec4bdb29a1" +checksum = "522de2a0fe3e380f1bc577ba0474108faf3f6b18321dbf60b3b9c39a75073377" [[package]] name = "futures-macro" -version = "0.3.15" +version = "0.3.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4c40298486cdf52cc00cd6d6987892ba502c7656a16a4192a9992b1ccedd121" +checksum = "18e4a4b95cea4b4ccbcf1c5675ca7c4ee4e9e75eb79944d07defde18068f79bb" dependencies = [ "autocfg 1.0.1", "proc-macro-hack", - "proc-macro2 1.0.27", + "proc-macro2 1.0.29", "quote 1.0.9", - "syn 1.0.72", + "syn 1.0.76", ] [[package]] name = "futures-sink" -version = "0.3.15" +version = "0.3.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a57bead0ceff0d6dde8f465ecd96c9338121bb7717d3e7b108059531870c4282" +checksum = "36ea153c13024fe480590b3e3d4cad89a0cfacecc24577b68f86c6ced9c2bc11" [[package]] name = "futures-task" -version = "0.3.15" +version = "0.3.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a16bef9fc1a4dddb5bee51c989e3fbba26569cbb0e31f5b303c184e3dd33dae" +checksum = "1d3d00f4eddb73e498a54394f228cd55853bdf059259e8e7bc6e69d408892e99" [[package]] name = "futures-util" -version = "0.3.15" +version = "0.3.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "feb5c238d27e2bf94ffdfd27b2c29e3df4a68c4193bb6427384259e2bf191967" +checksum = "36568465210a3a6ee45e1f165136d68671471a501e632e9a98d96872222b5481" dependencies = [ "autocfg 1.0.1", "futures-channel", @@ -1324,7 +1324,7 @@ dependencies = [ "futures-sink", "futures-task", "memchr", - "pin-project-lite 0.2.6", + "pin-project-lite 0.2.7", "pin-utils", "proc-macro-hack", "proc-macro-nested", @@ -1427,9 +1427,9 @@ dependencies = [ [[package]] name = "gfx-backend-dx12" -version = "0.9.0" +version = "0.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "61f09e9d8c2aa69e9a21eb83c0f5d1a286c6d37da011f796e550d180b08090ce" +checksum = "21506399f64a3c4d389182a89a30073856ae33eb712315456b4fd8f39ee7682a" dependencies = [ "arrayvec", "bit-set", @@ -1559,9 +1559,9 @@ version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1a5bcf1bbeab73aa4cf2fde60a846858dc036163c7c33bec309f8d17de785479" dependencies = [ - "proc-macro2 1.0.27", + "proc-macro2 1.0.29", "quote 1.0.9", - "syn 1.0.72", + "syn 1.0.76", ] [[package]] @@ -1615,7 +1615,7 @@ checksum = "ac2c82074cafb68b9e459c50c655f7eedcb92d6ee7166813802934bc6fc29fa3" dependencies = [ "ab_glyph", "crossbeam-channel 0.5.1", - "crossbeam-deque 0.8.0", + "crossbeam-deque 0.8.1", "linked-hash-map", "rayon", "rustc-hash", @@ -1623,9 +1623,9 @@ dependencies = [ [[package]] name = "glyph_brush_layout" -version = "0.2.2" +version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "15cf18cf985bd942f05e14552b63c9d08f7d0ed1ec79a977eb9747c9e065f497" +checksum = "cc32c2334f00ca5ac3695c5009ae35da21da8c62d255b5b96d56e2597a637a38" dependencies = [ "ab_glyph", "approx 0.5.0", @@ -1707,9 +1707,9 @@ dependencies = [ [[package]] name = "hermit-abi" -version = "0.1.18" +version = "0.1.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "322f4de77956e22ed0e5032c359a0f1273f1f7f0d79bfa3b8ffbc730d7fbcc5c" +checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33" dependencies = [ "libc", ] @@ -1784,12 +1784,12 @@ dependencies = [ [[package]] name = "indexmap" -version = "1.6.2" +version = "1.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "824845a0bf897a9042383849b02c1bc219c2383772efcd5c6f9766fa4b81aef3" +checksum = "bc633605454125dec4b66843673f01c7df2b89479b32e0ed634e43a91cff62a5" dependencies = [ "autocfg 1.0.1", - "hashbrown 0.9.1", + "hashbrown 0.11.2", "serde", ] @@ -1819,9 +1819,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ce046d161f000fffde5f432a0d034d0341dc152643b2598ed5bfce44c4f3a8f0" dependencies = [ "proc-macro-hack", - "proc-macro2 1.0.27", + "proc-macro2 1.0.29", "quote 1.0.9", - "syn 1.0.72", + "syn 1.0.76", "unindent", ] @@ -1851,9 +1851,9 @@ name = "inkwell_internals" version = "0.3.0" source = "git+https://github.com/rtfeldman/inkwell?tag=llvm12-0.release8#14b78d96d2dbc95694e181be66e4cd53df3fc02f" dependencies = [ - "proc-macro2 1.0.27", + "proc-macro2 1.0.29", "quote 1.0.9", - "syn 1.0.72", + "syn 1.0.76", ] [[package]] @@ -1870,9 +1870,9 @@ checksum = "90953f308a79fe6d62a4643e51f848fbfddcd05975a38e69fdf4ab86a7baf7ca" [[package]] name = "instant" -version = "0.1.9" +version = "0.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "61124eeebbd69b8190558df225adf7e4caafce0d743919e5d6b19652314ec5ec" +checksum = "bee0328b1209d157ef001c94dd85b4f8f64139adb0eac2659f4b08382b2f474d" dependencies = [ "cfg-if 1.0.0", ] @@ -1894,9 +1894,9 @@ version = "0.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "75c094e94816723ab936484666968f5b58060492e880f3c8d00489a1e244fa51" dependencies = [ - "proc-macro2 1.0.27", + "proc-macro2 1.0.29", "quote 1.0.9", - "syn 1.0.72", + "syn 1.0.76", ] [[package]] @@ -1919,18 +1919,18 @@ dependencies = [ [[package]] name = "itertools" -version = "0.10.0" +version = "0.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "37d572918e350e82412fe766d24b15e6682fb2ed2bbe018280caa810397cb319" +checksum = "69ddb889f9d0d08a67338271fa9b62996bc788c7796a5c18cf057420aaed5eaf" dependencies = [ "either", ] [[package]] name = "itoa" -version = "0.4.7" +version = "0.4.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd25036021b0de88a0aff6b850051563c6516d0bf53f8638938edbb9de732736" +checksum = "b71991ff56294aa922b450139ee08b3bfc70982c6b2c7562771375cf73542dd4" [[package]] name = "jni-sys" @@ -1940,18 +1940,18 @@ checksum = "8eaf4bc02d17cbdd7ff4c7438cafcdf7fb9a4613313ad11b4f8fefe7d3fa0130" [[package]] name = "jobserver" -version = "0.1.22" +version = "0.1.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "972f5ae5d1cb9c6ae417789196c803205313edde988685da5e3aae0827b9e7fd" +checksum = "af25a77299a7f711a01975c35a6a424eb6862092cc2d6c72c4ed6cbc56dfc1fa" dependencies = [ "libc", ] [[package]] name = "js-sys" -version = "0.3.51" +version = "0.3.54" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "83bdfbace3a0e81a4253f73b49e960b053e396a11012cbd49b9b74d6a2b67062" +checksum = "1866b355d9c878e5e607473cbe3f63282c0b7aad2db1dbebf55076c686918254" dependencies = [ "wasm-bindgen", ] @@ -2002,9 +2002,9 @@ checksum = "3576a87f2ba00f6f106fdfcd16db1d698d648a26ad8e0573cad8537c3c362d2a" [[package]] name = "libc" -version = "0.2.96" +version = "0.2.101" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5600b4e6efc5421841a2138a6b082e07fe12f9aaa12783d50e5d13325b26b4fc" +checksum = "3cb00336871be5ed2c8ed44b60ae9959dc5b9f08539422ed43f09e34ecaeba21" [[package]] name = "libloading" @@ -2042,14 +2042,14 @@ dependencies = [ "lazy_static", "libc", "regex", - "semver", + "semver 0.11.0", ] [[package]] name = "lock_api" -version = "0.4.4" +version = "0.4.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0382880606dff6d15c9476c416d18690b72742aa7b605bb6dd6ec9030fbf07eb" +checksum = "712a4d093c9976e24e7dbca41db895dabcbac38eb5f4045393d17a95bdfb1109" dependencies = [ "scopeguard", ] @@ -2081,7 +2081,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c0fbfc88337168279f2e9ae06e157cfed4efd3316e14dc96ed074d4f2e6c5952" dependencies = [ "quote 1.0.9", - "syn 1.0.72", + "syn 1.0.76", ] [[package]] @@ -2158,9 +2158,9 @@ dependencies = [ [[package]] name = "metal" -version = "0.23.0" +version = "0.23.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "79d7d769f1c104b8388294d6594d491d2e21240636f5f94d37f8a0f3d7904450" +checksum = "e0514f491f4cc03632ab399ee01e2c1c1b12d3e1cf2d667c1ff5f87d6dcd2084" dependencies = [ "bitflags", "block", @@ -2170,6 +2170,12 @@ dependencies = [ "objc", ] +[[package]] +name = "minimal-lexical" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c835948974f68e0bd58636fc6c5b1fbff7b297e3046f11b3b3c18bbac012c6d" + [[package]] name = "miniz_oxide" version = "0.4.4" @@ -2290,9 +2296,9 @@ checksum = "05d1c6307dc424d0f65b9b06e94f88248e6305726b14729fd67a5e47b2dc481d" dependencies = [ "darling 0.10.2", "proc-macro-crate", - "proc-macro2 1.0.27", + "proc-macro2 1.0.29", "quote 1.0.9", - "syn 1.0.72", + "syn 1.0.76", ] [[package]] @@ -2351,11 +2357,12 @@ dependencies = [ [[package]] name = "nom" -version = "6.1.2" +version = "7.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e7413f999671bd4745a7b624bd370a569fb6bc574b23c83a3c5ed2e453f3d5e2" +checksum = "7ffd9d26838a953b4af82cbeb9f1592c6798916983959be223a7124e992742c1" dependencies = [ "memchr", + "minimal-lexical", "version_check", ] @@ -2401,9 +2408,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ffa5a33ddddfee04c0283a7653987d634e880347e96b5b2ed64de07efb59db9d" dependencies = [ "proc-macro-crate", - "proc-macro2 1.0.27", + "proc-macro2 1.0.29", "quote 1.0.9", - "syn 1.0.72", + "syn 1.0.76", ] [[package]] @@ -2469,18 +2476,18 @@ dependencies = [ [[package]] name = "object" -version = "0.26.1" +version = "0.26.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ee2766204889d09937d00bfbb7fec56bb2a199e2ade963cab19185d8a6104c7c" +checksum = "39f37e50073ccad23b6d09bcb5b263f4e76d3bb6038e4a3c08e52162ffa8abc2" dependencies = [ "memchr", ] [[package]] name = "once_cell" -version = "1.7.2" +version = "1.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af8b08b04175473088b46763e51ee54da5f9a164bc162f615b91bc179dbf15a3" +checksum = "692fcb63b64b1758029e0a96ee63e049ce8c5948587f2f7208df04625e5f6b56" [[package]] name = "oorandom" @@ -2502,9 +2509,9 @@ checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5" [[package]] name = "ordered-float" -version = "2.5.1" +version = "2.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f100fcfb41e5385e0991f74981732049f9b896821542a219420491046baafdc2" +checksum = "97c9d06878b3a851e8026ef94bf7fef9ba93062cd412601da4d9cf369b1cc62d" dependencies = [ "num-traits", ] @@ -2529,11 +2536,11 @@ dependencies = [ [[package]] name = "owned_ttf_parser" -version = "0.12.0" +version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3a3c7a20e3f122223e68eef6ca58e39bc1ea8a1d83418ba4c2c1ba189d2ee355" +checksum = "60ac8dda2e5cc09bf6480e3b3feff9783db251710c922ae9369a429c51efdeb0" dependencies = [ - "ttf-parser 0.12.1", + "ttf-parser 0.12.3", ] [[package]] @@ -2565,9 +2572,9 @@ version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0b4b5f600e60dd3a147fb57b4547033d382d1979eb087af310e91cb45a63b1f4" dependencies = [ - "proc-macro2 1.0.27", + "proc-macro2 1.0.29", "quote 1.0.9", - "syn 1.0.72", + "syn 1.0.76", ] [[package]] @@ -2578,9 +2585,9 @@ checksum = "be5e13c266502aadf83426d87d81a0f5d1ef45b8027f5a471c360abfe4bfae92" [[package]] name = "parking_lot" -version = "0.11.1" +version = "0.11.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6d7744ac029df22dca6284efe4e898991d28e3085c706c972bcd7da4a27a15eb" +checksum = "7d17b78036a60663b797adeaee46f5c9dfebb86948d1255007a1d6be0271ff99" dependencies = [ "instant", "lock_api", @@ -2589,16 +2596,16 @@ dependencies = [ [[package]] name = "parking_lot_core" -version = "0.8.3" +version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa7a782938e745763fe6907fc6ba86946d72f49fe7e21de074e08128a99fb018" +checksum = "d76e8e1493bcac0d2766c42737f34458f1c8c50c0d23bcb24ea953affb273216" dependencies = [ "backtrace", "cfg-if 1.0.0", "instant", "libc", "petgraph", - "redox_syscall 0.2.8", + "redox_syscall", "smallvec", "thread-id", "winapi 0.3.9", @@ -2637,9 +2644,9 @@ checksum = "99b8db626e31e5b81787b9783425769681b347011cc59471e33ea46d2ea0cf55" dependencies = [ "pest", "pest_meta", - "proc-macro2 1.0.27", + "proc-macro2 1.0.29", "quote 1.0.9", - "syn 1.0.72", + "syn 1.0.76", ] [[package]] @@ -2709,9 +2716,9 @@ checksum = "257b64915a082f7811703966789728173279bdebb956b143dbcd23f6f970a777" [[package]] name = "pin-project-lite" -version = "0.2.6" +version = "0.2.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc0e1f259c92177c30a4c9d177246edd0a3568b25756a977d0632cf8fa37e905" +checksum = "8d31d11c69a6b52a174b42bdc0c30e5e11670f90788b2c471c31c1d17d449443" [[package]] name = "pin-utils" @@ -2739,15 +2746,15 @@ dependencies = [ [[package]] name = "plotters-backend" -version = "0.3.0" +version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b07fffcddc1cb3a1de753caa4e4df03b79922ba43cf882acc1bdd7e8df9f4590" +checksum = "d88417318da0eaf0fdcdb51a0ee6c3bed624333bff8f946733049380be67ac1c" [[package]] name = "plotters-svg" -version = "0.3.0" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b38a02e23bd9604b842a812063aec4ef702b57989c37b655254bb61c471ad211" +checksum = "521fa9638fa597e1dc53e9412a4f9cefb01187ee1f7413076f9e6749e2885ba9" dependencies = [ "plotters-backend", ] @@ -2796,9 +2803,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "18f33027081eba0a6d8aba6d1b1c3a3be58cbb12106341c2d5759fcd9b5277e7" dependencies = [ "proc-macro-error-attr 0.4.12", - "proc-macro2 1.0.27", + "proc-macro2 1.0.29", "quote 1.0.9", - "syn 1.0.72", + "syn 1.0.76", "version_check", ] @@ -2809,9 +2816,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c" dependencies = [ "proc-macro-error-attr 1.0.4", - "proc-macro2 1.0.27", + "proc-macro2 1.0.29", "quote 1.0.9", - "syn 1.0.72", + "syn 1.0.76", "version_check", ] @@ -2821,9 +2828,9 @@ version = "0.4.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8a5b4b77fdb63c1eca72173d68d24501c54ab1269409f6b672c85deb18af69de" dependencies = [ - "proc-macro2 1.0.27", + "proc-macro2 1.0.29", "quote 1.0.9", - "syn 1.0.72", + "syn 1.0.76", "syn-mid", "version_check", ] @@ -2834,7 +2841,7 @@ version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869" dependencies = [ - "proc-macro2 1.0.27", + "proc-macro2 1.0.29", "quote 1.0.9", "version_check", ] @@ -2862,18 +2869,18 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.27" +version = "1.0.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f0d8caf72986c1a598726adc988bb5984792ef84f5ee5aa50209145ee8077038" +checksum = "b9f5105d4fdaab20335ca9565e106a5d9b82b6219b5ba735731124ac6711d23d" dependencies = [ "unicode-xid 0.2.2", ] [[package]] name = "profiling" -version = "1.0.2" +version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0a7c000c0ce9d9bb94c0fbacdf20e5087fbe652c556ffb2c9387d980e17d51fb" +checksum = "87dfd5592a8eed7e74f56ad7b125f8234763b805c30f0c7c95c486920026a6ec" [[package]] name = "ptr_meta" @@ -2890,9 +2897,9 @@ version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "16b845dbfca988fa33db069c0e230574d15a3088f147a87b64c7589eb662c9ac" dependencies = [ - "proc-macro2 1.0.27", + "proc-macro2 1.0.29", "quote 1.0.9", - "syn 1.0.72", + "syn 1.0.76", ] [[package]] @@ -2924,9 +2931,9 @@ version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "588f6378e4dd99458b60ec275b4477add41ce4fa9f64dcba6f15adccb19b50d6" dependencies = [ - "env_logger 0.8.3", + "env_logger 0.8.4", "log", - "rand 0.8.3", + "rand 0.8.4", ] [[package]] @@ -2946,9 +2953,9 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b22a693222d716a9587786f37ac3f6b4faedb5b80c23914e7303ff5a1d8016e9" dependencies = [ - "proc-macro2 1.0.27", + "proc-macro2 1.0.29", "quote 1.0.9", - "syn 1.0.72", + "syn 1.0.76", ] [[package]] @@ -2966,7 +2973,7 @@ version = "1.0.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c3d0b9745dc2debf507c8422de05d7226cc1f0644216dfdfead988f9b1ab32a7" dependencies = [ - "proc-macro2 1.0.27", + "proc-macro2 1.0.29", ] [[package]] @@ -3004,14 +3011,14 @@ dependencies = [ [[package]] name = "rand" -version = "0.8.3" +version = "0.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ef9e7e66b4468674bfcb0c81af8b7fa0bb154fa9f28eb840da5c447baeb8d7e" +checksum = "2e7573632e6454cf6b99d7aac4ccca54be06da05aca2ef7423d22d27d4d4bcd8" dependencies = [ "libc", - "rand_chacha 0.3.0", - "rand_core 0.6.2", - "rand_hc 0.3.0", + "rand_chacha 0.3.1", + "rand_core 0.6.3", + "rand_hc 0.3.1", ] [[package]] @@ -3036,12 +3043,12 @@ dependencies = [ [[package]] name = "rand_chacha" -version = "0.3.0" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e12735cf05c9e10bf21534da50a147b924d555dc7a547c42e6bb2d5b6017ae0d" +checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" dependencies = [ "ppv-lite86", - "rand_core 0.6.2", + "rand_core 0.6.3", ] [[package]] @@ -3070,9 +3077,9 @@ dependencies = [ [[package]] name = "rand_core" -version = "0.6.2" +version = "0.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "34cf66eb183df1c5876e2dcf6b13d57340741e8dc255b48e40a26de954d06ae7" +checksum = "d34f1408f55294453790c48b2f1ebbb1c5b4b7563eb1f418bcfcfdbb06ebb4e7" dependencies = [ "getrandom 0.2.3", ] @@ -3097,11 +3104,11 @@ dependencies = [ [[package]] name = "rand_hc" -version = "0.3.0" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3190ef7066a446f2e7f42e239d161e905420ccab01eb967c9eb27d21b2322a73" +checksum = "d51e9f596de227fda2ea6c84607f5558e196eeaf43c986b724ba4fb8fdf497e7" dependencies = [ - "rand_core 0.6.2", + "rand_core 0.6.3", ] [[package]] @@ -3197,7 +3204,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c06aca804d41dbc8ba42dfd964f0d01334eceb64314b9ecf7c5fad5188a06d90" dependencies = [ "autocfg 1.0.1", - "crossbeam-deque 0.8.0", + "crossbeam-deque 0.8.1", "either", "rayon-core", ] @@ -3209,7 +3216,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d78120e2c850279833f1dd3582f730c4ab53ed95aeaaaa862a2a5c71b1656d8e" dependencies = [ "crossbeam-channel 0.5.1", - "crossbeam-deque 0.8.0", + "crossbeam-deque 0.8.1", "crossbeam-utils 0.8.5", "lazy_static", "num_cpus", @@ -3226,15 +3233,9 @@ dependencies = [ [[package]] name = "redox_syscall" -version = "0.1.57" +version = "0.2.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "41cc0f7e4d5d4544e8861606a285bb08d3e70712ccc7d2b84d7c0ccfaf4b05ce" - -[[package]] -name = "redox_syscall" -version = "0.2.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "742739e41cd49414de871ea5e549afb7e2a3ac77b589bcbebe8c82fab37147fc" +checksum = "8383f39639269cde97d255a32bdb68c047337295414940c68bdd30c2e13203ff" dependencies = [ "bitflags", ] @@ -3246,7 +3247,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "528532f3d801c87aec9def2add9ca802fe569e44a544afe633765267840abe64" dependencies = [ "getrandom 0.2.3", - "redox_syscall 0.2.8", + "redox_syscall", ] [[package]] @@ -3328,9 +3329,9 @@ version = "0.6.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ba8f489f6b6d8551bb15904293c1ad58a6abafa7d8390d15f7ed05a2afcd87d5" dependencies = [ - "proc-macro2 1.0.27", + "proc-macro2 1.0.29", "quote 1.0.9", - "syn 1.0.72", + "syn 1.0.76", ] [[package]] @@ -3520,7 +3521,7 @@ dependencies = [ "colored", "confy", "copypasta", - "env_logger 0.8.3", + "env_logger 0.8.4", "futures", "glyph_brush", "im 15.0.0", @@ -3537,7 +3538,7 @@ dependencies = [ "pretty_assertions 0.6.1", "quickcheck 1.0.3", "quickcheck_macros 1.0.0", - "rand 0.8.3", + "rand 0.8.4", "roc_can", "roc_collections", "roc_fmt", @@ -3872,9 +3873,9 @@ dependencies = [ [[package]] name = "ropey" -version = "1.2.0" +version = "1.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f0f3ef16589fdbb3e8fbce3dca944c08e61f39c7f16064b21a257d68ea911a83" +checksum = "9150aff6deb25b20ed110889f070a678bcd1033e46e5e9d6fb1abeab17947f28" dependencies = [ "smallvec", ] @@ -3890,9 +3891,9 @@ dependencies = [ [[package]] name = "rustc-demangle" -version = "0.1.19" +version = "0.1.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "410f7acf3cb3a44527c5d9546bad4bf4e6c460915d5f9f2fc524498bfe8f70ce" +checksum = "7ef03e0a2b150c7a90d01faf6254c9c48a41e95fb2a8c2ac1c6f0d2b9aefc342" [[package]] name = "rustc-hash" @@ -3902,11 +3903,11 @@ checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" [[package]] name = "rustc_version" -version = "0.3.3" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f0dfe2087c51c460008730de8b57e6a320782fbfb312e1f4d520e6c6fae155ee" +checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366" dependencies = [ - "semver", + "semver 1.0.4", ] [[package]] @@ -3939,7 +3940,7 @@ dependencies = [ "scopeguard", "unicode-segmentation", "unicode-width", - "utf8parse 0.2.0", + "utf8parse", "winapi 0.3.9", ] @@ -3949,7 +3950,7 @@ version = "0.3.1" source = "git+https://github.com/rtfeldman/rustyline?tag=prompt-fix#a6b8a20d2bf5c3793d7367848be2f4afec2f0d99" dependencies = [ "quote 1.0.9", - "syn 1.0.72", + "syn 1.0.76", ] [[package]] @@ -3994,6 +3995,12 @@ dependencies = [ "semver-parser", ] +[[package]] +name = "semver" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "568a8e6258aa33c13358f81fd834adb854c6f7c9468520910a9b1e8fac068012" + [[package]] name = "semver-parser" version = "0.10.2" @@ -4005,9 +4012,9 @@ dependencies = [ [[package]] name = "serde" -version = "1.0.126" +version = "1.0.130" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec7505abeacaec74ae4778d9d9328fe5a5d04253220a85c4ee022239fc996d03" +checksum = "f12d06de37cf59146fbdecab66aa99f9fe4f78722e3607577a5375d66bd0c913" dependencies = [ "serde_derive", ] @@ -4035,9 +4042,9 @@ dependencies = [ [[package]] name = "serde_cbor" -version = "0.11.1" +version = "0.11.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e18acfa2f90e8b735b2836ab8d538de304cbb6729a7360729ea5a895d15a622" +checksum = "2bef2ebfde456fb76bbcf9f59315333decc4fda0b2b44b420243c11e0f5ec1f5" dependencies = [ "half", "serde", @@ -4045,20 +4052,20 @@ dependencies = [ [[package]] name = "serde_derive" -version = "1.0.126" +version = "1.0.130" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "963a7dbc9895aeac7ac90e74f34a5d5261828f79df35cbed41e10189d3804d43" +checksum = "d7bc1a1ab1961464eae040d96713baa5a724a8152c1222492465b54322ec508b" dependencies = [ - "proc-macro2 1.0.27", + "proc-macro2 1.0.29", "quote 1.0.9", - "syn 1.0.72", + "syn 1.0.76", ] [[package]] name = "serde_json" -version = "1.0.64" +version = "1.0.67" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "799e97dc9fdae36a5c8b8f2cae9ce2ee9fdce2058c57a93e6099d919fd982f79" +checksum = "a7f9e390c27c3c0ce8bc5d725f6e4d30a29d26659494aa4b17535f7522c5c950" dependencies = [ "itoa", "ryu", @@ -4067,12 +4074,12 @@ dependencies = [ [[package]] name = "serde_yaml" -version = "0.8.17" +version = "0.8.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "15654ed4ab61726bf918a39cb8d98a2e2995b002387807fa6ba58fdf7f59bb23" +checksum = "ad104641f3c958dab30eb3010e834c2622d1f3f4c530fef1dee20ad9485f3c09" dependencies = [ "dtoa", - "linked-hash-map", + "indexmap", "serde", "yaml-rust", ] @@ -4094,9 +4101,9 @@ version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b2acd6defeddb41eb60bb468f8825d0cfd0c2a76bc03bfd235b6a1dc4f6a1ad5" dependencies = [ - "proc-macro2 1.0.27", + "proc-macro2 1.0.29", "quote 1.0.9", - "syn 1.0.72", + "syn 1.0.76", ] [[package]] @@ -4113,9 +4120,9 @@ dependencies = [ [[package]] name = "sha2" -version = "0.9.5" +version = "0.9.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b362ae5752fd2137731f9fa25fd4d9058af34666ca1966fb969119cc35719f12" +checksum = "9204c41a1597a8c5af23c82d1c921cb01ec0a4c59e07a9c7306062829a3903f3" dependencies = [ "block-buffer 0.9.0", "cfg-if 1.0.0", @@ -4126,9 +4133,9 @@ dependencies = [ [[package]] name = "siphasher" -version = "0.3.5" +version = "0.3.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cbce6d4507c7e4a3962091436e56e95290cb71fa302d0d270e32130b75fbff27" +checksum = "533494a8f9b724d33625ab53c6c4800f7cc445895924a8ef649222dcb76e938b" [[package]] name = "sized-chunks" @@ -4152,15 +4159,15 @@ dependencies = [ [[package]] name = "slab" -version = "0.4.3" +version = "0.4.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f173ac3d1a7e3b28003f40de0b5ce7fe2710f9b9dc3fc38664cebee46b3b6527" +checksum = "c307a32c1c5c437f38c7fd45d753050587732ba8628319fbdf12a7e289ccc590" [[package]] name = "slotmap" -version = "0.4.0" +version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c46a3482db8f247956e464d783693ece164ca056e6e67563ee5505bdb86452cd" +checksum = "6bf34684c5767b87de9119790e92e9a1d60056be2ceeaf16a8e6ef13082aeab1" [[package]] name = "smallvec" @@ -4188,12 +4195,29 @@ dependencies = [ ] [[package]] -name = "smithay-clipboard" -version = "0.6.3" +name = "smithay-client-toolkit" +version = "0.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "06384dfaf645908220d976ae24ed39f6cf92efecb0225ea0a948e403014de527" +checksum = "ec783683499a2cfc85b6df3d04f83b1907b5cbd98a1aed44667dbdf1eac4e64c" dependencies = [ - "smithay-client-toolkit", + "bitflags", + "dlib 0.5.0", + "lazy_static", + "log", + "memmap2 0.2.3", + "nix 0.20.0", + "wayland-client", + "wayland-cursor", + "wayland-protocols", +] + +[[package]] +name = "smithay-clipboard" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "986c5b4a7bd4f50d4c51f81f844745535cb488360f9cf63293780b109b9295f3" +dependencies = [ + "smithay-client-toolkit 0.14.0", "wayland-client", ] @@ -4214,9 +4238,9 @@ version = "0.6.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1508efa03c362e23817f96cde18abed596a25219a8b2c66e8db33c03543d315b" dependencies = [ - "proc-macro2 1.0.27", + "proc-macro2 1.0.29", "quote 1.0.9", - "syn 1.0.72", + "syn 1.0.76", ] [[package]] @@ -4263,9 +4287,9 @@ dependencies = [ [[package]] name = "strip-ansi-escapes" -version = "0.1.0" +version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9d63676e2abafa709460982ddc02a3bb586b6d15a49b75c212e06edd3933acee" +checksum = "011cbb39cf7c1f62871aea3cc46e5817b0937b49e9447370c93cacbe93a766d8" dependencies = [ "vte", ] @@ -4295,11 +4319,11 @@ dependencies = [ [[package]] name = "syn" -version = "1.0.72" +version = "1.0.76" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1e8cdbefb79a9a5a65e0db8b47b723ee907b7c7f8496c76a1770b5c310bab82" +checksum = "c6f107db402c2c2055242dbf4d2af0e69197202e9faacbef9571bbe47f5a1b84" dependencies = [ - "proc-macro2 1.0.27", + "proc-macro2 1.0.29", "quote 1.0.9", "unicode-xid 0.2.2", ] @@ -4310,20 +4334,20 @@ version = "0.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "baa8e7560a164edb1621a55d18a0c59abf49d360f47aa7b821061dd7eea7fac9" dependencies = [ - "proc-macro2 1.0.27", + "proc-macro2 1.0.29", "quote 1.0.9", - "syn 1.0.72", + "syn 1.0.76", ] [[package]] name = "synstructure" -version = "0.12.4" +version = "0.12.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b834f2d66f734cb897113e34aaff2f1ab4719ca946f9a7358dba8f8064148701" +checksum = "474aaa926faa1603c40b7885a9eaea29b444d1cb2850cb7c0e37bb1a4182f4fa" dependencies = [ - "proc-macro2 1.0.27", + "proc-macro2 1.0.29", "quote 1.0.9", - "syn 1.0.72", + "syn 1.0.76", "unicode-xid 0.2.2", ] @@ -4341,8 +4365,8 @@ checksum = "dac1c663cfc93810f88aed9b8941d48cabf856a1b111c29a40439018d870eb22" dependencies = [ "cfg-if 1.0.0", "libc", - "rand 0.8.3", - "redox_syscall 0.2.8", + "rand 0.8.4", + "redox_syscall", "remove_dir_all", "winapi 0.3.9", ] @@ -4434,9 +4458,9 @@ name = "test_mono_macros" version = "0.1.0" dependencies = [ "darling 0.10.2", - "proc-macro2 1.0.27", + "proc-macro2 1.0.29", "quote 1.0.9", - "syn 1.0.72", + "syn 1.0.76", ] [[package]] @@ -4450,32 +4474,32 @@ dependencies = [ [[package]] name = "thiserror" -version = "1.0.25" +version = "1.0.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa6f76457f59514c7eeb4e59d891395fab0b2fd1d40723ae737d64153392e9c6" +checksum = "602eca064b2d83369e2b2f34b09c70b605402801927c65c11071ac911d299b88" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.25" +version = "1.0.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a36768c0fbf1bb15eca10defa29526bda730a2376c2ab4393ccfa16fb1a318d" +checksum = "bad553cc2c78e8de258400763a647e80e6d1b31ee237275d756f6836d204494c" dependencies = [ - "proc-macro2 1.0.27", + "proc-macro2 1.0.29", "quote 1.0.9", - "syn 1.0.72", + "syn 1.0.76", ] [[package]] name = "thread-id" -version = "3.3.0" +version = "4.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c7fbf4c9d56b320106cd64fd024dadfa0be7cb4706725fc44a7d7ce952d820c1" +checksum = "5fdfe0627923f7411a43ec9ec9c39c3a9b4151be313e0922042581fb6c9b717f" dependencies = [ "libc", - "redox_syscall 0.1.57", + "redox_syscall", "winapi 0.3.9", ] @@ -4536,7 +4560,7 @@ checksum = "09adeb8c97449311ccd28a427f96fb563e7fd31aabf994189879d9da2394b89d" dependencies = [ "cfg-if 1.0.0", "log", - "pin-project-lite 0.2.6", + "pin-project-lite 0.2.7", "tracing-attributes", "tracing-core", ] @@ -4547,9 +4571,9 @@ version = "0.1.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c42e6fa53307c8a17e4ccd4dc81cf5ec38db9209f59b222210375b54ee40d1e2" dependencies = [ - "proc-macro2 1.0.27", + "proc-macro2 1.0.29", "quote 1.0.9", - "syn 1.0.72", + "syn 1.0.76", ] [[package]] @@ -4569,18 +4593,18 @@ checksum = "3e5d7cd7ab3e47dda6e56542f4bbf3824c15234958c6e1bd6aaa347e93499fdc" [[package]] name = "ttf-parser" -version = "0.12.1" +version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2fc71742ead70703a55d184f82087302f2f9ffa3793e64db46a78bf75dd723f4" +checksum = "7ae2f58a822f08abdaf668897e96a5656fe72f5a9ce66422423e8849384872e6" [[package]] name = "twox-hash" -version = "1.6.0" +version = "1.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "04f8ab788026715fa63b31960869617cba39117e520eb415b0139543e325ab59" +checksum = "1f559b464de2e2bdabcac6a210d12e9b5a5973c251e102c44c585c71d51bd78e" dependencies = [ - "cfg-if 0.1.10", - "rand 0.7.3", + "cfg-if 1.0.0", + "rand 0.8.4", "static_assertions", ] @@ -4592,9 +4616,9 @@ checksum = "0685c84d5d54d1c26f7d3eb96cd41550adb97baed141a761cf335d3d33bcd0ae" [[package]] name = "typenum" -version = "1.13.0" +version = "1.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "879f6906492a7cd215bfa4cf595b600146ccfac0c79bcbd1f3000162af5e8b06" +checksum = "b63708a265f51345575b27fe43f9500ad611579e764c79edbc2037b1121959ec" [[package]] name = "typetag" @@ -4615,9 +4639,9 @@ version = "0.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "504f9626fe6cc1c376227864781996668e15c1ff251d222f63ef17f310bf1fec" dependencies = [ - "proc-macro2 1.0.27", + "proc-macro2 1.0.29", "quote 1.0.9", - "syn 1.0.72", + "syn 1.0.76", ] [[package]] @@ -4637,9 +4661,9 @@ dependencies = [ [[package]] name = "unicode-segmentation" -version = "1.7.1" +version = "1.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bb0d2e7be6ae3a5fa87eed5fb451aff96f2573d2694942e40543ae0bbe19c796" +checksum = "8895849a949e7845e06bd6dc1aa51731a103c42707010a5b591c0038fb73385b" [[package]] name = "unicode-width" @@ -4665,12 +4689,6 @@ version = "0.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f14ee04d9415b52b3aeab06258a3f07093182b88ba0f9b8d203f211a7a7d41c7" -[[package]] -name = "utf8parse" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8772a4ccbb4e89959023bc5b7cb8623a795caa7092d99f3aa9501b9484d4557d" - [[package]] name = "utf8parse" version = "0.2.0" @@ -4723,11 +4741,23 @@ checksum = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d" [[package]] name = "vte" -version = "0.3.3" +version = "0.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4f42f536e22f7fcbb407639765c8fd78707a33109301f834a594758bedd6e8cf" +checksum = "6cbce692ab4ca2f1f3047fcf732430249c0e971bfdd2b234cf2c47ad93af5983" dependencies = [ - "utf8parse 0.1.1", + "arrayvec", + "utf8parse", + "vte_generate_state_changes", +] + +[[package]] +name = "vte_generate_state_changes" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d257817081c7dffcdbab24b9e62d2def62e2ff7d00b1c20062551e6cccc145ff" +dependencies = [ + "proc-macro2 1.0.29", + "quote 1.0.9", ] [[package]] @@ -4755,9 +4785,9 @@ checksum = "fd6fbd9a79829dd1ad0cc20627bf1ed606756a7f77edff7b66b7064f9cb327c6" [[package]] name = "wasm-bindgen" -version = "0.2.74" +version = "0.2.77" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d54ee1d4ed486f78874278e63e4069fc1ab9f6a18ca492076ffb90c5eb2997fd" +checksum = "5e68338db6becec24d3c7977b5bf8a48be992c934b5d07177e3931f5dc9b076c" dependencies = [ "cfg-if 1.0.0", "wasm-bindgen-macro", @@ -4765,24 +4795,24 @@ dependencies = [ [[package]] name = "wasm-bindgen-backend" -version = "0.2.74" +version = "0.2.77" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3b33f6a0694ccfea53d94db8b2ed1c3a8a4c86dd936b13b9f0a15ec4a451b900" +checksum = "f34c405b4f0658583dba0c1c7c9b694f3cac32655db463b56c254a1c75269523" dependencies = [ "bumpalo", "lazy_static", "log", - "proc-macro2 1.0.27", + "proc-macro2 1.0.29", "quote 1.0.9", - "syn 1.0.72", + "syn 1.0.76", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-futures" -version = "0.4.24" +version = "0.4.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5fba7978c679d53ce2d0ac80c8c175840feb849a161664365d1287b41f2e67f1" +checksum = "a87d738d4abc4cf22f6eb142f5b9a81301331ee3c767f2fef2fda4e325492060" dependencies = [ "cfg-if 1.0.0", "js-sys", @@ -4792,9 +4822,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro" -version = "0.2.74" +version = "0.2.77" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "088169ca61430fe1e58b8096c24975251700e7b1f6fd91cc9d59b04fb9b18bd4" +checksum = "b9d5a6580be83b19dc570a8f9c324251687ab2184e57086f71625feb57ec77c8" dependencies = [ "quote 1.0.9", "wasm-bindgen-macro-support", @@ -4802,22 +4832,22 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.74" +version = "0.2.77" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "be2241542ff3d9f241f5e2cb6dd09b37efe786df8851c54957683a49f0987a97" +checksum = "e3775a030dc6f5a0afd8a84981a21cc92a781eb429acef9ecce476d0c9113e92" dependencies = [ - "proc-macro2 1.0.27", + "proc-macro2 1.0.29", "quote 1.0.9", - "syn 1.0.72", + "syn 1.0.76", "wasm-bindgen-backend", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-shared" -version = "0.2.74" +version = "0.2.77" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d7cff876b8f18eed75a66cf49b65e7f967cb354a7aa16003fb55dbfd25b44b4f" +checksum = "c279e376c7a8e8752a8f1eaa35b7b0bee6bb9fb0cdacfa97cc3f1f289c87e2b4" [[package]] name = "wasmer" @@ -4889,9 +4919,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1ee7b351bcc1e782997c72dc0b5b328f3ddcad4813b8ce3cac3f25ae5a4ab56b" dependencies = [ "proc-macro-error 1.0.4", - "proc-macro2 1.0.27", + "proc-macro2 1.0.29", "quote 1.0.9", - "syn 1.0.72", + "syn 1.0.76", ] [[package]] @@ -5059,9 +5089,9 @@ dependencies = [ [[package]] name = "wayland-client" -version = "0.28.5" +version = "0.28.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "06ca44d86554b85cf449f1557edc6cc7da935cc748c8e4bf1c507cbd43bae02c" +checksum = "e3ab332350e502f159382201394a78e3cc12d0f04db863429260164ea40e0355" dependencies = [ "bitflags", "downcast-rs", @@ -5075,9 +5105,9 @@ dependencies = [ [[package]] name = "wayland-commons" -version = "0.28.5" +version = "0.28.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8bd75ae380325dbcff2707f0cd9869827ea1d2d6d534cff076858d3f0460fd5a" +checksum = "a21817947c7011bbd0a27e11b17b337bfd022e8544b071a2641232047966fbda" dependencies = [ "nix 0.20.0", "once_cell", @@ -5087,9 +5117,9 @@ dependencies = [ [[package]] name = "wayland-cursor" -version = "0.28.5" +version = "0.28.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b37e5455ec72f5de555ec39b5c3704036ac07c2ecd50d0bffe02d5fe2d4e65ab" +checksum = "be610084edd1586d45e7bdd275fe345c7c1873598caa464c4fb835dee70fa65a" dependencies = [ "nix 0.20.0", "wayland-client", @@ -5098,9 +5128,9 @@ dependencies = [ [[package]] name = "wayland-protocols" -version = "0.28.5" +version = "0.28.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "95df3317872bcf9eec096c864b69aa4769a1d5d6291a5b513f8ba0af0efbd52c" +checksum = "286620ea4d803bacf61fa087a4242ee316693099ee5a140796aaba02b29f861f" dependencies = [ "bitflags", "wayland-client", @@ -5110,20 +5140,20 @@ dependencies = [ [[package]] name = "wayland-scanner" -version = "0.28.5" +version = "0.28.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "389d680d7bd67512dc9c37f39560224327038deb0f0e8d33f870900441b68720" +checksum = "ce923eb2deb61de332d1f356ec7b6bf37094dc5573952e1c8936db03b54c03f1" dependencies = [ - "proc-macro2 1.0.27", + "proc-macro2 1.0.29", "quote 1.0.9", "xml-rs", ] [[package]] name = "wayland-sys" -version = "0.28.5" +version = "0.28.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2907bd297eef464a95ba9349ea771611771aa285b932526c633dc94d5400a8e2" +checksum = "d841fca9aed7febf9bed2e9796c49bf58d4152ceda8ac949ebe00868d8f0feb8" dependencies = [ "dlib 0.5.0", "lazy_static", @@ -5162,9 +5192,9 @@ dependencies = [ [[package]] name = "wgpu-core" -version = "0.9.0" +version = "0.9.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2af5c8acd3ae5781a277cdf65a17f3a7135de5ae782775620e74ea16c9d47770" +checksum = "958a8a5e418492723ab4e7933bf6dbdf06f5dc87274ba2ae0e4f9c891aac579c" dependencies = [ "arrayvec", "bitflags", @@ -5290,7 +5320,7 @@ dependencies = [ "parking_lot", "percent-encoding", "raw-window-handle", - "smithay-client-toolkit", + "smithay-client-toolkit 0.12.3", "wayland-client", "winapi 0.3.9", "x11-dl", @@ -5357,9 +5387,9 @@ dependencies = [ [[package]] name = "xcursor" -version = "0.3.3" +version = "0.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3a9a231574ae78801646617cefd13bfe94be907c0e4fa979cfd8b770aa3c5d08" +checksum = "463705a63313cd4301184381c5e8042f0a7e9b4bb63653f216311d4ae74690b7" dependencies = [ "nom", ] @@ -5378,9 +5408,9 @@ checksum = "a67300977d3dc3f8034dae89778f502b6ba20b269527b3223ba59c0cf393bb8a" [[package]] name = "xml-rs" -version = "0.8.3" +version = "0.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b07db065a5cf61a7e4ba64f29e67db906fb1787316516c4e6e5ff0fea1efcd8a" +checksum = "d2d7d3948613f75c98fd9328cfdcc45acc4d360655289d0a7d4ec931392200a3" [[package]] name = "yaml-rust" @@ -5407,7 +5437,7 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d498dbd1fd7beb83c86709ae1c33ca50942889473473d287d56ce4770a18edfb" dependencies = [ - "proc-macro2 1.0.27", - "syn 1.0.72", + "proc-macro2 1.0.29", + "syn 1.0.76", "synstructure", ] From 597dea08d87eba86cae0ac2cdd4006e3186328a4 Mon Sep 17 00:00:00 2001 From: Anton-4 <17049058+Anton-4@users.noreply.github.com> Date: Wed, 8 Sep 2021 19:37:28 +0200 Subject: [PATCH 38/42] use small-ci for tests --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index f3e6f6051a..4b6c2b7a9c 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -11,7 +11,7 @@ env: jobs: build-fmt-clippy-test: name: fmt, clippy, test --release - runs-on: [self-hosted] + runs-on: [self-hosted, i5-4690K] timeout-minutes: 90 env: FORCE_COLOR: 1 From 4667c34326e326b2891b2249f7119bc07cf93693 Mon Sep 17 00:00:00 2001 From: Anton-4 <17049058+Anton-4@users.noreply.github.com> Date: Wed, 8 Sep 2021 19:50:00 +0200 Subject: [PATCH 39/42] change tag name for small-ci --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 4b6c2b7a9c..e52bfcf9e0 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -11,7 +11,7 @@ env: jobs: build-fmt-clippy-test: name: fmt, clippy, test --release - runs-on: [self-hosted, i5-4690K] + runs-on: [self-hosted, anton-vm-small] timeout-minutes: 90 env: FORCE_COLOR: 1 From 3cece55772d420eb1e90e9129c99d1bbfbc02470 Mon Sep 17 00:00:00 2001 From: Anton-4 <17049058+Anton-4@users.noreply.github.com> Date: Wed, 8 Sep 2021 19:56:53 +0200 Subject: [PATCH 40/42] used correct tag for CI workflow --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index e52bfcf9e0..4b6c2b7a9c 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -11,7 +11,7 @@ env: jobs: build-fmt-clippy-test: name: fmt, clippy, test --release - runs-on: [self-hosted, anton-vm-small] + runs-on: [self-hosted, i5-4690K] timeout-minutes: 90 env: FORCE_COLOR: 1 From 57a30b8e9ebe7e37a27b7e3ef7f7a3b00542535c Mon Sep 17 00:00:00 2001 From: Brian Carroll Date: Wed, 8 Sep 2021 20:16:59 +0100 Subject: [PATCH 41/42] Get rid of duplicated eval helper file --- .../tests/helpers/{eval_simple.rs => eval.rs} | 8 +- compiler/gen_wasm/tests/helpers/eval_full.rs | 265 ------------------ compiler/gen_wasm/tests/helpers/mod.rs | 2 +- 3 files changed, 5 insertions(+), 270 deletions(-) rename compiler/gen_wasm/tests/helpers/{eval_simple.rs => eval.rs} (95%) delete mode 100644 compiler/gen_wasm/tests/helpers/eval_full.rs diff --git a/compiler/gen_wasm/tests/helpers/eval_simple.rs b/compiler/gen_wasm/tests/helpers/eval.rs similarity index 95% rename from compiler/gen_wasm/tests/helpers/eval_simple.rs rename to compiler/gen_wasm/tests/helpers/eval.rs index ede52522b3..831bfc8b8c 100644 --- a/compiler/gen_wasm/tests/helpers/eval_simple.rs +++ b/compiler/gen_wasm/tests/helpers/eval.rs @@ -139,7 +139,7 @@ where let is_gen_test = true; let instance = - crate::helpers::eval_simple::helper_wasm(&arena, src, stdlib, is_gen_test, ignore_problems); + crate::helpers::eval::helper_wasm(&arena, src, stdlib, is_gen_test, ignore_problems); let main_function = instance.exports.get_function("#UserApp_main_1").unwrap(); @@ -165,7 +165,7 @@ where #[macro_export] macro_rules! assert_wasm_evals_to { ($src:expr, $expected:expr, $ty:ty, $transform:expr, $ignore_problems:expr) => { - match $crate::helpers::eval_simple::assert_wasm_evals_to_help::<$ty>($src, $ignore_problems) + match $crate::helpers::eval::assert_wasm_evals_to_help::<$ty>($src, $ignore_problems) { Err(msg) => println!("{:?}", msg), Ok(actual) => { @@ -180,7 +180,7 @@ macro_rules! assert_wasm_evals_to { $src, $expected, $ty, - $crate::helpers::eval_simple::identity, + $crate::helpers::eval::identity, false ); }; @@ -193,7 +193,7 @@ macro_rules! assert_wasm_evals_to { #[macro_export] macro_rules! assert_evals_to { ($src:expr, $expected:expr, $ty:ty) => {{ - assert_evals_to!($src, $expected, $ty, $crate::helpers::eval_simple::identity); + assert_evals_to!($src, $expected, $ty, $crate::helpers::eval::identity); }}; ($src:expr, $expected:expr, $ty:ty, $transform:expr) => { // Same as above, except with an additional transformation argument. diff --git a/compiler/gen_wasm/tests/helpers/eval_full.rs b/compiler/gen_wasm/tests/helpers/eval_full.rs deleted file mode 100644 index 64ed67f64f..0000000000 --- a/compiler/gen_wasm/tests/helpers/eval_full.rs +++ /dev/null @@ -1,265 +0,0 @@ -use roc_can::builtins::builtin_defs_map; -use roc_collections::all::{MutMap, MutSet}; -use roc_std::{RocDec, RocList, RocOrder, RocStr}; -use crate::from_wasm32_memory::FromWasm32Memory; - -fn promote_expr_to_module(src: &str) -> String { - let mut buffer = String::from("app \"test\" provides [ main ] to \"./platform\"\n\nmain =\n"); - - for line in src.lines() { - // indent the body! - buffer.push_str(" "); - buffer.push_str(line); - buffer.push('\n'); - } - - buffer -} - -#[allow(dead_code)] -pub fn helper_wasm<'a>( - arena: &'a bumpalo::Bump, - src: &str, - stdlib: &'a roc_builtins::std::StdLib, - _is_gen_test: bool, - _ignore_problems: bool, -) -> wasmer::Instance { - use std::path::{Path, PathBuf}; - - let filename = PathBuf::from("Test.roc"); - let src_dir = Path::new("fake/test/path"); - - let module_src; - let temp; - if src.starts_with("app") { - // this is already a module - module_src = src; - } else { - // this is an expression, promote it to a module - temp = promote_expr_to_module(src); - module_src = &temp; - } - - let exposed_types = MutMap::default(); - let loaded = roc_load::file::load_and_monomorphize_from_str( - arena, - filename, - module_src, - stdlib, - src_dir, - exposed_types, - 8, - builtin_defs_map, - ); - - let loaded = loaded.expect("failed to load module"); - - use roc_load::file::MonomorphizedModule; - let MonomorphizedModule { - procedures: top_procedures, - interns, - exposed_to_host, - .. - } = loaded; - - let mut procedures = MutMap::default(); - - for (key, proc) in top_procedures { - procedures.insert(key, proc); - } - - // You can comment and uncomment this block out to get more useful information - // while you're working on the wasm backend! - // { - // println!("=========== Procedures =========="); - // println!("{:?}", procedures); - // println!("=================================\n"); - - // println!("=========== Interns =========="); - // println!("{:?}", interns); - // println!("=================================\n"); - - // println!("=========== Exposed =========="); - // println!("{:?}", exposed_to_host); - // println!("=================================\n"); - // } - - let exposed_to_host = exposed_to_host.keys().copied().collect::>(); - - let env = gen_wasm::Env { - arena, - interns, - exposed_to_host, - }; - - let module_bytes = gen_wasm::build_module(&env, procedures).unwrap(); - - // for debugging (e.g. with wasm2wat) - if true { - use std::io::Write; - let mut file = - std::fs::File::create("/home/brian/Documents/roc/compiler/gen_wasm/debug.wasm") - .unwrap(); - file.write_all(&module_bytes).unwrap(); - } - - // now, do wasmer stuff - - use wasmer::{Function, Instance, Module, Store}; - - let store = Store::default(); - // let module = Module::from_file(&store, &test_wasm_path).unwrap(); - let module = Module::from_binary(&store, &module_bytes).unwrap(); - - // First, we create the `WasiEnv` - use wasmer_wasi::WasiState; - let mut wasi_env = WasiState::new("hello") - // .args(&["world"]) - // .env("KEY", "Value") - .finalize() - .unwrap(); - - // Then, we get the import object related to our WASI - // and attach it to the Wasm instance. - let mut import_object = wasi_env - .import_object(&module) - .unwrap_or_else(|_| wasmer::imports!()); - - { - let mut exts = wasmer::Exports::new(); - - let main_function = Function::new_native(&store, fake_wasm_main_function); - let ext = wasmer::Extern::Function(main_function); - exts.insert("main", ext); - - let main_function = Function::new_native(&store, wasm_roc_panic); - let ext = wasmer::Extern::Function(main_function); - exts.insert("roc_panic", ext); - - import_object.register("env", exts); - } - - Instance::new(&module, &import_object).unwrap() -} - -#[allow(dead_code)] -fn wasm_roc_panic(address: u32, tag_id: u32) { - match tag_id { - 0 => { - let mut string = ""; - - MEMORY.with(|f| { - let memory = f.borrow().unwrap(); - - let ptr: wasmer::WasmPtr = wasmer::WasmPtr::new(address); - let width = 100; - let c_ptr = (ptr.deref(memory, 0, width)).unwrap(); - - use libc::c_char; - use std::ffi::CStr; - let slice = unsafe { CStr::from_ptr(c_ptr as *const _ as *const c_char) }; - string = slice.to_str().unwrap(); - }); - - panic!("Roc failed with message: {:?}", string) - } - _ => todo!(), - } -} - -use std::cell::RefCell; - -thread_local! { - pub static MEMORY: RefCell> = RefCell::new(None); -} - -#[allow(dead_code)] -fn fake_wasm_main_function(_: u32, _: u32) -> u32 { - panic!("wasm entered the main function; this should never happen!") -} - -#[allow(dead_code)] -pub fn assert_wasm_evals_to_help(src: &str, ignore_problems: bool) -> Result -where - T: FromWasm32Memory, -{ - let arena = bumpalo::Bump::new(); - - // NOTE the stdlib must be in the arena; just taking a reference will segfault - let stdlib = arena.alloc(roc_builtins::std::standard_stdlib()); - - let is_gen_test = true; - let instance = - crate::helpers::eval_full::helper_wasm(&arena, src, stdlib, is_gen_test, ignore_problems); - - let memory = instance.exports.get_memory("memory").unwrap(); - - crate::helpers::eval_full::MEMORY.with(|f| { - *f.borrow_mut() = Some(unsafe { std::mem::transmute(memory) }); - }); - - let test_wrapper = instance.exports.get_function("test_wrapper").unwrap(); - - match test_wrapper.call(&[]) { - Err(e) => Err(format!("{:?}", e)), - Ok(result) => { - let address = match result[0] { - wasmer::Value::I32(a) => a, - _ => panic!(), - }; - - let output = ::decode( - memory, - // skip the RocCallResult tag id - address as u32 + 8, - ); - - Ok(output) - } - } -} - -#[macro_export] -macro_rules! assert_wasm_evals_to { - ($src:expr, $expected:expr, $ty:ty, $transform:expr, $ignore_problems:expr) => { - match $crate::helpers::eval_full::assert_wasm_evals_to_help::<$ty>($src, $ignore_problems) { - Err(msg) => println!("{:?}", msg), - Ok(actual) => { - #[allow(clippy::bool_assert_comparison)] - assert_eq!($transform(actual), $expected) - } - } - }; - - ($src:expr, $expected:expr, $ty:ty) => { - $crate::assert_wasm_evals_to!( - $src, - $expected, - $ty, - $crate::helpers::eval_full::identity, - false - ); - }; - - ($src:expr, $expected:expr, $ty:ty, $transform:expr) => { - $crate::assert_wasm_evals_to!($src, $expected, $ty, $transform, false); - }; -} - -#[macro_export] -macro_rules! assert_evals_to { - ($src:expr, $expected:expr, $ty:ty) => {{ - assert_evals_to!($src, $expected, $ty, $crate::helpers::eval_full::identity); - }}; - ($src:expr, $expected:expr, $ty:ty, $transform:expr) => { - // Same as above, except with an additional transformation argument. - { - $crate::assert_wasm_evals_to!($src, $expected, $ty, $transform, false); - } - }; -} - -#[allow(dead_code)] -pub fn identity(value: T) -> T { - value -} diff --git a/compiler/gen_wasm/tests/helpers/mod.rs b/compiler/gen_wasm/tests/helpers/mod.rs index 4d22ed81a3..7e538193f7 100644 --- a/compiler/gen_wasm/tests/helpers/mod.rs +++ b/compiler/gen_wasm/tests/helpers/mod.rs @@ -1,7 +1,7 @@ extern crate bumpalo; #[macro_use] -pub mod eval_simple; +pub mod eval; /// Used in the with_larger_debug_stack() function, for tests that otherwise /// run out of stack space in debug builds (but don't in --release builds) From f822251c658d5ee81998d999fe9286af6ef34288 Mon Sep 17 00:00:00 2001 From: Brian Carroll Date: Wed, 8 Sep 2021 20:38:27 +0100 Subject: [PATCH 42/42] Fix rust-fmt --- compiler/gen_wasm/tests/helpers/eval.rs | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/compiler/gen_wasm/tests/helpers/eval.rs b/compiler/gen_wasm/tests/helpers/eval.rs index 831bfc8b8c..d380c77e3a 100644 --- a/compiler/gen_wasm/tests/helpers/eval.rs +++ b/compiler/gen_wasm/tests/helpers/eval.rs @@ -165,8 +165,7 @@ where #[macro_export] macro_rules! assert_wasm_evals_to { ($src:expr, $expected:expr, $ty:ty, $transform:expr, $ignore_problems:expr) => { - match $crate::helpers::eval::assert_wasm_evals_to_help::<$ty>($src, $ignore_problems) - { + match $crate::helpers::eval::assert_wasm_evals_to_help::<$ty>($src, $ignore_problems) { Err(msg) => println!("{:?}", msg), Ok(actual) => { #[allow(clippy::bool_assert_comparison)] @@ -176,13 +175,7 @@ macro_rules! assert_wasm_evals_to { }; ($src:expr, $expected:expr, $ty:ty) => { - $crate::assert_wasm_evals_to!( - $src, - $expected, - $ty, - $crate::helpers::eval::identity, - false - ); + $crate::assert_wasm_evals_to!($src, $expected, $ty, $crate::helpers::eval::identity, false); }; ($src:expr, $expected:expr, $ty:ty, $transform:expr) => {