Create types for DataSection

This commit is contained in:
Brian Carroll 2021-11-04 18:58:17 +00:00
parent 21988b5fd6
commit c57d99c1ac
4 changed files with 122 additions and 31 deletions

View file

@ -13,7 +13,7 @@ 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, GlobalInitValue, GlobalType, LinkingSubSection, Align, CodeBuilder, Export, ExportType, Global, ConstExpr, GlobalType, LinkingSubSection,
LocalId, SymInfo, ValueType, WasmModule, LocalId, SymInfo, ValueType, WasmModule,
}; };
@ -85,7 +85,7 @@ pub fn build_module_help<'a>(
value_type: ValueType::I32, value_type: ValueType::I32,
is_mutable: true, is_mutable: true,
}, },
init_value: GlobalInitValue::I32(stack_pointer_init), init: ConstExpr::I32(stack_pointer_init),
}); });
Ok(backend.module) Ok(backend.module)

View file

@ -9,5 +9,5 @@ pub use code_builder::{
}; };
pub use linking::{LinkingSubSection, SymInfo}; pub use linking::{LinkingSubSection, SymInfo};
pub use sections::{ pub use sections::{
Export, ExportType, Global, GlobalInitValue, GlobalType, Signature, WasmModule, Export, ExportType, Global, ConstExpr, GlobalType, Signature, WasmModule,
}; };

View file

