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()) } }