diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-28 14:29:10 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-28 14:29:10 +0000 |
commit | 2aa4a82499d4becd2284cdb482213d541b8804dd (patch) | |
tree | b80bf8bf13c3766139fbacc530efd0dd9d54394c /third_party/rust/parity-wasm/src/builder | |
parent | Initial commit. (diff) | |
download | firefox-upstream.tar.xz firefox-upstream.zip |
Adding upstream version 86.0.1.upstream/86.0.1upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to '')
-rw-r--r-- | third_party/rust/parity-wasm/src/builder/code.rs | 414 | ||||
-rw-r--r-- | third_party/rust/parity-wasm/src/builder/data.rs | 56 | ||||
-rw-r--r-- | third_party/rust/parity-wasm/src/builder/export.rs | 116 | ||||
-rw-r--r-- | third_party/rust/parity-wasm/src/builder/global.rs | 93 | ||||
-rw-r--r-- | third_party/rust/parity-wasm/src/builder/import.rs | 130 | ||||
-rw-r--r-- | third_party/rust/parity-wasm/src/builder/invoke.rs | 17 | ||||
-rw-r--r-- | third_party/rust/parity-wasm/src/builder/memory.rs | 85 | ||||
-rw-r--r-- | third_party/rust/parity-wasm/src/builder/misc.rs | 93 | ||||
-rw-r--r-- | third_party/rust/parity-wasm/src/builder/mod.rs | 25 | ||||
-rw-r--r-- | third_party/rust/parity-wasm/src/builder/module.rs | 598 | ||||
-rw-r--r-- | third_party/rust/parity-wasm/src/builder/table.rs | 85 |
11 files changed, 1712 insertions, 0 deletions
diff --git a/third_party/rust/parity-wasm/src/builder/code.rs b/third_party/rust/parity-wasm/src/builder/code.rs new file mode 100644 index 0000000000..305a7e7fad --- /dev/null +++ b/third_party/rust/parity-wasm/src/builder/code.rs @@ -0,0 +1,414 @@ +use alloc::vec::Vec; +use crate::elements; +use super::{ + invoke::{Invoke, Identity}, + misc::{ValueTypeBuilder, ValueTypesBuilder, OptionalValueTypeBuilder}, +}; + +/// Signature template description +pub enum Signature { + TypeReference(u32), + Inline(elements::FunctionType), +} + +/// Signature builder +pub struct SignatureBuilder<F=Identity> { + callback: F, + signature: elements::FunctionType, +} + +impl SignatureBuilder { + /// New signature builder + pub fn new() -> Self { + SignatureBuilder::with_callback(Identity) + } +} + +impl<F> SignatureBuilder<F> where F: Invoke<elements::FunctionType> { + /// New builder with callback function specified + pub fn with_callback(callback: F) -> Self { + SignatureBuilder { + callback: callback, + signature: elements::FunctionType::default(), + } + } + + /// Add argument to signature builder + pub fn with_param(mut self, value_type: elements::ValueType) -> Self { + self.signature.params_mut().push(value_type); + self + } + + /// Add multiple arguments to signature builder + pub fn with_params(mut self, value_types: Vec<elements::ValueType>) -> Self { + self.signature.params_mut().extend(value_types); + self + } + + /// Override signature return type + pub fn with_return_type(mut self, return_type: Option<elements::ValueType>) -> Self { + *self.signature.return_type_mut() = return_type; + self + } + + /// Start build new argument + pub fn param(self) -> ValueTypeBuilder<Self> { + ValueTypeBuilder::with_callback(self) + } + + /// Start build multiple arguments + pub fn params(self) -> ValueTypesBuilder<Self> { + ValueTypesBuilder::with_callback(self) + } + + /// Start building return type + pub fn return_type(self) -> OptionalValueTypeBuilder<Self> { + OptionalValueTypeBuilder::with_callback(self) + } + + /// Finish current builder + pub fn build(self) -> F::Result { + self.callback.invoke(self.signature) + } + + /// Finish current builder returning intermediate `Signature` struct + pub fn build_sig(self) -> Signature { + Signature::Inline(self.signature) + } +} + +impl<F> Invoke<Vec<elements::ValueType>> for SignatureBuilder<F> + where F: Invoke<elements::FunctionType> +{ + type Result = Self; + + fn invoke(self, args: Vec<elements::ValueType>) -> Self { + self.with_params(args) + } +} + +impl<F> Invoke<Option<elements::ValueType>> for SignatureBuilder<F> + where F: Invoke<elements::FunctionType> +{ + type Result = Self; + + fn invoke(self, arg: Option<elements::ValueType>) -> Self { + self.with_return_type(arg) + } +} + +impl<F> Invoke<elements::ValueType> for SignatureBuilder<F> + where F: Invoke<elements::FunctionType> +{ + type Result = Self; + + fn invoke(self, arg: elements::ValueType) -> Self { + self.with_param(arg) + } +} + +/// Type (signature) reference builder (for function/import/indirect call) +pub struct TypeRefBuilder<F=Identity> { + callback: F, + type_ref: u32, +} + +impl<F> TypeRefBuilder<F> where F: Invoke<u32> { + /// New builder chained with specified callback + pub fn with_callback(callback: F) -> Self { + TypeRefBuilder { + callback: callback, + type_ref: 0 + } + } + + /// Set/override of type reference + pub fn val(mut self, val: u32) -> Self { + self.type_ref = val; + self + } + + /// Finish current builder + pub fn build(self) -> F::Result { self.callback.invoke(self.type_ref) } +} + +/// Multiple signatures builder +pub struct SignaturesBuilder<F=Identity> { + callback: F, + section: Vec<Signature>, +} + +impl SignaturesBuilder { + /// New empty functions section builder + pub fn new() -> Self { + SignaturesBuilder::with_callback(Identity) + } +} + +impl<F> SignaturesBuilder<F> { + /// New builder chained with specified callback + pub fn with_callback(callback: F) -> Self { + SignaturesBuilder { + callback: callback, + section: Vec::new(), + } + } + + /// Push new signature into the builder output + pub fn with_signature(mut self, signature: Signature) -> Self { + self.section.push(signature); + self + } + + /// Start building new signature with `TypeRefBuilder` + pub fn type_ref(self) -> TypeRefBuilder<Self> { + TypeRefBuilder::with_callback(self) + } +} + +impl<F> SignaturesBuilder<F> where F: Invoke<SignatureBindings> { + /// Start building new signature with dedicated builder + pub fn signature(self) -> SignatureBuilder<Self> { + SignatureBuilder::with_callback(self) + } +} + +impl<F> Invoke<elements::FunctionType> for SignaturesBuilder<F> { + type Result = Self; + + fn invoke(self, signature: elements::FunctionType) -> Self { + self.with_signature(Signature::Inline(signature)) + } +} + +impl<F> Invoke<u32> for SignaturesBuilder<F> { + type Result = Self; + + fn invoke(self, type_ref: u32) -> Self { + self.with_signature(Signature::TypeReference(type_ref)) + } +} + +impl<F> SignaturesBuilder<F> where F: Invoke<elements::FunctionSection> { + + /// Finalize builder spawning element + pub fn build(self) -> F::Result { + let mut result = elements::FunctionSection::default(); + for f in self.section.into_iter() { + if let Signature::TypeReference(type_ref) = f { + result.entries_mut().push(elements::Func::new(type_ref)); + } else { + unreachable!(); // never possible with current generics impl-s + } + } + self.callback.invoke(result) + } +} + +/// Signature bindings +pub type SignatureBindings = Vec<Signature>; + +impl<F> SignaturesBuilder<F> where F: Invoke<SignatureBindings> { + /// Bind signature list + pub fn bind(self) -> F::Result { + self.callback.invoke(self.section) + } +} + +/// Function body (code) builder +pub struct FuncBodyBuilder<F=Identity> { + callback: F, + body: elements::FuncBody, +} + +impl<F> FuncBodyBuilder<F> { + /// New body (code) builder given the chain callback + pub fn with_callback(callback: F) -> Self { + FuncBodyBuilder { + callback: callback, + body: elements::FuncBody::new(Vec::new(), elements::Instructions::empty()), + } + } +} + +impl<F> FuncBodyBuilder<F> where F: Invoke<elements::FuncBody> { + /// Set/override entirely with FuncBody struct + pub fn with_func(mut self, func: elements::FuncBody) -> Self { + self.body = func; + self + } + + /// Extend function local list with new entries + pub fn with_locals(mut self, locals: Vec<elements::Local>) -> Self { + self.body.locals_mut().extend(locals); + self + } + + /// Set code of the function + pub fn with_instructions(mut self, instructions: elements::Instructions) -> Self { + *self.body.code_mut() = instructions; + self + } + + /// Finish current builder spawning resulting struct + pub fn build(self) -> F::Result { + self.callback.invoke(self.body) + } +} + +/// Function definition (extended structure to specify function entirely, incl. signature, mainness and code) +pub struct FunctionDefinition { + /// Is this function is start function + pub is_main: bool, + /// Signature description + pub signature: Signature, + /// Body (code) of the function + pub code: elements::FuncBody, +} + +impl Default for FunctionDefinition { + fn default() -> Self { + FunctionDefinition { + is_main: false, + signature: Signature::TypeReference(0), + code: elements::FuncBody::empty(), + } + } +} + +/// Function definition builder +pub struct FunctionBuilder<F=Identity> { + callback: F, + func: FunctionDefinition, +} + +impl FunctionBuilder { + /// New function builder + pub fn new() -> Self { + FunctionBuilder::with_callback(Identity) + } +} + +impl<F> FunctionBuilder<F> where F: Invoke<FunctionDefinition> { + /// New function builder with chained callback + pub fn with_callback(callback: F) -> Self { + FunctionBuilder { + callback: callback, + func: Default::default(), + } + } + + /// Set that this function is main entry point + pub fn main(mut self) -> Self { + self.func.is_main = true; + self + } + + /// Start signature builder of the function + pub fn signature(self) -> SignatureBuilder<Self> { + SignatureBuilder::with_callback(self) + } + + /// Override current signature entirely with new one from known struct + pub fn with_signature(mut self, signature: Signature) -> Self { + self.func.signature = signature; + self + } + + /// Start code (body) builder + pub fn body(self) -> FuncBodyBuilder<Self> { + FuncBodyBuilder::with_callback(self) + } + + /// Set body (code) for this function + pub fn with_body(mut self, body: elements::FuncBody) -> Self { + self.func.code = body; + self + } + + /// Finalize current builder spawning resulting struct in the callback + pub fn build(self) -> F::Result { + self.callback.invoke(self.func) + } +} + +impl<F> Invoke<elements::FunctionType> for FunctionBuilder<F> where F: Invoke<FunctionDefinition> { + type Result = Self; + + fn invoke(self, signature: elements::FunctionType) -> Self { + self.with_signature(Signature::Inline(signature)) + } +} + +impl<F> Invoke<u32> for FunctionBuilder<F> where F: Invoke<FunctionDefinition> { + type Result = Self; + + fn invoke(self, type_ref: u32) -> Self { + self.with_signature(Signature::TypeReference(type_ref)) + } +} + +impl<F> Invoke<elements::FuncBody> for FunctionBuilder<F> where F: Invoke<FunctionDefinition> { + type Result = Self; + + fn invoke(self, body: elements::FuncBody) -> Self::Result { + self.with_body(body) + } +} + +/// New builder of signature list +pub fn signatures() -> SignaturesBuilder { + SignaturesBuilder::new() +} + +/// New signature builder +pub fn signature() -> SignatureBuilder { + SignatureBuilder::new() +} + +/// New builder of function (signature & body) +pub fn function() -> FunctionBuilder { + FunctionBuilder::new() +} + +#[cfg(test)] +mod tests { + + use super::{signatures, function}; + use crate::elements; + + #[test] + fn example() { + let result = signatures() + .type_ref().val(1).build() + .build(); + + assert_eq!(result.entries().len(), 1); + + let result = signatures() + .signature() + .param().i32() + .param().i32() + .return_type().i64() + .build() + .bind(); + + assert_eq!(result.len(), 1); + } + + #[test] + fn func_example() { + let func = function() + .signature() + .param().i32() + .return_type().i32() + .build() + .body() + .with_instructions(elements::Instructions::empty()) + .build() + .build(); + + assert_eq!(func.code.locals().len(), 0); + assert_eq!(func.code.code().elements().len(), 1); + } +} diff --git a/third_party/rust/parity-wasm/src/builder/data.rs b/third_party/rust/parity-wasm/src/builder/data.rs new file mode 100644 index 0000000000..bca5e34f1a --- /dev/null +++ b/third_party/rust/parity-wasm/src/builder/data.rs @@ -0,0 +1,56 @@ +use alloc::vec::Vec; +use super::invoke::{Identity, Invoke}; +use crate::elements; + +/// Data segment builder +pub struct DataSegmentBuilder<F=Identity> { + callback: F, + // todo: add mapper once multiple memory refs possible + mem_index: u32, + offset: elements::InitExpr, + value: Vec<u8>, +} + +impl DataSegmentBuilder { + /// New data segment builder + pub fn new() -> Self { + DataSegmentBuilder::with_callback(Identity) + } +} + +impl<F> DataSegmentBuilder<F> { + /// New data segment builder inside the chain context + pub fn with_callback(callback: F) -> Self { + DataSegmentBuilder { + callback: callback, + mem_index: 0, + offset: elements::InitExpr::empty(), + value: Vec::new(), + } + } + + /// Set offset initialization instruction. `End` instruction will be added automatically. + pub fn offset(mut self, instruction: elements::Instruction) -> Self { + self.offset = elements::InitExpr::new(vec![instruction, elements::Instruction::End]); + self + } + + /// Set the bytes value of the segment + pub fn value(mut self, value: Vec<u8>) -> Self { + self.value = value; + self + } +} + +impl<F> DataSegmentBuilder<F> where F: Invoke<elements::DataSegment> { + /// Finish current builder, spawning resulting struct + pub fn build(self) -> F::Result { + self.callback.invoke( + elements::DataSegment::new( + self.mem_index, + Some(self.offset), + self.value, + ) + ) + } +} diff --git a/third_party/rust/parity-wasm/src/builder/export.rs b/third_party/rust/parity-wasm/src/builder/export.rs new file mode 100644 index 0000000000..a2de79c24e --- /dev/null +++ b/third_party/rust/parity-wasm/src/builder/export.rs @@ -0,0 +1,116 @@ +use alloc::{borrow::ToOwned, string::String}; +use super::invoke::{Invoke, Identity}; +use crate::elements; + +/// Export entry builder +pub struct ExportBuilder<F=Identity> { + callback: F, + field: String, + binding: elements::Internal, +} + +impl ExportBuilder { + /// New export builder + pub fn new() -> Self { + ExportBuilder::with_callback(Identity) + } +} + +impl<F> ExportBuilder<F> { + + /// New export entry builder in the specified chained context + pub fn with_callback(callback: F) -> Self { + ExportBuilder { + callback: callback, + field: String::new(), + binding: elements::Internal::Function(0), + } + } + + /// Set the field name of the export entry + pub fn field(mut self, field: &str) -> Self { + self.field = field.to_owned(); + self + } + + /// Specify the internal module mapping for this entry + pub fn with_internal(mut self, external: elements::Internal) -> Self { + self.binding = external; + self + } + + /// Start the internal builder for this export entry + pub fn internal(self) -> ExportInternalBuilder<Self> { + ExportInternalBuilder::with_callback(self) + } +} + +impl<F> ExportBuilder<F> where F: Invoke<elements::ExportEntry> { + /// Finalize export entry builder spawning the resulting struct + pub fn build(self) -> F::Result { + self.callback.invoke(elements::ExportEntry::new(self.field, self.binding)) + } +} + +impl<F> Invoke<elements::Internal> for ExportBuilder<F> { + type Result = Self; + fn invoke(self, val: elements::Internal) -> Self { + self.with_internal(val) + } +} + +/// Internal mapping builder for export entry +pub struct ExportInternalBuilder<F=Identity> { + callback: F, + binding: elements::Internal, +} + +impl<F> ExportInternalBuilder<F> where F: Invoke<elements::Internal> { + /// New export entry internal mapping for the chained context + pub fn with_callback(callback: F) -> Self { + ExportInternalBuilder{ + callback: callback, + binding: elements::Internal::Function(0), + } + } + + /// Map to function by index + pub fn func(mut self, index: u32) -> F::Result { + self.binding = elements::Internal::Function(index); + self.callback.invoke(self.binding) + } + + /// Map to memory + pub fn memory(mut self, index: u32) -> F::Result { + self.binding = elements::Internal::Memory(index); + self.callback.invoke(self.binding) + } + + /// Map to table + pub fn table(mut self, index: u32) -> F::Result { + self.binding = elements::Internal::Table(index); + self.callback.invoke(self.binding) + } + + /// Map to global + pub fn global(mut self, index: u32) -> F::Result { + self.binding = elements::Internal::Global(index); + self.callback.invoke(self.binding) + } +} + +/// New builder for export entry +pub fn export() -> ExportBuilder { + ExportBuilder::new() +} + +#[cfg(test)] +mod tests { + use super::export; + + #[test] + fn example() { + let entry = export().field("memory").internal().memory(0).build(); + assert_eq!(entry.field(), "memory"); + } +} diff --git a/third_party/rust/parity-wasm/src/builder/global.rs b/third_party/rust/parity-wasm/src/builder/global.rs new file mode 100644 index 0000000000..0b3acb8560 --- /dev/null +++ b/third_party/rust/parity-wasm/src/builder/global.rs @@ -0,0 +1,93 @@ +use super::{ + invoke::{Invoke, Identity}, + misc::ValueTypeBuilder, +}; + +use crate::elements; + +/// Global builder +pub struct GlobalBuilder<F=Identity> { + callback: F, + value_type: elements::ValueType, + is_mutable: bool, + init_expr: elements::InitExpr, +} + +impl GlobalBuilder { + /// New global builder + pub fn new() -> Self { + GlobalBuilder::with_callback(Identity) + } +} + +impl<F> GlobalBuilder<F> { + /// New global builder with callback (in chained context) + pub fn with_callback(callback: F) -> Self { + GlobalBuilder { + callback: callback, + value_type: elements::ValueType::I32, + init_expr: elements::InitExpr::empty(), + is_mutable: false, + } + } + + /// Set/override resulting global type + pub fn with_type(mut self, value_type: elements::ValueType) -> Self { + self.value_type = value_type; + self + } + + /// Set mutabilty to true + pub fn mutable(mut self) -> Self { + self.is_mutable = true; + self + } + + /// Set initialization expression instruction for this global (`end` instruction will be added automatically) + pub fn init_expr(mut self, instruction: elements::Instruction) -> Self { + self.init_expr = elements::InitExpr::new(vec![instruction, elements::Instruction::End]); + self + } + + /// Start value type builder + pub fn value_type(self) -> ValueTypeBuilder<Self> { + ValueTypeBuilder::with_callback(self) + } +} + +impl<F> GlobalBuilder<F> where F: Invoke<elements::GlobalEntry> { + /// Finalize current builder spawning resulting struct + pub fn build(self) -> F::Result { + self.callback.invoke( + elements::GlobalEntry::new( + elements::GlobalType::new(self.value_type, self.is_mutable), + self.init_expr, + ) + ) + } +} + +impl<F> Invoke<elements::ValueType> for GlobalBuilder<F> { + type Result = Self; + fn invoke(self, the_type: elements::ValueType) -> Self { + self.with_type(the_type) + } +} + +/// New builder for export entry +pub fn global() -> GlobalBuilder { + GlobalBuilder::new() +} + +#[cfg(test)] +mod tests { + use super::global; + use crate::elements; + + #[test] + fn example() { + let entry = global().value_type().i32().build(); + assert_eq!(entry.global_type().content_type(), elements::ValueType::I32); + assert_eq!(entry.global_type().is_mutable(), false); + } +} diff --git a/third_party/rust/parity-wasm/src/builder/import.rs b/third_party/rust/parity-wasm/src/builder/import.rs new file mode 100644 index 0000000000..4d9d7665fe --- /dev/null +++ b/third_party/rust/parity-wasm/src/builder/import.rs @@ -0,0 +1,130 @@ +use alloc::{borrow::ToOwned, string::String}; +use super::invoke::{Identity, Invoke}; +use crate::elements; + +/// Import builder +pub struct ImportBuilder<F=Identity> { + callback: F, + module: String, + field: String, + binding: elements::External, +} + +impl ImportBuilder { + /// New import builder + pub fn new() -> Self { + ImportBuilder::with_callback(Identity) + } +} + +impl<F> ImportBuilder<F> { + /// New import builder with callback (in chained context) + pub fn with_callback(callback: F) -> Self { + ImportBuilder { + callback: callback, + module: String::new(), + field: String::new(), + binding: elements::External::Function(0), + } + } + + /// Set/override module name + pub fn module(mut self, name: &str) -> Self { + self.module = name.to_owned(); + self + } + + /// Set/override field name + pub fn field(mut self, name: &str) -> Self { + self.field = name.to_owned(); + self + } + + /// Set/override both module name and field name + pub fn path(self, module: &str, field: &str) -> Self { + self.module(module).field(field) + } + + /// Set/override external mapping for this import + pub fn with_external(mut self, external: elements::External) -> Self { + self.binding = external; + self + } + + /// Start new external mapping builder + pub fn external(self) -> ImportExternalBuilder<Self> { + ImportExternalBuilder::with_callback(self) + } +} + +impl<F> ImportBuilder<F> where F: Invoke<elements::ImportEntry> { + /// Finalize current builder spawning the resulting struct + pub fn build(self) -> F::Result { + self.callback.invoke(elements::ImportEntry::new(self.module, self.field, self.binding)) + } +} + +impl<F> Invoke<elements::External> for ImportBuilder<F> { + type Result = Self; + fn invoke(self, val: elements::External) -> Self { + self.with_external(val) + } +} + +/// Import to external mapping builder +pub struct ImportExternalBuilder<F=Identity> { + callback: F, + binding: elements::External, +} + +impl<F> ImportExternalBuilder<F> where F: Invoke<elements::External> { + /// New import to external mapping builder with callback (in chained context) + pub fn with_callback(callback: F) -> Self { + ImportExternalBuilder{ + callback: callback, + binding: elements::External::Function(0), + } + } + + /// Function mapping with type reference + pub fn func(mut self, index: u32) -> F::Result { + self.binding = elements::External::Function(index); + self.callback.invoke(self.binding) + } + + /// Memory mapping with specified limits + pub fn memory(mut self, min: u32, max: Option<u32>) -> F::Result { + self.binding = elements::External::Memory(elements::MemoryType::new(min, max)); + self.callback.invoke(self.binding) + } + + /// Table mapping with specified limits + pub fn table(mut self, min: u32, max: Option<u32>) -> F::Result { + self.binding = elements::External::Table(elements::TableType::new(min, max)); + self.callback.invoke(self.binding) + } + + /// Global mapping with speciifed type and mutability + pub fn global(mut self, value_type: elements::ValueType, is_mut: bool) -> F::Result { + self.binding = elements::External::Global(elements::GlobalType::new(value_type, is_mut)); + self.callback.invoke(self.binding) + } +} + +/// New builder for import entry +pub fn import() -> ImportBuilder { + ImportBuilder::new() +} + +#[cfg(test)] +mod tests { + use super::import; + + #[test] + fn example() { + let entry = import().module("env").field("memory").external().memory(256, Some(256)).build(); + + assert_eq!(entry.module(), "env"); + assert_eq!(entry.field(), "memory"); + } +} diff --git a/third_party/rust/parity-wasm/src/builder/invoke.rs b/third_party/rust/parity-wasm/src/builder/invoke.rs new file mode 100644 index 0000000000..1dd6598d0d --- /dev/null +++ b/third_party/rust/parity-wasm/src/builder/invoke.rs @@ -0,0 +1,17 @@ +//! invoke helper + +/// Helper trait to allow chaining +pub trait Invoke<A> { + type Result; + + fn invoke(self, arg: A) -> Self::Result; +} + +/// Identity chain element +pub struct Identity; + +impl<A> Invoke<A> for Identity { + type Result = A; + + fn invoke(self, arg: A) -> A { arg } +}
\ No newline at end of file diff --git a/third_party/rust/parity-wasm/src/builder/memory.rs b/third_party/rust/parity-wasm/src/builder/memory.rs new file mode 100644 index 0000000000..9f7a6887ef --- /dev/null +++ b/third_party/rust/parity-wasm/src/builder/memory.rs @@ -0,0 +1,85 @@ +use alloc::vec::Vec; +use crate::elements; +use super::invoke::{Invoke, Identity}; + +/// Memory definition struct +#[derive(Debug, PartialEq)] +pub struct MemoryDefinition { + /// Minimum memory size + pub min: u32, + /// Maximum memory size + pub max: Option<u32>, + /// Memory data segments (static regions) + pub data: Vec<MemoryDataDefinition>, +} + +/// Memory static region entry definition +#[derive(Debug, PartialEq)] +pub struct MemoryDataDefinition { + /// Segment initialization expression for offset + pub offset: elements::InitExpr, + /// Raw bytes of static region + pub values: Vec<u8>, +} + +/// Memory and static regions builder +pub struct MemoryBuilder<F=Identity> { + callback: F, + memory: MemoryDefinition, +} + +impl MemoryBuilder { + /// New memory builder + pub fn new() -> Self { + MemoryBuilder::with_callback(Identity) + } +} + +impl<F> MemoryBuilder<F> where F: Invoke<MemoryDefinition> { + /// New memory builder with callback (in chained context) + pub fn with_callback(callback: F) -> Self { + MemoryBuilder { + callback: callback, + memory: Default::default(), + } + } + + /// Set/override minimum size + pub fn with_min(mut self, min: u32) -> Self { + self.memory.min = min; + self + } + + /// Set/override maximum size + pub fn with_max(mut self, max: Option<u32>) -> Self { + self.memory.max = max; + self + } + + /// Push new static region with initialized offset expression and raw bytes + pub fn with_data(mut self, index: u32, values: Vec<u8>) -> Self { + self.memory.data.push(MemoryDataDefinition { + offset: elements::InitExpr::new(vec![ + elements::Instruction::I32Const(index as i32), + elements::Instruction::End, + ]), + values: values, + }); + self + } + + /// Finalize current builder, spawning resulting struct + pub fn build(self) -> F::Result { + self.callback.invoke(self.memory) + } +} + +impl Default for MemoryDefinition { + fn default() -> Self { + MemoryDefinition { + min: 1, + max: None, + data: Vec::new(), + } + } +} diff --git a/third_party/rust/parity-wasm/src/builder/misc.rs b/third_party/rust/parity-wasm/src/builder/misc.rs new file mode 100644 index 0000000000..2b6cd2dcc5 --- /dev/null +++ b/third_party/rust/parity-wasm/src/builder/misc.rs @@ -0,0 +1,93 @@ +use alloc::vec::Vec; +use super::invoke::{Invoke, Identity}; +use crate::elements; + +pub struct ValueTypeBuilder<F=Identity> { + callback: F, +} + +impl<F> ValueTypeBuilder<F> where F: Invoke<elements::ValueType> { + pub fn with_callback(callback: F) -> Self { + ValueTypeBuilder { callback: callback } + } + + pub fn i32(self) -> F::Result { + self.callback.invoke(elements::ValueType::I32) + } + + pub fn i64(self) -> F::Result { + self.callback.invoke(elements::ValueType::I64) + } + + pub fn f32(self) -> F::Result { + self.callback.invoke(elements::ValueType::F32) + } + + pub fn f64(self) -> F::Result { + self.callback.invoke(elements::ValueType::F64) + } +} + +pub struct OptionalValueTypeBuilder<F=Identity> { + callback: F, +} + +impl<F> OptionalValueTypeBuilder<F> where F: Invoke<Option<elements::ValueType>> { + pub fn with_callback(callback: F) -> Self { + OptionalValueTypeBuilder { callback: callback } + } + + pub fn i32(self) -> F::Result { + self.callback.invoke(Some(elements::ValueType::I32)) + } + + pub fn i64(self) -> F::Result { + self.callback.invoke(Some(elements::ValueType::I64)) + } + + pub fn f32(self) -> F::Result { + self.callback.invoke(Some(elements::ValueType::F32)) + } + + pub fn f64(self) -> F::Result { + self.callback.invoke(Some(elements::ValueType::F64)) + } +} + +pub struct ValueTypesBuilder<F=Identity> { + callback: F, + value_types: Vec<elements::ValueType>, +} + +impl<F> ValueTypesBuilder<F> where F: Invoke<Vec<elements::ValueType>> { + pub fn with_callback(callback: F) -> Self { + ValueTypesBuilder { + callback: callback, + value_types: Vec::new(), + } + } + + pub fn i32(mut self) -> Self { + self.value_types.push(elements::ValueType::I32); + self + } + + pub fn i64(mut self) -> Self { + self.value_types.push(elements::ValueType::I64); + self + } + + pub fn f32(mut self) -> Self { + self.value_types.push(elements::ValueType::F32); + self + } + + pub fn f64(mut self) -> Self { + self.value_types.push(elements::ValueType::F64); + self + } + + pub fn build(self) -> F::Result { + self.callback.invoke(self.value_types) + } +} diff --git a/third_party/rust/parity-wasm/src/builder/mod.rs b/third_party/rust/parity-wasm/src/builder/mod.rs new file mode 100644 index 0000000000..b40b05efcd --- /dev/null +++ b/third_party/rust/parity-wasm/src/builder/mod.rs @@ -0,0 +1,25 @@ +//! Various builders to generate/alter wasm components + +mod invoke; +mod module; +mod code; +mod misc; +mod import; +mod memory; +mod table; +mod export; +mod global; +mod data; + +pub use self::code::{ + signatures, signature, function, SignatureBuilder, SignaturesBuilder, + FunctionBuilder, TypeRefBuilder, FuncBodyBuilder, FunctionDefinition, +}; +pub use self::data::DataSegmentBuilder; +pub use self::export::{export, ExportBuilder, ExportInternalBuilder}; +pub use self::global::{global, GlobalBuilder}; +pub use self::import::{import, ImportBuilder}; +pub use self::invoke::Identity; +pub use self::memory::MemoryBuilder; +pub use self::module::{module, from_module, ModuleBuilder}; +pub use self::table::{TableBuilder, TableDefinition, TableEntryDefinition}; diff --git a/third_party/rust/parity-wasm/src/builder/module.rs b/third_party/rust/parity-wasm/src/builder/module.rs new file mode 100644 index 0000000000..49806e126c --- /dev/null +++ b/third_party/rust/parity-wasm/src/builder/module.rs @@ -0,0 +1,598 @@ +use alloc::vec::Vec; +use crate::elements; +use super::{ + import, + export, + global, + data, + invoke::{Invoke, Identity}, + code::{self, SignaturesBuilder, FunctionBuilder}, + memory::{self, MemoryBuilder}, + table::{self, TableBuilder}, +}; + +/// Module builder +pub struct ModuleBuilder<F=Identity> { + callback: F, + module: ModuleScaffold, +} + +/// Location of the internal module function +pub struct CodeLocation { + /// Location (index in 'functions' section) of the signature + pub signature: u32, + /// Location (index in the 'code' section) of the body + pub body: u32, +} + +#[derive(Default, PartialEq)] +struct ModuleScaffold { + pub types: elements::TypeSection, + pub import: elements::ImportSection, + pub functions: elements::FunctionSection, + pub table: elements::TableSection, + pub memory: elements::MemorySection, + pub global: elements::GlobalSection, + pub export: elements::ExportSection, + pub start: Option<u32>, + pub element: elements::ElementSection, + pub code: elements::CodeSection, + pub data: elements::DataSection, + pub other: Vec<elements::Section>, +} + +impl From<elements::Module> for ModuleScaffold { + fn from(module: elements::Module) -> Self { + let mut types: Option<elements::TypeSection> = None; + let mut import: Option<elements::ImportSection> = None; + let mut funcs: Option<elements::FunctionSection> = None; + let mut table: Option<elements::TableSection> = None; + let mut memory: Option<elements::MemorySection> = None; + let mut global: Option<elements::GlobalSection> = None; + let mut export: Option<elements::ExportSection> = None; + let mut start: Option<u32> = None; + let mut element: Option<elements::ElementSection> = None; + let mut code: Option<elements::CodeSection> = None; + let mut data: Option<elements::DataSection> = None; + + let mut sections = module.into_sections(); + while let Some(section) = sections.pop() { + match section { + elements::Section::Type(sect) => { types = Some(sect); } + elements::Section::Import(sect) => { import = Some(sect); } + elements::Section::Function(sect) => { funcs = Some(sect); } + elements::Section::Table(sect) => { table = Some(sect); } + elements::Section::Memory(sect) => { memory = Some(sect); } + elements::Section::Global(sect) => { global = Some(sect); } + elements::Section::Export(sect) => { export = Some(sect); } + elements::Section::Start(index) => { start = Some(index); } + elements::Section::Element(sect) => { element = Some(sect); } + elements::Section::Code(sect) => { code = Some(sect); } + elements::Section::Data(sect) => { data = Some(sect); } + _ => {} + } + } + + ModuleScaffold { + types: types.unwrap_or_default(), + import: import.unwrap_or_default(), + functions: funcs.unwrap_or_default(), + table: table.unwrap_or_default(), + memory: memory.unwrap_or_default(), + global: global.unwrap_or_default(), + export: export.unwrap_or_default(), + start: start, + element: element.unwrap_or_default(), + code: code.unwrap_or_default(), + data: data.unwrap_or_default(), + other: sections, + } + } +} + +impl From<ModuleScaffold> for elements::Module { + fn from(module: ModuleScaffold) -> Self { + let mut sections = Vec::new(); + + let types = module.types; + if types.types().len() > 0 { + sections.push(elements::Section::Type(types)); + } + let import = module.import; + if import.entries().len() > 0 { + sections.push(elements::Section::Import(import)); + } + let functions = module.functions; + if functions.entries().len() > 0 { + sections.push(elements::Section::Function(functions)); + } + let table = module.table; + if table.entries().len() > 0 { + sections.push(elements::Section::Table(table)); + } + let memory = module.memory; + if memory.entries().len() > 0 { + sections.push(elements::Section::Memory(memory)); + } + let global = module.global; + if global.entries().len() > 0 { + sections.push(elements::Section::Global(global)); + } + let export = module.export; + if export.entries().len() > 0 { + sections.push(elements::Section::Export(export)); + } + if let Some(start) = module.start { + sections.push(elements::Section::Start(start)); + } + let element = module.element; + if element.entries().len() > 0 { + sections.push(elements::Section::Element(element)); + } + let code = module.code; + if code.bodies().len() > 0 { + sections.push(elements::Section::Code(code)); + } + let data = module.data; + if data.entries().len() > 0 { + sections.push(elements::Section::Data(data)); + } + sections.extend(module.other); + elements::Module::new(sections) + } +} + +impl ModuleBuilder { + /// New empty module builder + pub fn new() -> Self { + ModuleBuilder::with_callback(Identity) + } +} + +impl<F> ModuleBuilder<F> where F: Invoke<elements::Module> { + /// New module builder with bound callback + pub fn with_callback(callback: F) -> Self { + ModuleBuilder { + callback: callback, + module: Default::default(), + } + } + + /// Builder from raw module + pub fn with_module(mut self, module: elements::Module) -> Self { + self.module = module.into(); + self + } + + /// Fill module with sections from iterator + pub fn with_sections<I>(mut self, sections: I) -> Self + where I: IntoIterator<Item=elements::Section> + { + self.module.other.extend(sections); + self + } + + /// Add additional section + pub fn with_section(mut self, section: elements::Section) -> Self { + self.module.other.push(section); + self + } + + /// Binds to the type section, creates additional types when required + pub fn with_signatures(mut self, bindings: code::SignatureBindings) -> Self { + self.push_signatures(bindings); + self + } + + /// Push stand-alone function definition, creating sections, signature and code blocks + /// in corresponding sections. + /// `FunctionDefinition` can be build using `builder::function` builder + pub fn push_function(&mut self, func: code::FunctionDefinition) -> CodeLocation { + let signature = func.signature; + let body = func.code; + + let type_ref = self.resolve_type_ref(signature); + + self.module.functions.entries_mut().push(elements::Func::new(type_ref)); + let signature_index = self.module.functions.entries_mut().len() as u32 - 1; + self.module.code.bodies_mut().push(body); + let body_index = self.module.code.bodies_mut().len() as u32 - 1; + + if func.is_main { + self.module.start = Some(body_index); + } + + CodeLocation { + signature: signature_index, + body: body_index, + } + } + + /// Push linear memory region + pub fn push_memory(&mut self, mut memory: memory::MemoryDefinition) -> u32 { + let entries = self.module.memory.entries_mut(); + entries.push(elements::MemoryType::new(memory.min, memory.max)); + let memory_index = (entries.len() - 1) as u32; + for data in memory.data.drain(..) { + self.module.data.entries_mut() + .push(elements::DataSegment::new(memory_index, Some(data.offset), data.values)) + } + memory_index + } + + /// Push table + pub fn push_table(&mut self, mut table: table::TableDefinition) -> u32 { + let entries = self.module.table.entries_mut(); + entries.push(elements::TableType::new(table.min, table.max)); + let table_index = (entries.len() - 1) as u32; + for entry in table.elements.drain(..) { + self.module.element.entries_mut() + .push(elements::ElementSegment::new(table_index, Some(entry.offset), entry.values)) + } + table_index + } + + fn resolve_type_ref(&mut self, signature: code::Signature) -> u32 { + match signature { + code::Signature::Inline(func_type) => { + if let Some(existing_entry) = self.module.types.types().iter().enumerate().find(|(_idx, t)| { + let elements::Type::Function(ref existing) = t; + *existing == func_type + }) { + return existing_entry.0 as u32 + } + self.module.types.types_mut().push(elements::Type::Function(func_type)); + self.module.types.types().len() as u32 - 1 + } + code::Signature::TypeReference(type_ref) => { + type_ref + } + } + } + + /// Push one function signature, returning it's calling index. + /// Can create corresponding type in type section. + pub fn push_signature(&mut self, signature: code::Signature) -> u32 { + self.resolve_type_ref(signature) + } + + /// Push signatures in the module, returning corresponding indices of pushed signatures + pub fn push_signatures(&mut self, signatures: code::SignatureBindings) -> Vec<u32> { + signatures.into_iter().map(|binding| + self.resolve_type_ref(binding) + ).collect() + } + + /// Push import entry to module. Note that this does not update calling indices in + /// function bodies. + pub fn push_import(&mut self, import: elements::ImportEntry) -> u32 { + self.module.import.entries_mut().push(import); + // todo: actually update calling addresses in function bodies + // todo: also batch push + + self.module.import.entries_mut().len() as u32 - 1 + } + + /// Push export entry to module. + pub fn push_export(&mut self, export: elements::ExportEntry) -> u32 { + self.module.export.entries_mut().push(export); + self.module.export.entries_mut().len() as u32 - 1 + } + + /// Add new function using dedicated builder + pub fn function(self) -> FunctionBuilder<Self> { + FunctionBuilder::with_callback(self) + } + + /// Add new linear memory using dedicated builder + pub fn memory(self) -> MemoryBuilder<Self> { + MemoryBuilder::with_callback(self) + } + + /// Add new table using dedicated builder + pub fn table(self) -> TableBuilder<Self> { + TableBuilder::with_callback(self) + } + + /// Define functions section + pub fn functions(self) -> SignaturesBuilder<Self> { + SignaturesBuilder::with_callback(self) + } + + /// With inserted export entry + pub fn with_export(mut self, entry: elements::ExportEntry) -> Self { + self.module.export.entries_mut().push(entry); + self + } + + /// With inserted import entry + pub fn with_import(mut self, entry: elements::ImportEntry) -> Self { + self.module.import.entries_mut().push(entry); + self + } + + /// Import entry builder + /// # Examples + /// ``` + /// use parity_wasm::builder::module; + /// + /// let module = module() + /// .import() + /// .module("env") + /// .field("memory") + /// .external().memory(256, Some(256)) + /// .build() + /// .build(); + /// + /// assert_eq!(module.import_section().expect("import section to exist").entries().len(), 1); + /// ``` + pub fn import(self) -> import::ImportBuilder<Self> { + import::ImportBuilder::with_callback(self) + } + + /// With global variable + pub fn with_global(mut self, global: elements::GlobalEntry) -> Self { + self.module.global.entries_mut().push(global); + self + } + + /// With table + pub fn with_table(mut self, table: elements::TableType) -> Self { + self.module.table.entries_mut().push(table); + self + } + + /// Export entry builder + /// # Examples + /// ``` + /// use parity_wasm::builder::module; + /// use parity_wasm::elements::Instruction::*; + /// + /// let module = module() + /// .global() + /// .value_type().i32() + /// .init_expr(I32Const(0)) + /// .build() + /// .export() + /// .field("_zero") + /// .internal().global(0) + /// .build() + /// .build(); + /// + /// assert_eq!(module.export_section().expect("export section to exist").entries().len(), 1); + /// ``` + pub fn export(self) -> export::ExportBuilder<Self> { + export::ExportBuilder::with_callback(self) + } + + /// Glboal entry builder + /// # Examples + /// ``` + /// use parity_wasm::builder::module; + /// use parity_wasm::elements::Instruction::*; + /// + /// let module = module() + /// .global() + /// .value_type().i32() + /// .init_expr(I32Const(0)) + /// .build() + /// .build(); + /// + /// assert_eq!(module.global_section().expect("global section to exist").entries().len(), 1); + /// ``` + pub fn global(self) -> global::GlobalBuilder<Self> { + global::GlobalBuilder::with_callback(self) + } + + /// Add data segment to the builder + pub fn with_data_segment(mut self, segment: elements::DataSegment) -> Self { + self.module.data.entries_mut().push(segment); + self + } + + /// Data entry builder + pub fn data(self) -> data::DataSegmentBuilder<Self> { + data::DataSegmentBuilder::with_callback(self) + } + + /// Build module (final step) + pub fn build(self) -> F::Result { + self.callback.invoke(self.module.into()) + } +} + +impl<F> Invoke<elements::FunctionSection> for ModuleBuilder<F> + where F: Invoke<elements::Module> +{ + type Result = Self; + + fn invoke(self, section: elements::FunctionSection) -> Self { + self.with_section(elements::Section::Function(section)) + } +} + +impl<F> Invoke<code::SignatureBindings> for ModuleBuilder<F> + where F: Invoke<elements::Module> +{ + type Result = Self; + + fn invoke(self, bindings: code::SignatureBindings) -> Self { + self.with_signatures(bindings) + } +} + + +impl<F> Invoke<code::FunctionDefinition> for ModuleBuilder<F> + where F: Invoke<elements::Module> +{ + type Result = Self; + + fn invoke(self, def: code::FunctionDefinition) -> Self { + let mut b = self; + b.push_function(def); + b + } +} + +impl<F> Invoke<memory::MemoryDefinition> for ModuleBuilder<F> + where F: Invoke<elements::Module> +{ + type Result = Self; + + fn invoke(self, def: memory::MemoryDefinition) -> Self { + let mut b = self; + b.push_memory(def); + b + } +} + +impl<F> Invoke<table::TableDefinition> for ModuleBuilder<F> + where F: Invoke<elements::Module> +{ + type Result = Self; + + fn invoke(self, def: table::TableDefinition) -> Self { + let mut b = self; + b.push_table(def); + b + } +} + +impl<F> Invoke<elements::ImportEntry> for ModuleBuilder<F> + where F: Invoke<elements::Module> +{ + type Result = Self; + + fn invoke(self, entry: elements::ImportEntry) -> Self::Result { + self.with_import(entry) + } +} + +impl<F> Invoke<elements::ExportEntry> for ModuleBuilder<F> + where F: Invoke<elements::Module> +{ + type Result = Self; + + fn invoke(self, entry: elements::ExportEntry) -> Self::Result { + self.with_export(entry) + } +} + +impl<F> Invoke<elements::GlobalEntry> for ModuleBuilder<F> + where F: Invoke<elements::Module> +{ + type Result = Self; + + fn invoke(self, entry: elements::GlobalEntry) -> Self::Result { + self.with_global(entry) + } +} + +impl<F> Invoke<elements::DataSegment> for ModuleBuilder<F> + where F: Invoke<elements::Module> +{ + type Result = Self; + + fn invoke(self, segment: elements::DataSegment) -> Self { + self.with_data_segment(segment) + } +} + +/// Start new module builder +/// # Examples +/// +/// ``` +/// use parity_wasm::builder; +/// +/// let module = builder::module() +/// .function() +/// .signature().param().i32().build() +/// .body().build() +/// .build() +/// .build(); +/// +/// assert_eq!(module.type_section().expect("type section to exist").types().len(), 1); +/// assert_eq!(module.function_section().expect("function section to exist").entries().len(), 1); +/// assert_eq!(module.code_section().expect("code section to exist").bodies().len(), 1); +/// ``` +pub fn module() -> ModuleBuilder { + ModuleBuilder::new() +} + +/// Start builder to extend existing module +pub fn from_module(module: elements::Module) -> ModuleBuilder { + ModuleBuilder::new().with_module(module) +} + +#[cfg(test)] +mod tests { + + use crate::elements; + use super::module; + + #[test] + fn smoky() { + let module = module().build(); + assert_eq!(module.sections().len(), 0); + } + + #[test] + fn functions() { + let module = module() + .function() + .signature().param().i32().build() + .body().build() + .build() + .build(); + + assert_eq!(module.type_section().expect("type section to exist").types().len(), 1); + assert_eq!(module.function_section().expect("function section to exist").entries().len(), 1); + assert_eq!(module.code_section().expect("code section to exist").bodies().len(), 1); + } + + #[test] + fn export() { + let module = module() + .export().field("call").internal().func(0).build() + .build(); + + assert_eq!(module.export_section().expect("export section to exist").entries().len(), 1); + } + + #[test] + fn global() { + let module = module() + .global().value_type().i64().mutable().init_expr(elements::Instruction::I64Const(5)).build() + .build(); + + assert_eq!(module.global_section().expect("global section to exist").entries().len(), 1); + } + + #[test] + fn data() { + let module = module() + .data() + .offset(elements::Instruction::I32Const(16)) + .value(vec![0u8, 15, 10, 5, 25]) + .build() + .build(); + + assert_eq!(module.data_section().expect("data section to exist").entries().len(), 1); + } + + #[test] + fn reuse_types() { + let module = module() + .function() + .signature().param().i32().build() + .body().build() + .build() + .function() + .signature().param().i32().build() + .body().build() + .build() + .build(); + + assert_eq!(module.type_section().expect("type section failed").types().len(), 1); + } + } diff --git a/third_party/rust/parity-wasm/src/builder/table.rs b/third_party/rust/parity-wasm/src/builder/table.rs new file mode 100644 index 0000000000..29bbe2d2dc --- /dev/null +++ b/third_party/rust/parity-wasm/src/builder/table.rs @@ -0,0 +1,85 @@ +use alloc::vec::Vec; +use crate::elements; +use super::invoke::{Invoke, Identity}; + +/// Table definition +#[derive(Debug, PartialEq)] +pub struct TableDefinition { + /// Minimum length + pub min: u32, + /// Maximum length, if any + pub max: Option<u32>, + /// Element segments, if any + pub elements: Vec<TableEntryDefinition>, +} + +/// Table elements entry definition +#[derive(Debug, PartialEq)] +pub struct TableEntryDefinition { + /// Offset initialization expression + pub offset: elements::InitExpr, + /// Values of initialization + pub values: Vec<u32>, +} + +/// Table builder +pub struct TableBuilder<F=Identity> { + callback: F, + table: TableDefinition, +} + +impl TableBuilder { + /// New table builder + pub fn new() -> Self { + TableBuilder::with_callback(Identity) + } +} + +impl<F> TableBuilder<F> where F: Invoke<TableDefinition> { + /// New table builder with callback in chained context + pub fn with_callback(callback: F) -> Self { + TableBuilder { + callback: callback, + table: Default::default(), + } + } + + /// Set/override minimum length + pub fn with_min(mut self, min: u32) -> Self { + self.table.min = min; + self + } + + /// Set/override maximum length + pub fn with_max(mut self, max: Option<u32>) -> Self { + self.table.max = max; + self + } + + /// Generate initialization expression and element values on specified index + pub fn with_element(mut self, index: u32, values: Vec<u32>) -> Self { + self.table.elements.push(TableEntryDefinition { + offset: elements::InitExpr::new(vec![ + elements::Instruction::I32Const(index as i32), + elements::Instruction::End, + ]), + values: values, + }); + self + } + + /// Finalize current builder spawning resulting struct + pub fn build(self) -> F::Result { + self.callback.invoke(self.table) + } +} + +impl Default for TableDefinition { + fn default() -> Self { + TableDefinition { + min: 0, + max: None, + elements: Vec::new(), + } + } +} |