@ -322,39 +322,49 @@ impl Serialize for GlobalType {
} }
} }
pub enum GlobalInitValue { /// Constant expression for initialising globals or data segments
/// Note: This is restricted for simplicity, but the spec allows arbitrary constant expressions
pub enum ConstExpr {
I32(i32), I32(i32),
I64(i64), I64(i64),
F32(f32), F32(f32),
F64(f64), F64(f64),
} }
impl Serialize for ConstExpr {
fn serialize<T: SerialBuffer>(&self, buffer: &mut T) {
match self {
ConstExpr::I32(x) => {
buffer.append_u8(opcodes::I32CONST);
buffer.encode_i32(*x);
}
ConstExpr::I64(x) => {
buffer.append_u8(opcodes::I64CONST);
buffer.encode_i64(*x);
}
ConstExpr::F32(x) => {
buffer.append_u8(opcodes::F32CONST);
buffer.encode_f32(*x);
}
ConstExpr::F64(x) => {
buffer.append_u8(opcodes::F64CONST);
buffer.encode_f64(*x);
}
}
}
}
pub struct Global { pub struct Global {
/// Type and mutability of the global
pub ty: GlobalType, pub ty: GlobalType,
pub init_value: GlobalInitValue, /// Initial value of the global.
pub init: ConstExpr,
} }
impl Serialize for Global { 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);
match self.init_value { self.init.serialize(buffer);
GlobalInitValue::I32(x) => {
buffer.append_u8(opcodes::I32CONST);
buffer.encode_i32(x);
}
GlobalInitValue::I64(x) => {
buffer.append_u8(opcodes::I64CONST);
buffer.encode_i64(x);
}
GlobalInitValue::F32(x) => {
buffer.append_u8(opcodes::F32CONST);
buffer.encode_f32(x);
}
GlobalInitValue::F64(x) => {
buffer.append_u8(opcodes::F64CONST);
buffer.encode_f64(x);
}
}
buffer.append_u8(opcodes::END); buffer.append_u8(opcodes::END);
} }
} }
@ -458,6 +468,76 @@ impl<'a> CodeSection<'a> {
} }
} }
/*******************************************************************
*
* Data section
*
*******************************************************************/
pub enum DataMode {
/// A data segment that auto-initialises on instantiation
Active { memidx: u32, offset: ConstExpr },
/// A data segment that can be initialised with the `memory.init` instruction
Passive,
}
#[repr(u8)]
enum DataModeEncoding {
DefaultMemoryActive = 0,
Passive = 1,
ExplicitMemoryActive = 2,
}
pub struct DataSegment<'a> {
mode: DataMode,
init: Vec<'a, u8>,
}
impl Serialize for DataSegment<'_> {
fn serialize<T: SerialBuffer>(&self, buffer: &mut T) {
match &self.mode {
DataMode::Active { memidx, offset } => {
if *memidx == 0 {
buffer.append_u8(DataModeEncoding::DefaultMemoryActive as u8);
} else {
buffer.append_u8(DataModeEncoding::ExplicitMemoryActive as u8);
buffer.encode_u32(*memidx);
}
offset.serialize(buffer);
}
DataMode::Passive => {
buffer.append_u8(DataModeEncoding::Passive as u8);
}
}
self.init.serialize(buffer);
}
}
pub struct DataSection<'a> {
segments: Vec<'a, DataSegment<'a>>,
}
impl<'a> DataSection<'a> {
pub fn new(arena: &'a Bump) -> Self {
DataSection {
segments: Vec::with_capacity_in(1, arena),
}
}
}
impl Serialize for DataSection<'_> {
fn serialize<T: SerialBuffer>(&self, buffer: &mut T) {
serialize_vector_section(buffer, SectionId::Data, &self.segments);
}
}
fn write_data_count_section<'a, T: SerialBuffer>(buffer: &mut T, data_section: &DataSection<'a>) {
let header_indices = write_section_header(buffer, SectionId::DataCount);
buffer.encode_u32(data_section.segments.len() as u32);
update_section_size(buffer, header_indices);
}
/******************************************************************* /*******************************************************************
* *
* Module * Module
@ -478,11 +558,9 @@ pub struct WasmModule<'a> {
pub start: (), pub start: (),
/// Dummy placeholder for table elements. Roc does not use tables. /// Dummy placeholder for table elements. Roc does not use tables.
pub element: (), pub element: (),
/// Dummy placeholder for data count section, not yet implemented
pub data_count: (),
pub code: CodeSection<'a>, pub code: CodeSection<'a>,
/// Dummy placeholder for data section, not yet implemented /// Dummy placeholder for data section, not yet implemented
pub data: (), pub data: DataSection<'a>,
pub linking: LinkingSection<'a>, pub linking: LinkingSection<'a>,
pub reloc_code: RelocationSection<'a>, pub reloc_code: RelocationSection<'a>,
pub reloc_data: RelocationSection<'a>, pub reloc_data: RelocationSection<'a>,
@ -500,11 +578,10 @@ impl<'a> WasmModule<'a> {
memory: MemorySection::new(1024 * 1024), memory: MemorySection::new(1024 * 1024),
global: GlobalSection::new(arena), global: GlobalSection::new(arena),
export: ExportSection::new(arena), export: ExportSection::new(arena),
start: (), // Entry function. In Roc this would be part of the platform. start: (), // Entry function. In Roc this would be part of the platform.
element: (), // Unused in Roc (related to table section) element: (), // Unused in Roc (related to table section)
data_count: (), // TODO, related to data section
code: CodeSection::new(arena), code: CodeSection::new(arena),
data: (), // TODO: program constants (e.g. string literals) data: DataSection::new(arena),
linking: LinkingSection::new(arena), linking: LinkingSection::new(arena),
reloc_code: RelocationSection::new(arena, "reloc.CODE"), reloc_code: RelocationSection::new(arena, "reloc.CODE"),
reloc_data: RelocationSection::new(arena, "reloc.DATA"), reloc_data: RelocationSection::new(arena, "reloc.DATA"),
@ -553,7 +630,8 @@ impl<'a> WasmModule<'a> {
self.element.serialize(buffer); self.element.serialize(buffer);
maybe_increment_section(buffer.size(), &mut prev_size, &mut index); maybe_increment_section(buffer.size(), &mut prev_size, &mut index);
self.data_count.serialize(buffer); // Data count section has no independent data, it's just to enable single-pass validation
write_data_count_section(buffer, &self.data);
maybe_increment_section(buffer.size(), &mut prev_size, &mut index); maybe_increment_section(buffer.size(), &mut prev_size, &mut index);
self.reloc_code.target_section_index = Some(index); self.reloc_code.target_section_index = Some(index);

View file

@ -13,6 +13,12 @@ impl Serialize for str {
} }
} }
impl Serialize for u8 {
fn serialize<T: SerialBuffer>(&self, buffer: &mut T) {
buffer.append_u8(*self);
}
}
impl Serialize for u32 { impl Serialize for u32 {
fn serialize<T: SerialBuffer>(&self, buffer: &mut T) { fn serialize<T: SerialBuffer>(&self, buffer: &mut T) {
buffer.encode_u32(*self); buffer.encode_u32(*self);
@ -33,6 +39,13 @@ impl<S: Serialize> Serialize for [S] {
} }
} }
impl Serialize for Vec<'_, u8> {
fn serialize<T: SerialBuffer>(&self, buffer: &mut T) {
buffer.encode_u32(self.len() as u32);
buffer.append_slice(self);
}
}
impl<S: Serialize> Serialize for Option<S> { impl<S: Serialize> Serialize for Option<S> {
/// serialize Option as a vector of length 1 or 0 /// serialize Option as a vector of length 1 or 0
fn serialize<T: SerialBuffer>(&self, buffer: &mut T) { fn serialize<T: SerialBuffer>(&self, buffer: &mut T) {