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::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)
|
||||||
|
|
|
@ -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,
|
||||||
};
|
};
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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) {
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue