Move WasmModule initialisation into WasmBackend

It helps to coordinate different sections with related values,
based on knowledge of Roc rather than Wasm.
This commit is contained in:
Brian Carroll 2021-11-04 20:41:23 +00:00
parent 1b91fd9533
commit 414c9e6f86
3 changed files with 58 additions and 49 deletions

View file

@ -9,8 +9,14 @@ use roc_mono::layout::Layout;
use crate::layout::WasmLayout; use crate::layout::WasmLayout;
use crate::storage::{Storage, StoredValue, StoredValueKind}; use crate::storage::{Storage, StoredValue, StoredValueKind};
use crate::wasm_module::linking::{LinkingSection, RelocationSection};
use crate::wasm_module::sections::{
CodeSection, DataMode, DataSection, DataSegment, ExportSection, FunctionSection, GlobalSection,
ImportSection, MemorySection, TypeSection, WasmModule,
};
use crate::wasm_module::{ use crate::wasm_module::{
code_builder, BlockType, CodeBuilder, LocalId, Signature, ValueType, WasmModule, code_builder, BlockType, CodeBuilder, ConstExpr, Export, ExportType, Global, GlobalType,
LocalId, Signature, ValueType,
}; };
use crate::{copy_memory, CopyMemoryConfig, Env, PTR_TYPE}; use crate::{copy_memory, CopyMemoryConfig, Env, PTR_TYPE};
@ -18,16 +24,12 @@ use crate::{copy_memory, CopyMemoryConfig, Env, PTR_TYPE};
// Follow Emscripten's example by using 1kB (4 bytes would probably do) // Follow Emscripten's example by using 1kB (4 bytes would probably do)
const UNUSED_DATA_SECTION_BYTES: u32 = 1024; const UNUSED_DATA_SECTION_BYTES: u32 = 1024;
#[derive(Clone, Copy, Debug)]
struct LabelId(u32);
pub struct WasmBackend<'a> { pub struct WasmBackend<'a> {
env: &'a Env<'a>, env: &'a Env<'a>,
// Module-level data // Module-level data
pub module: WasmModule<'a>, pub module: WasmModule<'a>,
_data_offset_map: MutMap<Literal<'a>, u32>, next_literal_addr: u32,
_data_offset_next: u32,
proc_symbols: Vec<'a, Symbol>, proc_symbols: Vec<'a, Symbol>,
// Function-level data // Function-level data
@ -41,13 +43,54 @@ pub struct WasmBackend<'a> {
impl<'a> WasmBackend<'a> { impl<'a> WasmBackend<'a> {
pub fn new(env: &'a Env<'a>, proc_symbols: Vec<'a, Symbol>) -> Self { pub fn new(env: &'a Env<'a>, proc_symbols: Vec<'a, Symbol>) -> Self {
const MEMORY_INIT_SIZE: u32 = 1024 * 1024;
let mut module = WasmModule {
types: TypeSection::new(env.arena),
import: ImportSection::new(env.arena),
function: FunctionSection::new(env.arena),
table: (), // Unused in Roc (mainly for function pointers)
memory: MemorySection::new(MEMORY_INIT_SIZE),
global: GlobalSection::new(env.arena),
export: ExportSection::new(env.arena),
start: (), // Entry function. In Roc this would be part of the platform.
element: (), // Unused in Roc (related to table section)
code: CodeSection::new(env.arena),
data: DataSection::new(env.arena),
linking: LinkingSection::new(env.arena),
reloc_code: RelocationSection::new(env.arena, "reloc.CODE"),
reloc_data: RelocationSection::new(env.arena, "reloc.DATA"),
};
module.export.entries.push(Export {
name: "memory".to_string(),
ty: ExportType::Mem,
index: 0,
});
let stack_pointer_global = Global {
ty: GlobalType {
value_type: ValueType::I32,
is_mutable: true,
},
init: ConstExpr::I32(MEMORY_INIT_SIZE as i32),
};
module.global.entries.push(stack_pointer_global);
let literal_segment = DataSegment {
mode: DataMode::Active {
offset: ConstExpr::I32(UNUSED_DATA_SECTION_BYTES as i32),
},
init: Vec::with_capacity_in(64, env.arena),
};
module.data.segments.push(literal_segment);
WasmBackend { WasmBackend {
env, env,
// Module-level data // Module-level data
module: WasmModule::new(env.arena), module,
_data_offset_map: MutMap::default(), next_literal_addr: UNUSED_DATA_SECTION_BYTES,
_data_offset_next: UNUSED_DATA_SECTION_BYTES,
proc_symbols, proc_symbols,
// Function-level data // Function-level data

View file

@ -13,8 +13,8 @@ use roc_mono::layout::LayoutIds;
use crate::backend::WasmBackend; use crate::backend::WasmBackend;
use crate::wasm_module::{ use crate::wasm_module::{
Align, CodeBuilder, Export, ExportType, Global, ConstExpr, GlobalType, LinkingSubSection, Align, CodeBuilder, Export, ExportType, LinkingSubSection, LocalId, SymInfo, ValueType,
LocalId, SymInfo, ValueType, WasmModule, WasmModule,
}; };
const PTR_SIZE: u32 = 4; const PTR_SIZE: u32 = 4;
@ -73,21 +73,6 @@ pub fn build_module_help<'a>(
let symbol_table = LinkingSubSection::SymbolTable(symbol_table_entries); let symbol_table = LinkingSubSection::SymbolTable(symbol_table_entries);
backend.module.linking.subsections.push(symbol_table); backend.module.linking.subsections.push(symbol_table);
backend.module.export.entries.push(Export {
name: "memory".to_string(),
ty: ExportType::Mem,
index: 0,
});
let stack_pointer_init = backend.module.memory.min_size().unwrap() as i32;
backend.module.global.entries.push(Global {
ty: GlobalType {
value_type: ValueType::I32,
is_mutable: true,
},
init: ConstExpr::I32(stack_pointer_init),
});
Ok(backend.module) Ok(backend.module)
} }

View file

@ -351,6 +351,7 @@ impl Serialize for ConstExpr {
buffer.encode_f64(*x); buffer.encode_f64(*x);
} }
} }
buffer.append_u8(opcodes::END);
} }
} }
@ -365,7 +366,6 @@ impl Serialize for Global {
fn serialize<T: SerialBuffer>(&self, buffer: &mut T) { fn serialize<T: SerialBuffer>(&self, buffer: &mut T) {
self.ty.serialize(buffer); self.ty.serialize(buffer);
self.init.serialize(buffer); self.init.serialize(buffer);
buffer.append_u8(opcodes::END);
} }
} }
@ -482,8 +482,8 @@ pub enum DataMode {
} }
pub struct DataSegment<'a> { pub struct DataSegment<'a> {
mode: DataMode, pub mode: DataMode,
init: Vec<'a, u8>, pub init: Vec<'a, u8>,
} }
impl Serialize for DataSegment<'_> { impl Serialize for DataSegment<'_> {
@ -503,7 +503,7 @@ impl Serialize for DataSegment<'_> {
} }
pub struct DataSection<'a> { pub struct DataSection<'a> {
segments: Vec<'a, DataSegment<'a>>, pub segments: Vec<'a, DataSegment<'a>>,
} }
impl<'a> DataSection<'a> { impl<'a> DataSection<'a> {
@ -557,25 +557,6 @@ pub struct WasmModule<'a> {
impl<'a> WasmModule<'a> { impl<'a> WasmModule<'a> {
pub const WASM_VERSION: u32 = 1; pub const WASM_VERSION: u32 = 1;
pub fn new(arena: &'a Bump) -> Self {
WasmModule {
types: TypeSection::new(arena),
import: ImportSection::new(arena),
function: FunctionSection::new(arena),
table: (), // Unused in Roc (mainly for function pointers)
memory: MemorySection::new(1024 * 1024),
global: GlobalSection::new(arena),
export: ExportSection::new(arena),
start: (), // Entry function. In Roc this would be part of the platform.
element: (), // Unused in Roc (related to table section)
code: CodeSection::new(arena),
data: DataSection::new(arena),
linking: LinkingSection::new(arena),
reloc_code: RelocationSection::new(arena, "reloc.CODE"),
reloc_data: RelocationSection::new(arena, "reloc.DATA"),
}
}
/// Create entries in the Type and Function sections for a function signature /// Create entries in the Type and Function sections for a function signature
pub fn add_function_signature(&mut self, signature: Signature<'a>) { pub fn add_function_signature(&mut self, signature: Signature<'a>) {
let index = self.types.insert(signature); let index = self.types.insert(signature);