mirror of
https://github.com/roc-lang/roc.git
synced 2025-09-29 06:44:46 +00:00
Create types for DataSection
This commit is contained in:
parent
21988b5fd6
commit
c57d99c1ac
4 changed files with 122 additions and 31 deletions
|
@ -13,7 +13,7 @@ use roc_mono::layout::LayoutIds;
|
|||
|
||||
use crate::backend::WasmBackend;
|
||||
use crate::wasm_module::{
|
||||
Align, CodeBuilder, Export, ExportType, Global, GlobalInitValue, GlobalType, LinkingSubSection,
|
||||
Align, CodeBuilder, Export, ExportType, Global, ConstExpr, GlobalType, LinkingSubSection,
|
||||
LocalId, SymInfo, ValueType, WasmModule,
|
||||
};
|
||||
|
||||
|
@ -85,7 +85,7 @@ pub fn build_module_help<'a>(
|
|||
value_type: ValueType::I32,
|
||||
is_mutable: true,
|
||||
},
|
||||
init_value: GlobalInitValue::I32(stack_pointer_init),
|
||||
init: ConstExpr::I32(stack_pointer_init),
|
||||
});
|
||||
|
||||
Ok(backend.module)
|
||||
|
|
|
@ -9,5 +9,5 @@ pub use code_builder::{
|
|||
};
|
||||
pub use linking::{LinkingSubSection, SymInfo};
|
||||
pub use sections::{
|
||||
Export, ExportType, Global, GlobalInitValue, GlobalType, Signature, WasmModule,
|
||||
Export, ExportType, Global, ConstExpr, GlobalType, Signature, WasmModule,
|
||||
};
|
||||
|
|
|
@ -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),
|
||||
I64(i64),
|
||||
F32(f32),
|
||||
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 {
|
||||
/// Type and mutability of the global
|
||||
pub ty: GlobalType,
|
||||
pub init_value: GlobalInitValue,
|
||||
/// Initial value of the global.
|
||||
pub init: ConstExpr,
|
||||
}
|
||||
|
||||
impl Serialize for Global {
|
||||
fn serialize<T: SerialBuffer>(&self, buffer: &mut T) {
|
||||
self.ty.serialize(buffer);
|
||||
match self.init_value {
|
||||
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);
|
||||
}
|
||||
}
|
||||
self.init.serialize(buffer);
|
||||
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
|
||||
|
@ -478,11 +558,9 @@ pub struct WasmModule<'a> {
|
|||
pub start: (),
|
||||
/// Dummy placeholder for table elements. Roc does not use tables.
|
||||
pub element: (),
|
||||
/// Dummy placeholder for data count section, not yet implemented
|
||||
pub data_count: (),
|
||||
pub code: CodeSection<'a>,
|
||||
/// Dummy placeholder for data section, not yet implemented
|
||||
pub data: (),
|
||||
pub data: DataSection<'a>,
|
||||
pub linking: LinkingSection<'a>,
|
||||
pub reloc_code: RelocationSection<'a>,
|
||||
pub reloc_data: RelocationSection<'a>,
|
||||
|
@ -502,9 +580,8 @@ impl<'a> WasmModule<'a> {
|
|||
export: ExportSection::new(arena),
|
||||
start: (), // Entry function. In Roc this would be part of the platform.
|
||||
element: (), // Unused in Roc (related to table section)
|
||||
data_count: (), // TODO, related to data section
|
||||
code: CodeSection::new(arena),
|
||||
data: (), // TODO: program constants (e.g. string literals)
|
||||
data: DataSection::new(arena),
|
||||
linking: LinkingSection::new(arena),
|
||||
reloc_code: RelocationSection::new(arena, "reloc.CODE"),
|
||||
reloc_data: RelocationSection::new(arena, "reloc.DATA"),
|
||||
|
@ -553,7 +630,8 @@ impl<'a> WasmModule<'a> {
|
|||
self.element.serialize(buffer);
|
||||
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);
|
||||
|
||||
self.reloc_code.target_section_index = Some(index);
|
||||
|
|
|
@ -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 {
|
||||
fn serialize<T: SerialBuffer>(&self, buffer: &mut T) {
|
||||
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> {
|
||||
/// serialize Option as a vector of length 1 or 0
|
||||
fn serialize<T: SerialBuffer>(&self, buffer: &mut T) {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue