chore: checkpoint before Python removal

This commit is contained in:
2026-03-26 22:33:59 +00:00
parent 683cec9307
commit e568ddf82a
29972 changed files with 11269302 additions and 2 deletions

View File

@@ -0,0 +1,127 @@
use crate::{CustomSection, Encode, Section, SectionId};
use alloc::borrow::Cow;
use alloc::vec::Vec;
/// Helper structure to encode the `metadata.code.branch_hint` custom section.
///
/// This section was defined in the branch-hinting proposal for WebAssembly:
/// <https://github.com/WebAssembly/branch-hinting>.
///
/// # Example
///
/// ```
/// use wasm_encoder::*;
///
/// let mut module = Module::new();
///
/// let mut types = TypeSection::new();
/// types.ty().function([], []);
/// module.section(&types);
///
/// let mut funcs = FunctionSection::new();
/// funcs.function(0);
/// module.section(&funcs);
///
/// let mut code = CodeSection::new();
/// let mut body = Function::new([]);
///
/// body.instructions().i32_const(1);
/// let if_offset = body.byte_len();
/// body.instructions()
/// .if_(BlockType::Empty)
/// .end()
/// .end();
/// code.function(&body);
///
/// let mut hints = BranchHints::new();
/// hints.function_hints(0, [BranchHint {
/// branch_func_offset: if_offset as u32,
/// branch_hint_value: 1, // taken
/// }]);
/// module.section(&hints);
/// module.section(&code);
///
/// let wasm = module.finish();
/// let wat = wasmprinter::print_bytes(&wasm).unwrap();
/// assert_eq!(wat, r#"(module
/// (type (;0;) (func))
/// (func (;0;) (type 0)
/// i32.const 1
/// (@metadata.code.branch_hint "\01")
/// if ;; label = @1
/// end
/// )
/// )
/// "#);
///
/// ```
#[derive(Default, Debug)]
pub struct BranchHints {
bytes: Vec<u8>,
num_hints: u32,
}
/// A single branch hint within a function.
#[derive(Debug, Clone, Copy)]
pub struct BranchHint {
/// The offset, in bytes from the beginning of the function, to the `if`
/// instruction that this is hinting.
pub branch_func_offset: u32,
/// The value of the hint, 0 for not taken and 1 for taken.
pub branch_hint_value: u32,
}
impl BranchHints {
/// Construct an empty encoder for the branch hints custom section.
pub fn new() -> Self {
Self::default()
}
/// Adds a new set of function hints for the `func` specified.
pub fn function_hints<I>(&mut self, func: u32, hints: I)
where
I: IntoIterator<Item = BranchHint>,
I::IntoIter: ExactSizeIterator,
{
self.num_hints += 1;
func.encode(&mut self.bytes);
let hints = hints.into_iter();
hints.len().encode(&mut self.bytes);
for hint in hints {
hint.branch_func_offset.encode(&mut self.bytes);
1u32.encode(&mut self.bytes);
hint.branch_hint_value.encode(&mut self.bytes);
}
}
/// Returns if this is an empty section.
pub fn is_empty(&self) -> bool {
self.num_hints == 0
}
/// Returns the number of functions that have hints registered in this
/// sectino.
pub fn len(&self) -> u32 {
self.num_hints
}
}
impl Encode for BranchHints {
fn encode(&self, sink: &mut Vec<u8>) {
let mut data = Vec::new();
self.num_hints.encode(&mut data);
data.extend(&self.bytes);
CustomSection {
name: "metadata.code.branch_hint".into(),
data: Cow::Borrowed(&data),
}
.encode(sink);
}
}
impl Section for BranchHints {
fn id(&self) -> u8 {
SectionId::Custom.into()
}
}

2464
vendor/wasm-encoder/src/core/code.rs vendored Normal file

File diff suppressed because it is too large Load Diff

74
vendor/wasm-encoder/src/core/custom.rs vendored Normal file
View File

@@ -0,0 +1,74 @@
use crate::{Encode, Section, SectionId, encoding_size};
use alloc::borrow::Cow;
use alloc::vec::Vec;
/// A custom section holding arbitrary data.
#[derive(Clone, Debug, PartialEq)]
pub struct CustomSection<'a> {
/// The name of this custom section.
pub name: Cow<'a, str>,
/// This custom section's data.
pub data: Cow<'a, [u8]>,
}
impl Encode for CustomSection<'_> {
fn encode(&self, sink: &mut Vec<u8>) {
let encoded_name_len = encoding_size(u32::try_from(self.name.len()).unwrap());
(encoded_name_len + self.name.len() + self.data.len()).encode(sink);
self.name.encode(sink);
sink.extend(&*self.data);
}
}
impl Section for CustomSection<'_> {
fn id(&self) -> u8 {
SectionId::Custom.into()
}
}
/// A raw custom section where the bytes specified contain the leb-encoded
/// length of the custom section, the custom section's name, and the custom
/// section's data.
#[derive(Clone, Debug)]
pub struct RawCustomSection<'a>(pub &'a [u8]);
impl Encode for RawCustomSection<'_> {
fn encode(&self, sink: &mut Vec<u8>) {
sink.extend(self.0);
}
}
impl Section for RawCustomSection<'_> {
fn id(&self) -> u8 {
SectionId::Custom.into()
}
}
#[cfg(test)]
mod tests {
use super::*;
use alloc::vec;
#[test]
fn test_custom_section() {
let custom = CustomSection {
name: "test".into(),
data: Cow::Borrowed(&[11, 22, 33, 44]),
};
let mut encoded = vec![];
custom.encode(&mut encoded);
#[rustfmt::skip]
assert_eq!(encoded, vec![
// LEB128 length of section.
9,
// LEB128 length of name.
4,
// Name.
b't', b'e', b's', b't',
// Data.
11, 22, 33, 44,
]);
}
}

187
vendor/wasm-encoder/src/core/data.rs vendored Normal file
View File

@@ -0,0 +1,187 @@
use crate::{ConstExpr, Encode, Section, SectionId, encode_section, encoding_size};
use alloc::vec::Vec;
/// An encoder for the data section.
///
/// Data sections are only supported for modules.
///
/// # Example
///
/// ```
/// use wasm_encoder::{
/// ConstExpr, DataSection, Instruction, MemorySection, MemoryType,
/// Module,
/// };
///
/// let mut memory = MemorySection::new();
/// memory.memory(MemoryType {
/// minimum: 1,
/// maximum: None,
/// memory64: false,
/// shared: false,
/// page_size_log2: None,
/// });
///
/// let mut data = DataSection::new();
/// let memory_index = 0;
/// let offset = ConstExpr::i32_const(42);
/// let segment_data = b"hello";
/// data.active(memory_index, &offset, segment_data.iter().copied());
///
/// let mut module = Module::new();
/// module
/// .section(&memory)
/// .section(&data);
///
/// let wasm_bytes = module.finish();
/// ```
#[derive(Clone, Default, Debug)]
pub struct DataSection {
bytes: Vec<u8>,
num_added: u32,
}
/// A segment in the data section.
#[derive(Clone, Debug)]
pub struct DataSegment<'a, D> {
/// This data segment's mode.
pub mode: DataSegmentMode<'a>,
/// This data segment's data.
pub data: D,
}
/// A data segment's mode.
#[derive(Clone, Debug)]
pub enum DataSegmentMode<'a> {
/// An active data segment.
Active {
/// The memory this segment applies to.
memory_index: u32,
/// The offset where this segment's data is initialized at.
offset: &'a ConstExpr,
},
/// A passive data segment.
///
/// Passive data segments are part of the bulk memory proposal.
Passive,
}
impl DataSection {
/// Create a new data section encoder.
pub fn new() -> Self {
Self::default()
}
/// The number of data segments in the section.
pub fn len(&self) -> u32 {
self.num_added
}
/// Determines if the section is empty.
pub fn is_empty(&self) -> bool {
self.num_added == 0
}
/// Define a data segment.
pub fn segment<D>(&mut self, segment: DataSegment<D>) -> &mut Self
where
D: IntoIterator<Item = u8>,
D::IntoIter: ExactSizeIterator,
{
match segment.mode {
DataSegmentMode::Passive => {
self.bytes.push(0x01);
}
DataSegmentMode::Active {
memory_index: 0,
offset,
} => {
self.bytes.push(0x00);
offset.encode(&mut self.bytes);
}
DataSegmentMode::Active {
memory_index,
offset,
} => {
self.bytes.push(0x02);
memory_index.encode(&mut self.bytes);
offset.encode(&mut self.bytes);
}
}
let data = segment.data.into_iter();
data.len().encode(&mut self.bytes);
self.bytes.extend(data);
self.num_added += 1;
self
}
/// Define an active data segment.
pub fn active<D>(&mut self, memory_index: u32, offset: &ConstExpr, data: D) -> &mut Self
where
D: IntoIterator<Item = u8>,
D::IntoIter: ExactSizeIterator,
{
self.segment(DataSegment {
mode: DataSegmentMode::Active {
memory_index,
offset,
},
data,
})
}
/// Define a passive data segment.
///
/// Passive data segments are part of the bulk memory proposal.
pub fn passive<D>(&mut self, data: D) -> &mut Self
where
D: IntoIterator<Item = u8>,
D::IntoIter: ExactSizeIterator,
{
self.segment(DataSegment {
mode: DataSegmentMode::Passive,
data,
})
}
/// Copy an already-encoded data segment into this data section.
pub fn raw(&mut self, already_encoded_data_segment: &[u8]) -> &mut Self {
self.bytes.extend_from_slice(already_encoded_data_segment);
self.num_added += 1;
self
}
}
impl Encode for DataSection {
fn encode(&self, sink: &mut Vec<u8>) {
encode_section(sink, self.num_added, &self.bytes);
}
}
impl Section for DataSection {
fn id(&self) -> u8 {
SectionId::Data.into()
}
}
/// An encoder for the data count section.
#[derive(Clone, Copy, Debug)]
pub struct DataCountSection {
/// The number of segments in the data section.
pub count: u32,
}
impl Encode for DataCountSection {
fn encode(&self, sink: &mut Vec<u8>) {
encoding_size(self.count).encode(sink);
self.count.encode(sink);
}
}
impl Section for DataCountSection {
fn id(&self) -> u8 {
SectionId::DataCount.into()
}
}

629
vendor/wasm-encoder/src/core/dump.rs vendored Normal file
View File

@@ -0,0 +1,629 @@
use crate::{CustomSection, Encode, Ieee32, Ieee64, Section};
use alloc::borrow::Cow;
use alloc::string::String;
use alloc::vec;
use alloc::vec::Vec;
/// The "core" custom section for coredumps, as described in the
/// [tool-conventions
/// repository](https://github.com/WebAssembly/tool-conventions/blob/main/Coredump.md).
///
/// There are four sections that comprise a core dump:
/// - "core", which contains the name of the core dump
/// - "coremodules", a listing of modules
/// - "coreinstances", a listing of module instances
/// - "corestack", a listing of frames for a specific thread
///
/// # Example of how these could be constructed and encoded into a module:
///
/// ```
/// use wasm_encoder::{
/// CoreDumpInstancesSection, CoreDumpModulesSection, CoreDumpSection, CoreDumpStackSection,
/// CoreDumpValue, Module,
/// };
/// let core = CoreDumpSection::new("MyModule.wasm");
///
/// let mut modules = CoreDumpModulesSection::new();
/// modules.module("my_module");
///
/// let mut instances = CoreDumpInstancesSection::new();
/// let module_idx = 0;
/// let memories = vec![1];
/// let globals = vec![2];
/// instances.instance(module_idx, memories, globals);
///
/// let mut thread = CoreDumpStackSection::new("main");
/// let instance_index = 0;
/// let func_index = 42;
/// let code_offset = 0x1234;
/// let locals = vec![CoreDumpValue::I32(1)];
/// let stack = vec![CoreDumpValue::I32(2)];
/// thread.frame(instance_index, func_index, code_offset, locals, stack);
///
/// let mut module = Module::new();
/// module.section(&core);
/// module.section(&modules);
/// module.section(&instances);
/// module.section(&thread);
/// ```
#[derive(Clone, Debug, Default)]
pub struct CoreDumpSection {
name: String,
}
impl CoreDumpSection {
/// Create a new core dump section encoder
pub fn new(name: impl Into<String>) -> Self {
let name = name.into();
CoreDumpSection { name }
}
/// View the encoded section as a CustomSection.
fn as_custom<'a>(&'a self) -> CustomSection<'a> {
let mut data = vec![0];
self.name.encode(&mut data);
CustomSection {
name: "core".into(),
data: Cow::Owned(data),
}
}
}
impl Encode for CoreDumpSection {
fn encode(&self, sink: &mut Vec<u8>) {
self.as_custom().encode(sink);
}
}
impl Section for CoreDumpSection {
fn id(&self) -> u8 {
crate::core::SectionId::Custom as u8
}
}
/// The "coremodules" custom section for coredumps which lists the names of the
/// modules
///
/// # Example
///
/// ```
/// use wasm_encoder::{CoreDumpModulesSection, Module};
/// let mut modules_section = CoreDumpModulesSection::new();
/// modules_section.module("my_module");
/// let mut module = Module::new();
/// module.section(&modules_section);
/// ```
#[derive(Debug)]
pub struct CoreDumpModulesSection {
num_added: u32,
bytes: Vec<u8>,
}
impl CoreDumpModulesSection {
/// Create a new core dump modules section encoder.
pub fn new() -> Self {
CoreDumpModulesSection {
bytes: vec![],
num_added: 0,
}
}
/// View the encoded section as a CustomSection.
pub fn as_custom(&self) -> CustomSection<'_> {
let mut data = vec![];
self.num_added.encode(&mut data);
data.extend(self.bytes.iter().copied());
CustomSection {
name: "coremodules".into(),
data: Cow::Owned(data),
}
}
/// Encode a module name into the section's bytes.
pub fn module(&mut self, module_name: impl AsRef<str>) -> &mut Self {
self.bytes.push(0x0);
module_name.as_ref().encode(&mut self.bytes);
self.num_added += 1;
self
}
/// The number of modules that are encoded in the section.
pub fn len(&self) -> u32 {
self.num_added
}
}
impl Encode for CoreDumpModulesSection {
fn encode(&self, sink: &mut Vec<u8>) {
self.as_custom().encode(sink);
}
}
impl Section for CoreDumpModulesSection {
fn id(&self) -> u8 {
crate::core::SectionId::Custom as u8
}
}
/// The "coreinstances" section for the core dump
#[derive(Debug)]
pub struct CoreDumpInstancesSection {
num_added: u32,
bytes: Vec<u8>,
}
impl CoreDumpInstancesSection {
/// Create a new core dump instances section encoder.
pub fn new() -> Self {
CoreDumpInstancesSection {
bytes: vec![],
num_added: 0,
}
}
/// View the encoded section as a CustomSection.
pub fn as_custom(&self) -> CustomSection<'_> {
let mut data = vec![];
self.num_added.encode(&mut data);
data.extend(self.bytes.iter().copied());
CustomSection {
name: "coreinstances".into(),
data: Cow::Owned(data),
}
}
/// Encode an instance into the section's bytes.
pub fn instance<M, G>(&mut self, module_index: u32, memories: M, globals: G) -> &mut Self
where
M: IntoIterator<Item = u32>,
<M as IntoIterator>::IntoIter: ExactSizeIterator,
G: IntoIterator<Item = u32>,
<G as IntoIterator>::IntoIter: ExactSizeIterator,
{
self.bytes.push(0x0);
module_index.encode(&mut self.bytes);
crate::encode_vec(memories, &mut self.bytes);
crate::encode_vec(globals, &mut self.bytes);
self.num_added += 1;
self
}
/// The number of modules that are encoded in the section.
pub fn len(&self) -> u32 {
self.num_added
}
}
impl Encode for CoreDumpInstancesSection {
fn encode(&self, sink: &mut Vec<u8>) {
self.as_custom().encode(sink);
}
}
impl Section for CoreDumpInstancesSection {
fn id(&self) -> u8 {
crate::core::SectionId::Custom as u8
}
}
/// A "corestack" custom section as described in the [tool-conventions
/// repository](https://github.com/WebAssembly/tool-conventions/blob/main/Coredump.md)
///
/// # Example
///
/// ```
/// use wasm_encoder::{CoreDumpStackSection, Module, CoreDumpValue};
/// let mut thread = CoreDumpStackSection::new("main");
///
/// let instance_index = 0;
/// let func_index = 42;
/// let code_offset = 0x1234;
/// let locals = vec![CoreDumpValue::I32(1)];
/// let stack = vec![CoreDumpValue::I32(2)];
/// thread.frame(instance_index, func_index, code_offset, locals, stack);
///
/// let mut module = Module::new();
/// module.section(&thread);
/// ```
#[derive(Clone, Debug, Default)]
pub struct CoreDumpStackSection {
frame_bytes: Vec<u8>,
count: u32,
name: String,
}
impl CoreDumpStackSection {
/// Create a new core dump stack section encoder.
pub fn new(name: impl Into<String>) -> Self {
let name = name.into();
CoreDumpStackSection {
frame_bytes: Vec::new(),
count: 0,
name,
}
}
/// Add a stack frame to this coredump stack section.
pub fn frame<L, S>(
&mut self,
instanceidx: u32,
funcidx: u32,
codeoffset: u32,
locals: L,
stack: S,
) -> &mut Self
where
L: IntoIterator<Item = CoreDumpValue>,
<L as IntoIterator>::IntoIter: ExactSizeIterator,
S: IntoIterator<Item = CoreDumpValue>,
<S as IntoIterator>::IntoIter: ExactSizeIterator,
{
self.count += 1;
self.frame_bytes.push(0);
instanceidx.encode(&mut self.frame_bytes);
funcidx.encode(&mut self.frame_bytes);
codeoffset.encode(&mut self.frame_bytes);
crate::encode_vec(locals, &mut self.frame_bytes);
crate::encode_vec(stack, &mut self.frame_bytes);
self
}
/// View the encoded section as a CustomSection.
pub fn as_custom<'a>(&'a self) -> CustomSection<'a> {
let mut data = vec![0];
self.name.encode(&mut data);
self.count.encode(&mut data);
data.extend(&self.frame_bytes);
CustomSection {
name: "corestack".into(),
data: Cow::Owned(data),
}
}
}
impl Encode for CoreDumpStackSection {
fn encode(&self, sink: &mut Vec<u8>) {
self.as_custom().encode(sink);
}
}
impl Section for CoreDumpStackSection {
fn id(&self) -> u8 {
crate::core::SectionId::Custom as u8
}
}
/// Local and stack values are encoded using one byte for the type (similar to
/// Wasm's Number Types) followed by bytes representing the actual value
/// See the tool-conventions repo for more details.
#[derive(Clone, Debug)]
pub enum CoreDumpValue {
/// a missing value (usually missing because it was optimized out)
Missing,
/// An i32 value
I32(i32),
/// An i64 value
I64(i64),
/// An f32 value
F32(Ieee32),
/// An f64 value
F64(Ieee64),
}
impl Encode for CoreDumpValue {
fn encode(&self, sink: &mut Vec<u8>) {
match self {
CoreDumpValue::Missing => sink.push(0x01),
CoreDumpValue::I32(x) => {
sink.push(0x7F);
x.encode(sink);
}
CoreDumpValue::I64(x) => {
sink.push(0x7E);
x.encode(sink);
}
CoreDumpValue::F32(x) => {
sink.push(0x7D);
x.encode(sink);
}
CoreDumpValue::F64(x) => {
sink.push(0x7C);
x.encode(sink);
}
}
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::Module;
use wasmparser::{KnownCustom, Parser, Payload};
// Create new core dump section and test whether it is properly encoded and
// parsed back out by wasmparser
#[test]
fn test_roundtrip_core() {
let core = CoreDumpSection::new("test.wasm");
let mut module = Module::new();
module.section(&core);
let wasm_bytes = module.finish();
let mut parser = Parser::new(0).parse_all(&wasm_bytes);
match parser.next() {
Some(Ok(Payload::Version { .. })) => {}
_ => panic!(""),
}
let payload = parser
.next()
.expect("parser is not empty")
.expect("element is a payload");
match payload {
Payload::CustomSection(section) => {
assert_eq!(section.name(), "core");
let core = match section.as_known() {
KnownCustom::CoreDump(s) => s,
_ => panic!("not coredump"),
};
assert_eq!(core.name, "test.wasm");
}
_ => panic!("unexpected payload"),
}
}
#[test]
fn test_roundtrip_coremodules() {
let mut coremodules = CoreDumpModulesSection::new();
coremodules.module("test_module");
let mut module = crate::Module::new();
module.section(&coremodules);
let wasm_bytes = module.finish();
let mut parser = Parser::new(0).parse_all(&wasm_bytes);
match parser.next() {
Some(Ok(Payload::Version { .. })) => {}
_ => panic!(""),
}
let payload = parser
.next()
.expect("parser is not empty")
.expect("element is a payload");
match payload {
Payload::CustomSection(section) => {
assert_eq!(section.name(), "coremodules");
let modules = match section.as_known() {
KnownCustom::CoreDumpModules(s) => s,
_ => panic!("not coremodules"),
};
assert_eq!(modules.modules[0], "test_module");
}
_ => panic!("unexpected payload"),
}
}
#[test]
fn test_roundtrip_coreinstances() {
let mut coreinstances = CoreDumpInstancesSection::new();
let module_index = 0;
let memories = vec![42];
let globals = vec![17];
coreinstances.instance(module_index, memories, globals);
let mut module = Module::new();
module.section(&coreinstances);
let wasm_bytes = module.finish();
let mut parser = Parser::new(0).parse_all(&wasm_bytes);
match parser.next() {
Some(Ok(Payload::Version { .. })) => {}
_ => panic!(""),
}
let payload = parser
.next()
.expect("parser is not empty")
.expect("element is a payload");
match payload {
Payload::CustomSection(section) => {
assert_eq!(section.name(), "coreinstances");
let coreinstances = match section.as_known() {
KnownCustom::CoreDumpInstances(s) => s,
_ => panic!("not coreinstances"),
};
assert_eq!(coreinstances.instances.len(), 1);
let instance = coreinstances
.instances
.first()
.expect("instance is encoded");
assert_eq!(instance.module_index, 0);
assert_eq!(instance.memories.len(), 1);
assert_eq!(instance.globals.len(), 1);
}
_ => panic!("unexpected payload"),
}
}
// Create new corestack section and test whether it is properly encoded and
// parsed back out by wasmparser
#[test]
fn test_roundtrip_corestack() {
let mut corestack = CoreDumpStackSection::new("main");
corestack.frame(
0,
12,
0,
vec![CoreDumpValue::I32(10)],
vec![CoreDumpValue::I32(42)],
);
let mut module = Module::new();
module.section(&corestack);
let wasm_bytes = module.finish();
let mut parser = Parser::new(0).parse_all(&wasm_bytes);
match parser.next() {
Some(Ok(Payload::Version { .. })) => {}
_ => panic!(""),
}
let payload = parser
.next()
.expect("parser is not empty")
.expect("element is a payload");
match payload {
Payload::CustomSection(section) => {
assert_eq!(section.name(), "corestack");
let corestack = match section.as_known() {
KnownCustom::CoreDumpStack(s) => s,
_ => panic!("not a corestack section"),
};
assert_eq!(corestack.name, "main");
assert_eq!(corestack.frames.len(), 1);
let frame = corestack
.frames
.first()
.expect("frame is encoded in corestack");
assert_eq!(frame.instanceidx, 0);
assert_eq!(frame.funcidx, 12);
assert_eq!(frame.codeoffset, 0);
assert_eq!(frame.locals.len(), 1);
match frame.locals.first().expect("frame contains a local") {
&wasmparser::CoreDumpValue::I32(val) => assert_eq!(val, 10),
_ => panic!("unexpected local value"),
}
assert_eq!(frame.stack.len(), 1);
match frame.stack.first().expect("stack contains a value") {
&wasmparser::CoreDumpValue::I32(val) => assert_eq!(val, 42),
_ => panic!("unexpected stack value"),
}
}
_ => panic!("unexpected payload"),
}
}
#[test]
fn test_encode_coredump_section() {
let core = CoreDumpSection::new("test");
let mut encoded = vec![];
core.encode(&mut encoded);
#[rustfmt::skip]
assert_eq!(encoded, vec![
// section length
11,
// name length
4,
// section name (core)
b'c',b'o',b'r',b'e',
// process-info (0, data length, data)
0, 4, b't', b'e', b's', b't',
]);
}
#[test]
fn test_encode_coremodules_section() {
let mut modules = CoreDumpModulesSection::new();
modules.module("mod1");
modules.module("mod2");
let mut encoded = vec![];
modules.encode(&mut encoded);
#[rustfmt::skip]
assert_eq!(encoded, vec![
// section length
25,
// name length
11,
// section name (coremodules)
b'c',b'o',b'r',b'e',b'm',b'o',b'd',b'u',b'l',b'e',b's',
// module count
2,
// 0x0, name-length, module name (mod1)
0x0, 4, b'm',b'o',b'd',b'1',
// 0x0, name-length, module name (mod2)
0x0, 4, b'm',b'o',b'd',b'2'
]);
}
#[test]
fn test_encode_coreinstances_section() {
let mut instances = CoreDumpInstancesSection::new();
instances.instance(0, vec![42], vec![17]);
let mut encoded = vec![];
instances.encode(&mut encoded);
#[rustfmt::skip]
assert_eq!(encoded, vec![
// section length
21,
// name length
13,
// section name (coreinstances)
b'c',b'o',b'r',b'e',b'i',b'n',b's',b't',b'a',b'n',b'c',b'e',b's',
// instance count
1,
// 0x0, module_idx
0x0, 0,
// memories count, memories
1, 42,
// globals count, globals
1, 17
]);
}
#[test]
fn test_encode_corestack_section() {
let mut thread = CoreDumpStackSection::new("main");
thread.frame(
0,
42,
51,
vec![CoreDumpValue::I32(1)],
vec![CoreDumpValue::I32(2)],
);
let mut encoded = vec![];
thread.encode(&mut encoded);
#[rustfmt::skip]
assert_eq!(
encoded,
vec![
// section length
27,
// length of name.
9,
// section name (corestack)
b'c',b'o',b'r',b'e',b's',b't',b'a',b'c',b'k',
// 0x0, thread name length
0, 4,
// thread name (main)
b'm',b'a',b'i',b'n',
// frame count
1,
// 0x0, instanceidx, funcidx, codeoffset
0, 0, 42, 51,
// local count
1,
// local value type
0x7F,
// local value
1,
// stack count
1,
// stack value type
0x7F,
// stack value
2
]
);
}
}

225
vendor/wasm-encoder/src/core/elements.rs vendored Normal file
View File

@@ -0,0 +1,225 @@
use crate::{ConstExpr, Encode, RefType, Section, SectionId, encode_section};
use alloc::borrow::Cow;
use alloc::vec::Vec;
/// An encoder for the element section.
///
/// Element sections are only supported for modules.
///
/// # Example
///
/// ```
/// use std::borrow::Cow;
/// use wasm_encoder::{
/// Elements, ElementSection, Module, TableSection, TableType,
/// RefType, ConstExpr
/// };
///
/// let mut tables = TableSection::new();
/// tables.table(TableType {
/// element_type: RefType::FUNCREF,
/// minimum: 128,
/// maximum: None,
/// table64: false,
/// shared: false,
/// });
///
/// let mut elements = ElementSection::new();
/// let table_index = 0;
/// let offset = ConstExpr::i32_const(42);
/// let functions = Elements::Functions(Cow::Borrowed(&[
/// // Function indices...
/// ]));
/// elements.active(Some(table_index), &offset, functions);
///
/// let mut module = Module::new();
/// module
/// .section(&tables)
/// .section(&elements);
///
/// let wasm_bytes = module.finish();
/// ```
#[derive(Clone, Default, Debug)]
pub struct ElementSection {
bytes: Vec<u8>,
num_added: u32,
}
/// A sequence of elements in a segment in the element section.
#[derive(Clone, Debug)]
pub enum Elements<'a> {
/// A sequences of references to functions by their indices.
Functions(Cow<'a, [u32]>),
/// A sequence of reference expressions.
Expressions(RefType, Cow<'a, [ConstExpr]>),
}
/// An element segment's mode.
#[derive(Clone, Debug)]
pub enum ElementMode<'a> {
/// A passive element segment.
///
/// Passive segments are part of the bulk memory proposal.
Passive,
/// A declared element segment.
///
/// Declared segments are part of the bulk memory proposal.
Declared,
/// An active element segment.
Active {
/// The table index.
///
/// `Active` element specifying a `None` table forces the MVP encoding and refers to the
/// 0th table holding `funcref`s. Non-`None` tables use the encoding introduced with the
/// bulk memory proposal and can refer to tables with any valid reference type.
table: Option<u32>,
/// The offset within the table to place this segment.
offset: &'a ConstExpr,
},
}
/// An element segment in the element section.
#[derive(Clone, Debug)]
pub struct ElementSegment<'a> {
/// The element segment's mode.
pub mode: ElementMode<'a>,
/// This segment's elements.
pub elements: Elements<'a>,
}
impl ElementSection {
/// Create a new element section encoder.
pub fn new() -> Self {
Self::default()
}
/// The number of element segments in the section.
pub fn len(&self) -> u32 {
self.num_added
}
/// Determines if the section is empty.
pub fn is_empty(&self) -> bool {
self.num_added == 0
}
/// Define an element segment.
pub fn segment<'a>(&mut self, segment: ElementSegment<'a>) -> &mut Self {
let expr_bit = match segment.elements {
Elements::Expressions(..) => 0b100u32,
Elements::Functions(_) => 0b000u32,
};
let mut encode_type = false;
match &segment.mode {
ElementMode::Passive => {
(0x01 | expr_bit).encode(&mut self.bytes);
encode_type = true;
}
ElementMode::Active { table, offset } => {
match (table, &segment.elements) {
// If the `table` is not specified then the 0x00 encoding
// can be used with either function indices or expressions
// that have a `funcref` type.
(None, Elements::Functions(_) | Elements::Expressions(RefType::FUNCREF, _)) => {
(/* 0x00 | */expr_bit).encode(&mut self.bytes);
}
// ... otherwise fall through for all other expressions here
// with table 0 or an explicitly specified table to the 0x02
// encoding.
(None, Elements::Expressions(..)) | (Some(_), _) => {
(0x02 | expr_bit).encode(&mut self.bytes);
table.unwrap_or(0).encode(&mut self.bytes);
encode_type = true;
}
}
offset.encode(&mut self.bytes);
}
ElementMode::Declared => {
(0x03 | expr_bit).encode(&mut self.bytes);
encode_type = true;
}
}
match segment.elements {
Elements::Functions(fs) => {
if encode_type {
// elemkind == funcref
self.bytes.push(0x00);
}
fs.encode(&mut self.bytes);
}
Elements::Expressions(ty, e) => {
if encode_type {
ty.encode(&mut self.bytes);
}
e.len().encode(&mut self.bytes);
for expr in e.iter() {
expr.encode(&mut self.bytes);
}
}
}
self.num_added += 1;
self
}
/// Define an active element segment.
///
/// `Active` element specifying a `None` table forces the MVP encoding and refers to the 0th
/// table holding `funcref`s. Non-`None` tables use the encoding introduced with the bulk
/// memory proposal and can refer to tables with any valid reference type.
pub fn active(
&mut self,
table_index: Option<u32>,
offset: &ConstExpr,
elements: Elements<'_>,
) -> &mut Self {
self.segment(ElementSegment {
mode: ElementMode::Active {
table: table_index,
offset,
},
elements,
})
}
/// Encode a passive element segment.
///
/// Passive segments are part of the bulk memory proposal.
pub fn passive<'a>(&mut self, elements: Elements<'a>) -> &mut Self {
self.segment(ElementSegment {
mode: ElementMode::Passive,
elements,
})
}
/// Encode a declared element segment.
///
/// Declared segments are part of the bulk memory proposal.
pub fn declared<'a>(&mut self, elements: Elements<'a>) -> &mut Self {
self.segment(ElementSegment {
mode: ElementMode::Declared,
elements,
})
}
/// Copy a raw, already-encoded element segment into this elements section.
pub fn raw(&mut self, raw_bytes: &[u8]) -> &mut Self {
self.bytes.extend_from_slice(raw_bytes);
self.num_added += 1;
self
}
}
impl Encode for ElementSection {
fn encode(&self, sink: &mut Vec<u8>) {
encode_section(sink, self.num_added, &self.bytes);
}
}
impl Section for ElementSection {
fn id(&self) -> u8 {
SectionId::Element.into()
}
}

86
vendor/wasm-encoder/src/core/exports.rs vendored Normal file
View File

@@ -0,0 +1,86 @@
use super::{
CORE_FUNCTION_SORT, CORE_GLOBAL_SORT, CORE_MEMORY_SORT, CORE_TABLE_SORT, CORE_TAG_SORT,
};
use crate::{Encode, Section, SectionId, encode_section};
use alloc::vec::Vec;
/// Represents the kind of an export from a WebAssembly module.
#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash)]
#[repr(u8)]
pub enum ExportKind {
/// The export is a function.
Func = CORE_FUNCTION_SORT,
/// The export is a table.
Table = CORE_TABLE_SORT,
/// The export is a memory.
Memory = CORE_MEMORY_SORT,
/// The export is a global.
Global = CORE_GLOBAL_SORT,
/// The export is a tag.
Tag = CORE_TAG_SORT,
}
impl Encode for ExportKind {
fn encode(&self, sink: &mut Vec<u8>) {
sink.push(*self as u8);
}
}
/// An encoder for the export section of WebAssembly module.
///
/// # Example
///
/// ```rust
/// use wasm_encoder::{Module, ExportSection, ExportKind};
///
/// let mut exports = ExportSection::new();
/// exports.export("foo", ExportKind::Func, 0);
///
/// let mut module = Module::new();
/// module.section(&exports);
///
/// let bytes = module.finish();
/// ```
#[derive(Clone, Debug, Default)]
pub struct ExportSection {
bytes: Vec<u8>,
num_added: u32,
}
impl ExportSection {
/// Create a new export section encoder.
pub fn new() -> Self {
Self::default()
}
/// The number of exports in the section.
pub fn len(&self) -> u32 {
self.num_added
}
/// Determines if the section is empty.
pub fn is_empty(&self) -> bool {
self.num_added == 0
}
/// Define an export in the export section.
pub fn export(&mut self, name: &str, kind: ExportKind, index: u32) -> &mut Self {
name.encode(&mut self.bytes);
kind.encode(&mut self.bytes);
index.encode(&mut self.bytes);
self.num_added += 1;
self
}
}
impl Encode for ExportSection {
fn encode(&self, sink: &mut Vec<u8>) {
encode_section(sink, self.num_added, &self.bytes);
}
}
impl Section for ExportSection {
fn id(&self) -> u8 {
SectionId::Export.into()
}
}

View File

@@ -0,0 +1,64 @@
use crate::{Encode, Section, SectionId, encode_section};
use alloc::vec::Vec;
/// An encoder for the function section of WebAssembly modules.
///
/// # Example
///
/// ```
/// use wasm_encoder::{Module, FunctionSection, ValType};
///
/// let mut functions = FunctionSection::new();
/// let type_index = 0;
/// functions.function(type_index);
///
/// let mut module = Module::new();
/// module.section(&functions);
///
/// // Note: this will generate an invalid module because we didn't generate a
/// // code section containing the function body. See the documentation for
/// // `CodeSection` for details.
///
/// let bytes = module.finish();
/// ```
#[derive(Clone, Debug, Default)]
pub struct FunctionSection {
bytes: Vec<u8>,
num_added: u32,
}
impl FunctionSection {
/// Construct a new module function section encoder.
pub fn new() -> Self {
Self::default()
}
/// The number of functions in the section.
pub fn len(&self) -> u32 {
self.num_added
}
/// Determines if the section is empty.
pub fn is_empty(&self) -> bool {
self.num_added == 0
}
/// Define a function in a module's function section.
pub fn function(&mut self, type_index: u32) -> &mut Self {
type_index.encode(&mut self.bytes);
self.num_added += 1;
self
}
}
impl Encode for FunctionSection {
fn encode(&self, sink: &mut Vec<u8>) {
encode_section(sink, self.num_added, &self.bytes);
}
}
impl Section for FunctionSection {
fn id(&self) -> u8 {
SectionId::Function.into()
}
}

101
vendor/wasm-encoder/src/core/globals.rs vendored Normal file
View File

@@ -0,0 +1,101 @@
use crate::{ConstExpr, Encode, Section, SectionId, ValType, encode_section};
use alloc::vec::Vec;
/// An encoder for the global section.
///
/// Global sections are only supported for modules.
///
/// # Example
///
/// ```
/// use wasm_encoder::{ConstExpr, Module, GlobalSection, GlobalType, Instruction, ValType};
///
/// let mut globals = GlobalSection::new();
/// globals.global(
/// GlobalType {
/// val_type: ValType::I32,
/// mutable: false,
/// shared: false,
/// },
/// &ConstExpr::i32_const(42),
/// );
///
/// let mut module = Module::new();
/// module.section(&globals);
///
/// let wasm_bytes = module.finish();
/// ```
#[derive(Clone, Default, Debug)]
pub struct GlobalSection {
bytes: Vec<u8>,
num_added: u32,
}
impl GlobalSection {
/// Create a new global section encoder.
pub fn new() -> Self {
Self::default()
}
/// The number of globals in the section.
pub fn len(&self) -> u32 {
self.num_added
}
/// Determines if the section is empty.
pub fn is_empty(&self) -> bool {
self.num_added == 0
}
/// Define a global.
pub fn global(&mut self, global_type: GlobalType, init_expr: &ConstExpr) -> &mut Self {
global_type.encode(&mut self.bytes);
init_expr.encode(&mut self.bytes);
self.num_added += 1;
self
}
/// Add a raw byte slice into this code section as a global.
pub fn raw(&mut self, data: &[u8]) -> &mut Self {
self.bytes.extend(data);
self.num_added += 1;
self
}
}
impl Encode for GlobalSection {
fn encode(&self, sink: &mut Vec<u8>) {
encode_section(sink, self.num_added, &self.bytes);
}
}
impl Section for GlobalSection {
fn id(&self) -> u8 {
SectionId::Global.into()
}
}
/// A global's type.
#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash)]
pub struct GlobalType {
/// This global's value type.
pub val_type: ValType,
/// Whether this global is mutable or not.
pub mutable: bool,
/// Whether this global is shared or not.
pub shared: bool,
}
impl Encode for GlobalType {
fn encode(&self, sink: &mut Vec<u8>) {
self.val_type.encode(sink);
let mut flag = 0;
if self.mutable {
flag |= 0b01;
}
if self.shared {
flag |= 0b10;
}
sink.push(flag);
}
}

230
vendor/wasm-encoder/src/core/imports.rs vendored Normal file
View File

@@ -0,0 +1,230 @@
use crate::{
CORE_FUNCTION_EXACT_SORT, CORE_FUNCTION_SORT, CORE_GLOBAL_SORT, CORE_MEMORY_SORT,
CORE_TABLE_SORT, CORE_TAG_SORT, Encode, GlobalType, MemoryType, Section, SectionId, TableType,
TagType, encode_section,
};
use alloc::borrow::Cow;
use alloc::vec::Vec;
/// The type of an entity.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum EntityType {
/// A function type.
///
/// The value is an index into the types section.
Function(u32),
/// A table type.
Table(TableType),
/// A memory type.
Memory(MemoryType),
/// A global type.
Global(GlobalType),
/// A tag type.
///
/// This variant is used with the exception handling proposal.
Tag(TagType),
/// A function exact type.
///
/// The value is an index into the types section.
FunctionExact(u32),
}
impl Encode for EntityType {
fn encode(&self, sink: &mut Vec<u8>) {
match self {
Self::Function(f) => {
sink.push(CORE_FUNCTION_SORT);
f.encode(sink);
}
Self::FunctionExact(f) => {
sink.push(CORE_FUNCTION_EXACT_SORT);
f.encode(sink);
}
Self::Table(t) => {
sink.push(CORE_TABLE_SORT);
t.encode(sink);
}
Self::Memory(t) => {
sink.push(CORE_MEMORY_SORT);
t.encode(sink);
}
Self::Global(t) => {
sink.push(CORE_GLOBAL_SORT);
t.encode(sink);
}
Self::Tag(t) => {
sink.push(CORE_TAG_SORT);
t.encode(sink);
}
}
}
}
impl From<TableType> for EntityType {
fn from(t: TableType) -> Self {
Self::Table(t)
}
}
impl From<MemoryType> for EntityType {
fn from(t: MemoryType) -> Self {
Self::Memory(t)
}
}
impl From<GlobalType> for EntityType {
fn from(t: GlobalType) -> Self {
Self::Global(t)
}
}
impl From<TagType> for EntityType {
fn from(t: TagType) -> Self {
Self::Tag(t)
}
}
/// An import item to be used with [`Imports::Single`].
#[derive(Clone, Debug)]
pub struct Import<'a> {
/// The import's module name.
pub module: &'a str,
/// The import's item name.
pub name: &'a str,
/// The import's time.
pub ty: EntityType,
}
/// An import item to be used with [`Imports::Compact1`].
#[derive(Clone, Debug)]
pub struct ImportCompact<'a> {
/// The import's item name.
pub name: &'a str,
/// The import's type.
pub ty: EntityType,
}
/// A single entry in the import section of a WebAssembly module, possibly containing multiple imports.
#[derive(Clone, Debug)]
pub enum Imports<'a> {
/// A single import item.
Single(Import<'a>),
/// A group of imports with a common module name.
Compact1 {
/// The common module name.
module: &'a str,
/// The individual import items (name/type).
items: Cow<'a, [ImportCompact<'a>]>,
},
/// A group of imports with a common module name and type.
Compact2 {
/// The common module name.
module: &'a str,
/// The common import type.
ty: EntityType,
/// The individual import item names.
names: Cow<'a, [&'a str]>,
},
}
/// An encoder for the import section of WebAssembly modules.
///
/// # Example
///
/// ```rust
/// use wasm_encoder::{MemoryType, Module, ImportSection};
///
/// let mut imports = ImportSection::new();
/// imports.import(
/// "env",
/// "memory",
/// MemoryType {
/// minimum: 1,
/// maximum: None,
/// memory64: false,
/// shared: false,
/// page_size_log2: None,
/// }
/// );
///
/// let mut module = Module::new();
/// module.section(&imports);
///
/// let bytes = module.finish();
/// ```
#[derive(Clone, Debug, Default)]
pub struct ImportSection {
bytes: Vec<u8>,
num_added: u32,
}
impl ImportSection {
/// Create a new import section encoder.
pub fn new() -> Self {
Self::default()
}
/// The number of imports in the section.
pub fn len(&self) -> u32 {
self.num_added
}
/// Determines if the section is empty.
pub fn is_empty(&self) -> bool {
self.num_added == 0
}
/// Define imports in the import section.
pub fn imports<'a>(&mut self, imports: Imports<'a>) -> &mut Self {
match imports {
Imports::Single(import) => {
import.module.encode(&mut self.bytes);
import.name.encode(&mut self.bytes);
import.ty.encode(&mut self.bytes);
}
Imports::Compact1 { module, items } => {
module.encode(&mut self.bytes);
self.bytes.push(0x00); // empty name
self.bytes.push(0x7F);
items.len().encode(&mut self.bytes);
for item in items.iter() {
item.name.encode(&mut self.bytes);
item.ty.encode(&mut self.bytes);
}
}
Imports::Compact2 { module, ty, names } => {
module.encode(&mut self.bytes);
self.bytes.push(0x00); // empty name
self.bytes.push(0x7E);
ty.encode(&mut self.bytes);
names.len().encode(&mut self.bytes);
for item in names.iter() {
item.encode(&mut self.bytes);
}
}
}
self.num_added += 1;
self
}
/// Define an import in the import section.
pub fn import(&mut self, module: &str, name: &str, ty: impl Into<EntityType>) -> &mut Self {
self.imports(Imports::Single(Import {
module,
name,
ty: ty.into(),
}))
}
}
impl Encode for ImportSection {
fn encode(&self, sink: &mut Vec<u8>) {
encode_section(sink, self.num_added, &self.bytes);
}
}
impl Section for ImportSection {
fn id(&self) -> u8 {
SectionId::Import.into()
}
}

File diff suppressed because it is too large Load Diff

264
vendor/wasm-encoder/src/core/linking.rs vendored Normal file
View File

@@ -0,0 +1,264 @@
use crate::{CustomSection, Encode, Section, SectionId, encode_section};
use alloc::borrow::Cow;
use alloc::vec;
use alloc::vec::Vec;
const VERSION: u32 = 2;
/// An encoder for the [linking custom
/// section](https://github.com/WebAssembly/tool-conventions/blob/master/Linking.md#linking-metadata-section).
///
/// This section is a non-standard convention that is supported by the LLVM
/// toolchain. It, along with associated "reloc.*" custom sections, allows you
/// to treat a Wasm module as a low-level object file that can be linked with
/// other Wasm object files to produce a final, complete Wasm module.
///
/// The linking section must come before the reloc sections.
///
/// # Example
///
/// ```
/// use wasm_encoder::{LinkingSection, Module, SymbolTable};
///
/// // Create a new linking section.
/// let mut linking = LinkingSection::new();
///
/// // Define a symbol table.
/// let mut sym_tab = SymbolTable::new();
///
/// // Define a function symbol in the symbol table.
/// let flags = SymbolTable::WASM_SYM_BINDING_LOCAL | SymbolTable::WASM_SYM_EXPORTED;
/// let func_index = 42;
/// let sym_name = "my_exported_func";
/// sym_tab.function(flags, func_index, Some(sym_name));
///
/// // Add the symbol table to our linking section.
/// linking.symbol_table(&sym_tab);
///
/// // Add the linking section to a new Wasm module and get the encoded bytes.
/// let mut module = Module::new();
/// module.section(&linking);
/// let wasm_bytes = module.finish();
/// ```
#[derive(Clone, Debug)]
pub struct LinkingSection {
bytes: Vec<u8>,
}
impl LinkingSection {
/// Construct a new encoder for the linking custom section.
pub fn new() -> Self {
Self::default()
}
// TODO: `fn segment_info` for the `WASM_SEGMENT_INFO` linking subsection.
// TODO: `fn init_funcs` for the `WASM_INIT_FUNCS` linking subsection.
// TODO: `fn comdat_info` for the `WASM_COMDAT_INFO` linking subsection.
/// Add a symbol table subsection.
pub fn symbol_table(&mut self, symbol_table: &SymbolTable) -> &mut Self {
symbol_table.encode(&mut self.bytes);
self
}
}
impl Default for LinkingSection {
fn default() -> Self {
let mut bytes = Vec::new();
VERSION.encode(&mut bytes);
Self { bytes }
}
}
impl Encode for LinkingSection {
fn encode(&self, sink: &mut Vec<u8>) {
CustomSection {
name: "linking".into(),
data: Cow::Borrowed(&self.bytes),
}
.encode(sink);
}
}
impl Section for LinkingSection {
fn id(&self) -> u8 {
SectionId::Custom.into()
}
}
#[allow(unused)]
const WASM_SEGMENT_INFO: u8 = 5;
#[allow(unused)]
const WASM_INIT_FUNCS: u8 = 6;
#[allow(unused)]
const WASM_COMDAT_INFO: u8 = 7;
const WASM_SYMBOL_TABLE: u8 = 8;
/// A subsection of the [linking custom section][crate::LinkingSection] that
/// provides extra information about the symbols present in this Wasm object
/// file.
#[derive(Clone, Debug, Default)]
pub struct SymbolTable {
bytes: Vec<u8>,
num_added: u32,
}
const SYMTAB_FUNCTION: u32 = 0;
const SYMTAB_DATA: u32 = 1;
const SYMTAB_GLOBAL: u32 = 2;
#[allow(unused)]
const SYMTAB_SECTION: u32 = 3;
#[allow(unused)]
const SYMTAB_TAG: u32 = 4;
const SYMTAB_TABLE: u32 = 5;
impl SymbolTable {
/// Construct a new symbol table subsection encoder.
pub fn new() -> Self {
SymbolTable {
bytes: vec![],
num_added: 0,
}
}
/// Define a function symbol in this symbol table.
///
/// The `name` must be omitted if `index` references an imported table and
/// the `WASM_SYM_EXPLICIT_NAME` flag is not set.
pub fn function(&mut self, flags: u32, index: u32, name: Option<&str>) -> &mut Self {
SYMTAB_FUNCTION.encode(&mut self.bytes);
flags.encode(&mut self.bytes);
index.encode(&mut self.bytes);
if let Some(name) = name {
name.encode(&mut self.bytes);
}
self.num_added += 1;
self
}
/// Define a global symbol in this symbol table.
///
/// The `name` must be omitted if `index` references an imported table and
/// the `WASM_SYM_EXPLICIT_NAME` flag is not set.
pub fn global(&mut self, flags: u32, index: u32, name: Option<&str>) -> &mut Self {
SYMTAB_GLOBAL.encode(&mut self.bytes);
flags.encode(&mut self.bytes);
index.encode(&mut self.bytes);
if let Some(name) = name {
name.encode(&mut self.bytes);
}
self.num_added += 1;
self
}
// TODO: tags
/// Define a table symbol in this symbol table.
///
/// The `name` must be omitted if `index` references an imported table and
/// the `WASM_SYM_EXPLICIT_NAME` flag is not set.
pub fn table(&mut self, flags: u32, index: u32, name: Option<&str>) -> &mut Self {
SYMTAB_TABLE.encode(&mut self.bytes);
flags.encode(&mut self.bytes);
index.encode(&mut self.bytes);
if let Some(name) = name {
name.encode(&mut self.bytes);
}
self.num_added += 1;
self
}
/// Add a data symbol to this symbol table.
pub fn data(
&mut self,
flags: u32,
name: &str,
definition: Option<DataSymbolDefinition>,
) -> &mut Self {
SYMTAB_DATA.encode(&mut self.bytes);
flags.encode(&mut self.bytes);
name.encode(&mut self.bytes);
if let Some(def) = definition {
def.index.encode(&mut self.bytes);
def.offset.encode(&mut self.bytes);
def.size.encode(&mut self.bytes);
}
self.num_added += 1;
self
}
// TODO: sections
/// This is a weak symbol.
///
/// This flag is mutually exclusive with `WASM_SYM_BINDING_LOCAL`.
///
/// When linking multiple modules defining the same symbol, all weak
/// definitions are discarded if any strong definitions exist; then if
/// multiple weak definitions exist all but one (unspecified) are discarded;
/// and finally it is an error if more than one definition remains.
pub const WASM_SYM_BINDING_WEAK: u32 = 0x1;
/// This is a local symbol.
///
/// This flag is mutually exclusive with `WASM_SYM_BINDING_WEAK`.
///
/// Local symbols are not to be exported, or linked to other
/// modules/sections. The names of all non-local symbols must be unique, but
/// the names of local symbols are not considered for uniqueness. A local
/// function or global symbol cannot reference an import.
pub const WASM_SYM_BINDING_LOCAL: u32 = 0x02;
/// This is a hidden symbol.
///
/// Hidden symbols are not to be exported when performing the final link,
/// but may be linked to other modules.
pub const WASM_SYM_VISIBILITY_HIDDEN: u32 = 0x04;
/// This symbol is not defined.
///
/// For non-data symbols, this must match whether the symbol is an import or
/// is defined; for data symbols, determines whether a segment is specified.
pub const WASM_SYM_UNDEFINED: u32 = 0x10;
/// This symbol is intended to be exported from the wasm module to the host
/// environment.
///
/// This differs from the visibility flags in that it effects the static
/// linker.
pub const WASM_SYM_EXPORTED: u32 = 0x20;
/// This symbol uses an explicit symbol name, rather than reusing the name
/// from a wasm import.
///
/// This allows it to remap imports from foreign WebAssembly modules into
/// local symbols with different names.
pub const WASM_SYM_EXPLICIT_NAME: u32 = 0x40;
/// This symbol is intended to be included in the linker output, regardless
/// of whether it is used by the program.
pub const WASM_SYM_NO_STRIP: u32 = 0x80;
}
impl Encode for SymbolTable {
fn encode(&self, sink: &mut Vec<u8>) {
sink.push(WASM_SYMBOL_TABLE);
encode_section(sink, self.num_added, &self.bytes);
}
}
/// The definition of a data symbol within a symbol table.
#[derive(Clone, Debug)]
pub struct DataSymbolDefinition {
/// The index of the data segment that this symbol is in.
pub index: u32,
/// The offset of this symbol within its segment.
pub offset: u32,
/// The byte size (which can be zero) of this data symbol.
///
/// Note that `offset + size` must be less than or equal to the segment's
/// size.
pub size: u32,
}

116
vendor/wasm-encoder/src/core/memories.rs vendored Normal file
View File

@@ -0,0 +1,116 @@
use crate::{Encode, Section, SectionId, encode_section};
use alloc::vec::Vec;
/// An encoder for the memory section.
///
/// Memory sections are only supported for modules.
///
/// # Example
///
/// ```
/// use wasm_encoder::{Module, MemorySection, MemoryType};
///
/// let mut memories = MemorySection::new();
/// memories.memory(MemoryType {
/// minimum: 1,
/// maximum: None,
/// memory64: false,
/// shared: false,
/// page_size_log2: None,
/// });
///
/// let mut module = Module::new();
/// module.section(&memories);
///
/// let wasm_bytes = module.finish();
/// ```
#[derive(Clone, Default, Debug)]
pub struct MemorySection {
bytes: Vec<u8>,
num_added: u32,
}
impl MemorySection {
/// Create a new memory section encoder.
pub fn new() -> Self {
Self::default()
}
/// The number of memories in the section.
pub fn len(&self) -> u32 {
self.num_added
}
/// Determines if the section is empty.
pub fn is_empty(&self) -> bool {
self.num_added == 0
}
/// Define a memory.
pub fn memory(&mut self, memory_type: MemoryType) -> &mut Self {
memory_type.encode(&mut self.bytes);
self.num_added += 1;
self
}
}
impl Encode for MemorySection {
fn encode(&self, sink: &mut Vec<u8>) {
encode_section(sink, self.num_added, &self.bytes);
}
}
impl Section for MemorySection {
fn id(&self) -> u8 {
SectionId::Memory.into()
}
}
/// A memory's type.
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
pub struct MemoryType {
/// Minimum size, in pages, of this memory
pub minimum: u64,
/// Maximum size, in pages, of this memory
pub maximum: Option<u64>,
/// Whether or not this is a 64-bit memory.
pub memory64: bool,
/// Whether or not this memory is shared.
pub shared: bool,
/// The log base 2 of a custom page size for this memory.
///
/// The default page size for Wasm memories is 64KiB, i.e. 2<sup>16</sup> or
/// `65536`.
///
/// After the introduction of [the custom-page-sizes
/// proposal](https://github.com/WebAssembly/custom-page-sizes), Wasm can
/// customize the page size. It must be a power of two that is less than or
/// equal to 64KiB. Attempting to encode an invalid page size may panic.
pub page_size_log2: Option<u32>,
}
impl Encode for MemoryType {
fn encode(&self, sink: &mut Vec<u8>) {
let mut flags = 0;
if self.maximum.is_some() {
flags |= 0b0001;
}
if self.shared {
flags |= 0b0010;
}
if self.memory64 {
flags |= 0b0100;
}
if self.page_size_log2.is_some() {
flags |= 0b1000;
}
sink.push(flags);
self.minimum.encode(sink);
if let Some(max) = self.maximum {
max.encode(sink);
}
if let Some(p) = self.page_size_log2 {
p.encode(sink);
}
}
}

305
vendor/wasm-encoder/src/core/names.rs vendored Normal file
View File

@@ -0,0 +1,305 @@
use crate::{CustomSection, Encode, Section, SectionId, encoding_size};
use alloc::borrow::Cow;
use alloc::vec;
use alloc::vec::Vec;
/// An encoder for the custom `name` section.
///
/// # Example
///
/// ```
/// use wasm_encoder::{Module, NameSection, NameMap};
///
/// let mut names = NameSection::new();
/// names.module("the module name");
///
/// let mut function_names = NameMap::new();
/// function_names.append(0, "name of function 0");
/// function_names.append(1, "a better function");
/// function_names.append(3, "the best function");
/// names.functions(&function_names);
///
/// let mut module = Module::new();
/// module.section(&names);
///
/// let wasm_bytes = module.finish();
/// ```
#[derive(Clone, Debug, Default)]
pub struct NameSection {
bytes: Vec<u8>,
}
enum Subsection {
// Currently specified in the wasm spec's appendix
Module = 0,
Function = 1,
Local = 2,
// specified as part of the extended name section proposal
//
// https://github.com/WebAssembly/extended-name-section/blob/main/proposals/extended-name-section/Overview.md
Label = 3,
Type = 4,
Table = 5,
Memory = 6,
Global = 7,
Element = 8,
Data = 9,
// https://github.com/WebAssembly/gc/issues/193
Field = 10,
// https://github.com/WebAssembly/exception-handling/pull/213
Tag = 11,
}
impl NameSection {
/// Creates a new blank `name` custom section.
pub fn new() -> Self {
Self::default()
}
/// Appends a module name subsection to this section.
///
/// This will indicate that the name of the entire module should be the
/// `name` specified. Note that this should be encoded first before other
/// subsections.
pub fn module(&mut self, name: &str) {
let len = encoding_size(u32::try_from(name.len()).unwrap());
self.subsection_header(Subsection::Module, len + name.len());
name.encode(&mut self.bytes);
}
/// Appends a subsection for the names of all functions in this wasm module.
///
/// Function names are declared in the `names` map provided where the index
/// in the map corresponds to the wasm index of the function. This section
/// should come after the module name subsection (if present) and before the
/// locals subsection (if present).
pub fn functions(&mut self, names: &NameMap) {
self.subsection_header(Subsection::Function, names.size());
names.encode(&mut self.bytes);
}
/// Appends a subsection for the names of locals within functions in this
/// wasm module.
///
/// This section should come after the function name subsection (if present)
/// and before the labels subsection (if present).
pub fn locals(&mut self, names: &IndirectNameMap) {
self.subsection_header(Subsection::Local, names.size());
names.encode(&mut self.bytes);
}
/// Appends a subsection for the names of labels within functions in this
/// wasm module.
///
/// This section should come after the local name subsection (if present)
/// and before the type subsection (if present).
pub fn labels(&mut self, names: &IndirectNameMap) {
self.subsection_header(Subsection::Label, names.size());
names.encode(&mut self.bytes);
}
/// Appends a subsection for the names of all types in this wasm module.
///
/// This section should come after the label name subsection (if present)
/// and before the table subsection (if present).
pub fn types(&mut self, names: &NameMap) {
self.subsection_header(Subsection::Type, names.size());
names.encode(&mut self.bytes);
}
/// Appends a subsection for the names of all tables in this wasm module.
///
/// This section should come after the type name subsection (if present)
/// and before the memory subsection (if present).
pub fn tables(&mut self, names: &NameMap) {
self.subsection_header(Subsection::Table, names.size());
names.encode(&mut self.bytes);
}
/// Appends a subsection for the names of all memories in this wasm module.
///
/// This section should come after the table name subsection (if present)
/// and before the global subsection (if present).
pub fn memories(&mut self, names: &NameMap) {
self.subsection_header(Subsection::Memory, names.size());
names.encode(&mut self.bytes);
}
/// Appends a subsection for the names of all globals in this wasm module.
///
/// This section should come after the memory name subsection (if present)
/// and before the element subsection (if present).
pub fn globals(&mut self, names: &NameMap) {
self.subsection_header(Subsection::Global, names.size());
names.encode(&mut self.bytes);
}
/// Appends a subsection for the names of all elements in this wasm module.
///
/// This section should come after the global name subsection (if present)
/// and before the data subsection (if present).
pub fn elements(&mut self, names: &NameMap) {
self.subsection_header(Subsection::Element, names.size());
names.encode(&mut self.bytes);
}
/// Appends a subsection for the names of all data in this wasm module.
///
/// This section should come after the element name subsection (if present)
/// and before the field subsection (if present).
pub fn data(&mut self, names: &NameMap) {
self.subsection_header(Subsection::Data, names.size());
names.encode(&mut self.bytes);
}
/// Appends a subsection for the names of all tags in this wasm module.
///
/// This section should come after the data name subsection (if present).
pub fn tag(&mut self, names: &NameMap) {
self.subsection_header(Subsection::Tag, names.size());
names.encode(&mut self.bytes);
}
/// Appends a subsection for the names of fields within types in this
/// wasm module.
///
/// This section should come after the data name subsection (if present)
/// and before the tag subsection (if present).
pub fn fields(&mut self, names: &IndirectNameMap) {
self.subsection_header(Subsection::Field, names.size());
names.encode(&mut self.bytes);
}
/// Appends a subsection for the names of all tags in this wasm module.
///
/// This section should come after the field name subsection (if present).
pub fn tags(&mut self, names: &NameMap) {
self.subsection_header(Subsection::Tag, names.size());
names.encode(&mut self.bytes);
}
/// Appends a raw subsection with the given id and data.
pub fn raw(&mut self, id: u8, data: &[u8]) {
self.bytes.push(id);
data.encode(&mut self.bytes);
}
fn subsection_header(&mut self, id: Subsection, len: usize) {
self.bytes.push(id as u8);
len.encode(&mut self.bytes);
}
/// View the encoded section as a CustomSection.
pub fn as_custom<'a>(&'a self) -> CustomSection<'a> {
CustomSection {
name: "name".into(),
data: Cow::Borrowed(&self.bytes),
}
}
}
impl Encode for NameSection {
fn encode(&self, sink: &mut Vec<u8>) {
self.as_custom().encode(sink);
}
}
impl Section for NameSection {
fn id(&self) -> u8 {
SectionId::Custom.into()
}
}
/// A map used to name items in a wasm module, organized by naming each
/// individual index.
///
/// This is used in conjunction with [`NameSection::functions`] and simlar
/// methods.
#[derive(Clone, Debug, Default)]
pub struct NameMap {
bytes: Vec<u8>,
count: u32,
}
impl NameMap {
/// Creates a new empty `NameMap`.
pub fn new() -> NameMap {
NameMap {
bytes: vec![],
count: 0,
}
}
/// Adds a an entry where the item at `idx` has the `name` specified.
///
/// Note that indices should be appended in ascending order of the index
/// value. Each index may only be named once, but not all indices must be
/// named (e.g. `0 foo; 1 bar; 7 qux` is valid but `0 foo; 0 bar` is not).
/// Names do not have to be unique (e.g. `0 foo; 1 foo; 2 foo` is valid).
pub fn append(&mut self, idx: u32, name: &str) {
idx.encode(&mut self.bytes);
name.encode(&mut self.bytes);
self.count += 1;
}
pub(crate) fn size(&self) -> usize {
encoding_size(self.count) + self.bytes.len()
}
/// Returns whether no names have been added to this map.
pub fn is_empty(&self) -> bool {
self.count == 0
}
}
impl Encode for NameMap {
fn encode(&self, sink: &mut Vec<u8>) {
self.count.encode(sink);
sink.extend(&self.bytes);
}
}
/// A map used to describe names with two levels of indirection, as opposed to a
/// [`NameMap`] which has one level of indirection.
///
/// This naming map is used with [`NameSection::locals`], for example.
#[derive(Clone, Debug, Default)]
pub struct IndirectNameMap {
bytes: Vec<u8>,
count: u32,
}
impl IndirectNameMap {
/// Creates a new empty name map.
pub fn new() -> IndirectNameMap {
IndirectNameMap {
bytes: vec![],
count: 0,
}
}
/// Adds a new entry where the item at `idx` has sub-items named within
/// `names` as specified.
///
/// For example if this is describing local names then `idx` is a function
/// index where the indexes within `names` are local indices.
pub fn append(&mut self, idx: u32, names: &NameMap) {
idx.encode(&mut self.bytes);
names.encode(&mut self.bytes);
self.count += 1;
}
fn size(&self) -> usize {
encoding_size(self.count) + self.bytes.len()
}
}
impl Encode for IndirectNameMap {
fn encode(&self, sink: &mut Vec<u8>) {
self.count.encode(sink);
sink.extend(&self.bytes);
}
}

View File

@@ -0,0 +1,181 @@
use crate::{CustomSection, Encode, Section, SectionId};
use alloc::borrow::Cow;
use alloc::vec::Vec;
/// An encoder for the [producers custom
/// section](https://github.com/WebAssembly/tool-conventions/blob/main/ProducersSection.md).
///
/// This section is a non-standard convention that is supported by many toolchains.
///
/// # Example
///
/// ```
/// use wasm_encoder::{ProducersSection, ProducersField, Module};
///
/// // Create a new producers section.
/// let mut field = ProducersField::new();
/// field.value("clang", "14.0.4");
/// field.value("rustc", "1.66.1 (90743e729 2023-01-10)");
/// let mut producers = ProducersSection::new();
/// producers.field("processed-by", &field);
///
/// // Add the producers section to a new Wasm module and get the encoded bytes.
/// let mut module = Module::new();
/// module.section(&producers);
/// let wasm_bytes = module.finish();
/// ```
#[derive(Clone, Debug)]
pub struct ProducersSection {
bytes: Vec<u8>,
num_fields: u32,
}
impl ProducersSection {
/// Construct an empty encoder for the producers custom section.
pub fn new() -> Self {
Self::default()
}
/// Add a field to the section. The spec recommends names for this section
/// are "language", "processed-by", and "sdk". Each field in section must
/// have a unique name.
pub fn field(&mut self, name: &str, values: &ProducersField) -> &mut Self {
name.encode(&mut self.bytes);
values.encode(&mut self.bytes);
self.num_fields += 1;
self
}
}
impl Default for ProducersSection {
fn default() -> Self {
Self {
bytes: Vec::new(),
num_fields: 0,
}
}
}
impl Encode for ProducersSection {
fn encode(&self, sink: &mut Vec<u8>) {
let mut data = Vec::new();
self.num_fields.encode(&mut data);
data.extend(&self.bytes);
CustomSection {
name: "producers".into(),
data: Cow::Borrowed(&data),
}
.encode(sink);
}
}
impl Section for ProducersSection {
fn id(&self) -> u8 {
SectionId::Custom.into()
}
}
/// The value of a field in the producers custom section
#[derive(Clone, Debug)]
pub struct ProducersField {
bytes: Vec<u8>,
num_values: u32,
}
impl ProducersField {
/// Construct an empty encoder for a producers field value
pub fn new() -> Self {
ProducersField::default()
}
/// Add a value to the field encoder. Each value in a field must have a
/// unique name. If there is no sensible value for `version`, use the
/// empty string.
pub fn value(&mut self, name: &str, version: &str) -> &mut Self {
name.encode(&mut self.bytes);
version.encode(&mut self.bytes);
self.num_values += 1;
self
}
}
impl Default for ProducersField {
fn default() -> Self {
Self {
bytes: Vec::new(),
num_values: 0,
}
}
}
impl Encode for ProducersField {
fn encode(&self, sink: &mut Vec<u8>) {
self.num_values.encode(sink);
sink.extend(&self.bytes);
}
}
#[cfg(test)]
mod test {
#[test]
fn roundtrip_example() {
use crate::{Module, ProducersField, ProducersSection};
use wasmparser::{KnownCustom, Parser, Payload};
// Create a new producers section.
let mut field = ProducersField::new();
field.value("clang", "14.0.4");
field.value("rustc", "1.66.1");
let mut producers = ProducersSection::new();
producers.field("processed-by", &field);
// Add the producers section to a new Wasm module and get the encoded bytes.
let mut module = Module::new();
module.section(&producers);
let wasm_bytes = module.finish();
let mut parser = Parser::new(0).parse_all(&wasm_bytes);
let payload = parser
.next()
.expect("parser is not empty")
.expect("element is a payload");
match payload {
Payload::Version { .. } => {}
_ => panic!(""),
}
let payload = parser
.next()
.expect("parser is not empty")
.expect("element is a payload");
match payload {
Payload::CustomSection(c) => {
assert_eq!(c.name(), "producers");
let mut section = match c.as_known() {
KnownCustom::Producers(s) => s.into_iter(),
_ => panic!("unknown custom section"),
};
let field = section
.next()
.expect("section has an element")
.expect("element is a producers field");
assert_eq!(field.name, "processed-by");
let mut values = field.values.into_iter();
let value = values
.next()
.expect("values has an element")
.expect("element is a producers field value");
assert_eq!(value.name, "clang");
assert_eq!(value.version, "14.0.4");
let value = values
.next()
.expect("values has another element")
.expect("element is a producers field value");
assert_eq!(value.name, "rustc");
assert_eq!(value.version, "1.66.1");
}
_ => panic!("unexpected payload"),
}
}
}

40
vendor/wasm-encoder/src/core/start.rs vendored Normal file
View File

@@ -0,0 +1,40 @@
use crate::{Encode, Section, SectionId, encoding_size};
use alloc::vec::Vec;
/// An encoder for the start section of WebAssembly modules.
///
/// # Example
///
/// Note: this doesn't actually define the function at index 0, its type, or its
/// code body, so the resulting Wasm module will be invalid. See `TypeSection`,
/// `FunctionSection`, and `CodeSection` for details on how to generate those
/// things.
///
/// ```
/// use wasm_encoder::{Module, StartSection};
///
/// let start = StartSection { function_index: 0 };
///
/// let mut module = Module::new();
/// module.section(&start);
///
/// let wasm_bytes = module.finish();
/// ```
#[derive(Clone, Copy, Debug)]
pub struct StartSection {
/// The index of the start function.
pub function_index: u32,
}
impl Encode for StartSection {
fn encode(&self, sink: &mut Vec<u8>) {
encoding_size(self.function_index).encode(sink);
self.function_index.encode(sink);
}
}
impl Section for StartSection {
fn id(&self) -> u8 {
SectionId::Start.into()
}
}

130
vendor/wasm-encoder/src/core/tables.rs vendored Normal file
View File

@@ -0,0 +1,130 @@
use crate::{ConstExpr, Encode, RefType, Section, SectionId, ValType, encode_section};
use alloc::vec::Vec;
/// An encoder for the table section.
///
/// Table sections are only supported for modules.
///
/// # Example
///
/// ```
/// use wasm_encoder::{Module, TableSection, TableType, RefType};
///
/// let mut tables = TableSection::new();
/// tables.table(TableType {
/// element_type: RefType::FUNCREF,
/// minimum: 128,
/// maximum: None,
/// table64: false,
/// shared: false,
/// });
///
/// let mut module = Module::new();
/// module.section(&tables);
///
/// let wasm_bytes = module.finish();
/// ```
#[derive(Clone, Default, Debug)]
pub struct TableSection {
bytes: Vec<u8>,
num_added: u32,
}
impl TableSection {
/// Construct a new table section encoder.
pub fn new() -> Self {
Self::default()
}
/// The number of tables in the section.
pub fn len(&self) -> u32 {
self.num_added
}
/// Determines if the section is empty.
pub fn is_empty(&self) -> bool {
self.num_added == 0
}
/// Define a table.
pub fn table(&mut self, table_type: TableType) -> &mut Self {
table_type.encode(&mut self.bytes);
self.num_added += 1;
self
}
/// Define a table with an explicit initialization expression.
///
/// Note that this is part of the function-references proposal.
pub fn table_with_init(&mut self, table_type: TableType, init: &ConstExpr) -> &mut Self {
self.bytes.push(0x40);
self.bytes.push(0x00);
table_type.encode(&mut self.bytes);
init.encode(&mut self.bytes);
self.num_added += 1;
self
}
}
impl Encode for TableSection {
fn encode(&self, sink: &mut Vec<u8>) {
encode_section(sink, self.num_added, &self.bytes);
}
}
impl Section for TableSection {
fn id(&self) -> u8 {
SectionId::Table.into()
}
}
/// A table's type.
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
pub struct TableType {
/// The table's element type.
pub element_type: RefType,
/// Whether or not this is a 64-bit table.
pub table64: bool,
/// Minimum size, in elements, of this table
pub minimum: u64,
/// Maximum size, in elements, of this table
pub maximum: Option<u64>,
/// Whether this table is shared or not.
///
/// This is included the shared-everything-threads proposal.
pub shared: bool,
}
impl TableType {
/// Returns the type used to index this table.
pub fn index_type(&self) -> ValType {
if self.table64 {
ValType::I64
} else {
ValType::I32
}
}
}
impl Encode for TableType {
fn encode(&self, sink: &mut Vec<u8>) {
let mut flags = 0;
if self.maximum.is_some() {
flags |= 0b001;
}
if self.shared {
flags |= 0b010;
}
if self.table64 {
flags |= 0b100;
}
self.element_type.encode(sink);
sink.push(flags);
self.minimum.encode(sink);
if let Some(max) = self.maximum {
max.encode(sink);
}
}
}

86
vendor/wasm-encoder/src/core/tags.rs vendored Normal file
View File

@@ -0,0 +1,86 @@
use crate::{Encode, Section, SectionId, encode_section};
use alloc::vec::Vec;
/// An encoder for the tag section.
///
/// # Example
///
/// ```
/// use wasm_encoder::{Module, TagSection, TagType, TagKind};
///
/// let mut tags = TagSection::new();
/// tags.tag(TagType {
/// kind: TagKind::Exception,
/// func_type_idx: 0,
/// });
///
/// let mut module = Module::new();
/// module.section(&tags);
///
/// let wasm_bytes = module.finish();
/// ```
#[derive(Clone, Default, Debug)]
pub struct TagSection {
bytes: Vec<u8>,
num_added: u32,
}
impl TagSection {
/// Create a new tag section encoder.
pub fn new() -> Self {
Self::default()
}
/// The number of tags in the section.
pub fn len(&self) -> u32 {
self.num_added
}
/// Determines if the section is empty.
pub fn is_empty(&self) -> bool {
self.num_added == 0
}
/// Define a tag.
pub fn tag(&mut self, tag_type: TagType) -> &mut Self {
tag_type.encode(&mut self.bytes);
self.num_added += 1;
self
}
}
impl Encode for TagSection {
fn encode(&self, sink: &mut Vec<u8>) {
encode_section(sink, self.num_added, &self.bytes);
}
}
impl Section for TagSection {
fn id(&self) -> u8 {
SectionId::Tag.into()
}
}
/// Represents a tag kind.
#[repr(u8)]
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum TagKind {
/// The tag is an exception type.
Exception = 0x0,
}
/// A tag's type.
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub struct TagType {
/// The kind of tag
pub kind: TagKind,
/// The function type this tag uses
pub func_type_idx: u32,
}
impl Encode for TagType {
fn encode(&self, sink: &mut Vec<u8>) {
sink.push(self.kind as u8);
self.func_type_idx.encode(sink);
}
}

753
vendor/wasm-encoder/src/core/types.rs vendored Normal file
View File

@@ -0,0 +1,753 @@
use crate::{Encode, Section, SectionId, encode_section};
use alloc::boxed::Box;
use alloc::vec::Vec;
/// Represents a subtype of possible other types in a WebAssembly module.
#[derive(Debug, Clone)]
pub struct SubType {
/// Is the subtype final.
pub is_final: bool,
/// The list of supertype indexes. As of GC MVP, there can be at most one
/// supertype.
pub supertype_idx: Option<u32>,
/// The composite type of the subtype.
pub composite_type: CompositeType,
}
/// Represents a composite type in a WebAssembly module.
#[derive(Debug, Clone)]
pub struct CompositeType {
/// The type defined inside the composite type.
pub inner: CompositeInnerType,
/// Whether the type is shared. This is part of the
/// shared-everything-threads proposal.
pub shared: bool,
/// Optional descriptor attribute.
pub descriptor: Option<u32>,
/// Optional describes attribute.
pub describes: Option<u32>,
}
/// A [`CompositeType`] can contain one of these types.
#[derive(Debug, Clone)]
pub enum CompositeInnerType {
/// The type is for a function.
Func(FuncType),
/// The type is for an array.
Array(ArrayType),
/// The type is for a struct.
Struct(StructType),
/// The type is for a continuation.
Cont(ContType),
}
/// Represents a type of a function in a WebAssembly module.
#[derive(Debug, Clone, Eq, PartialEq, Hash)]
pub struct FuncType {
/// The combined parameters and result types.
params_results: Box<[ValType]>,
/// The number of parameter types.
len_params: usize,
}
/// Represents a type of an array in a WebAssembly module.
#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash)]
pub struct ArrayType(pub FieldType);
/// Represents a type of a struct in a WebAssembly module.
#[derive(Debug, Clone, Eq, PartialEq, Hash)]
pub struct StructType {
/// Struct fields.
pub fields: Box<[FieldType]>,
}
/// Field type in composite types (structs, arrays).
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Ord, PartialOrd)]
pub struct FieldType {
/// Storage type of the field.
pub element_type: StorageType,
/// Is the field mutable.
pub mutable: bool,
}
/// Storage type for composite type fields.
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Ord, PartialOrd)]
pub enum StorageType {
/// The `i8` type.
I8,
/// The `i16` type.
I16,
/// A value type.
Val(ValType),
}
impl StorageType {
/// Is this storage type defaultable?
pub fn is_defaultable(&self) -> bool {
self.unpack().is_defaultable()
}
/// Unpack this storage type into a value type.
pub fn unpack(&self) -> ValType {
match self {
StorageType::I8 | StorageType::I16 => ValType::I32,
StorageType::Val(v) => *v,
}
}
}
/// Represents a type of a continuation in a WebAssembly module.
#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash)]
pub struct ContType(pub u32);
/// The type of a core WebAssembly value.
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Ord, PartialOrd)]
pub enum ValType {
/// The `i32` type.
I32,
/// The `i64` type.
I64,
/// The `f32` type.
F32,
/// The `f64` type.
F64,
/// The `v128` type.
///
/// Part of the SIMD proposal.
V128,
/// A reference type.
///
/// The `funcref` and `externref` type fall into this category and the full
/// generalization here is due to the implementation of the
/// function-references proposal.
Ref(RefType),
}
impl ValType {
/// Is this a numeric value type?
pub fn is_numeric(&self) -> bool {
match self {
ValType::I32 | ValType::I64 | ValType::F32 | ValType::F64 => true,
ValType::V128 | ValType::Ref(_) => false,
}
}
/// Is this a vector type?
pub fn is_vector(&self) -> bool {
match self {
ValType::V128 => true,
ValType::I32 | ValType::I64 | ValType::F32 | ValType::F64 | ValType::Ref(_) => false,
}
}
/// Is this a reference type?
pub fn is_reference(&self) -> bool {
match self {
ValType::Ref(_) => true,
ValType::I32 | ValType::I64 | ValType::F32 | ValType::F64 | ValType::V128 => false,
}
}
}
impl FuncType {
/// Creates a new [`FuncType`] from the given `params` and `results`.
pub fn new<P, R>(params: P, results: R) -> Self
where
P: IntoIterator<Item = ValType>,
R: IntoIterator<Item = ValType>,
{
let mut buffer = params.into_iter().collect::<Vec<_>>();
let len_params = buffer.len();
buffer.extend(results);
Self::from_parts(buffer.into(), len_params)
}
#[inline]
pub(crate) fn from_parts(params_results: Box<[ValType]>, len_params: usize) -> Self {
Self {
params_results,
len_params,
}
}
/// Returns a shared slice to the parameter types of the [`FuncType`].
#[inline]
pub fn params(&self) -> &[ValType] {
&self.params_results[..self.len_params]
}
/// Returns a shared slice to the result types of the [`FuncType`].
#[inline]
pub fn results(&self) -> &[ValType] {
&self.params_results[self.len_params..]
}
}
impl ValType {
/// Alias for the `funcref` type in WebAssembly
pub const FUNCREF: ValType = ValType::Ref(RefType::FUNCREF);
/// Alias for the `externref` type in WebAssembly
pub const EXTERNREF: ValType = ValType::Ref(RefType::EXTERNREF);
/// Alias for the `exnref` type in WebAssembly
pub const EXNREF: ValType = ValType::Ref(RefType::EXNREF);
/// Is this value defaultable?
pub fn is_defaultable(&self) -> bool {
match self {
ValType::Ref(r) => r.nullable,
ValType::I32 | ValType::I64 | ValType::F32 | ValType::F64 | ValType::V128 => true,
}
}
}
impl Encode for StorageType {
fn encode(&self, sink: &mut Vec<u8>) {
match self {
StorageType::I8 => sink.push(0x78),
StorageType::I16 => sink.push(0x77),
StorageType::Val(vt) => vt.encode(sink),
}
}
}
impl Encode for ValType {
fn encode(&self, sink: &mut Vec<u8>) {
match self {
ValType::I32 => sink.push(0x7F),
ValType::I64 => sink.push(0x7E),
ValType::F32 => sink.push(0x7D),
ValType::F64 => sink.push(0x7C),
ValType::V128 => sink.push(0x7B),
ValType::Ref(rt) => rt.encode(sink),
}
}
}
/// A reference type.
///
/// This is largely part of the function references proposal for WebAssembly but
/// additionally is used by the `funcref` and `externref` types. The full
/// generality of this type is only exercised with function-references.
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Ord, PartialOrd)]
#[allow(missing_docs)]
pub struct RefType {
pub nullable: bool,
pub heap_type: HeapType,
}
impl RefType {
/// Alias for the `anyref` type in WebAssembly.
pub const ANYREF: RefType = RefType {
nullable: true,
heap_type: HeapType::Abstract {
shared: false,
ty: AbstractHeapType::Any,
},
};
/// Alias for the `anyref` type in WebAssembly.
pub const EQREF: RefType = RefType {
nullable: true,
heap_type: HeapType::Abstract {
shared: false,
ty: AbstractHeapType::Eq,
},
};
/// Alias for the `funcref` type in WebAssembly.
pub const FUNCREF: RefType = RefType {
nullable: true,
heap_type: HeapType::Abstract {
shared: false,
ty: AbstractHeapType::Func,
},
};
/// Alias for the `externref` type in WebAssembly.
pub const EXTERNREF: RefType = RefType {
nullable: true,
heap_type: HeapType::Abstract {
shared: false,
ty: AbstractHeapType::Extern,
},
};
/// Alias for the `i31ref` type in WebAssembly.
pub const I31REF: RefType = RefType {
nullable: true,
heap_type: HeapType::Abstract {
shared: false,
ty: AbstractHeapType::I31,
},
};
/// Alias for the `arrayref` type in WebAssembly.
pub const ARRAYREF: RefType = RefType {
nullable: true,
heap_type: HeapType::Abstract {
shared: false,
ty: AbstractHeapType::Array,
},
};
/// Alias for the `exnref` type in WebAssembly.
pub const EXNREF: RefType = RefType {
nullable: true,
heap_type: HeapType::Abstract {
shared: false,
ty: AbstractHeapType::Exn,
},
};
/// Create a new abstract reference type.
pub fn new_abstract(ty: AbstractHeapType, nullable: bool, shared: bool) -> Self {
Self {
nullable,
heap_type: HeapType::Abstract { shared, ty },
}
}
/// Set the nullability of this reference type.
pub fn nullable(mut self, nullable: bool) -> Self {
self.nullable = nullable;
self
}
}
impl Encode for RefType {
fn encode(&self, sink: &mut Vec<u8>) {
match self {
// Binary abbreviations (i.e., short form), for when the ref is
// nullable.
RefType {
nullable: true,
heap_type: heap @ HeapType::Abstract { .. },
} => {
heap.encode(sink);
}
// Generic 'ref null <heaptype>' encoding (i.e., long form).
RefType {
nullable: true,
heap_type,
} => {
sink.push(0x63);
heap_type.encode(sink);
}
// Generic 'ref <heaptype>' encoding.
RefType {
nullable: false,
heap_type,
} => {
sink.push(0x64);
heap_type.encode(sink);
}
}
}
}
impl From<RefType> for ValType {
fn from(ty: RefType) -> ValType {
ValType::Ref(ty)
}
}
/// Part of the function references proposal.
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Ord, PartialOrd)]
pub enum HeapType {
/// An abstract heap type; e.g., `anyref`.
Abstract {
/// Whether the type is shared.
shared: bool,
/// The actual heap type.
ty: AbstractHeapType,
},
/// A concrete Wasm-defined type at the given index.
Concrete(u32),
/// An exact type.
Exact(u32),
}
impl HeapType {
/// Alias for the unshared `any` heap type.
pub const ANY: Self = Self::Abstract {
shared: false,
ty: AbstractHeapType::Any,
};
/// Alias for the unshared `func` heap type.
pub const FUNC: Self = Self::Abstract {
shared: false,
ty: AbstractHeapType::Func,
};
/// Alias for the unshared `extern` heap type.
pub const EXTERN: Self = Self::Abstract {
shared: false,
ty: AbstractHeapType::Extern,
};
/// Alias for the unshared `i31` heap type.
pub const I31: Self = Self::Abstract {
shared: false,
ty: AbstractHeapType::I31,
};
}
impl Encode for HeapType {
fn encode(&self, sink: &mut Vec<u8>) {
match self {
HeapType::Abstract { shared, ty } => {
if *shared {
sink.push(0x65);
}
ty.encode(sink);
}
// Note that this is encoded as a signed type rather than unsigned
// as it's decoded as an s33
HeapType::Concrete(i) => i64::from(*i).encode(sink),
// Exact type is u32
HeapType::Exact(i) => {
sink.push(0x62);
u32::from(*i).encode(sink)
}
}
}
}
/// An abstract heap type.
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Ord, PartialOrd)]
pub enum AbstractHeapType {
/// Untyped (any) function.
Func,
/// The abstract external heap type.
Extern,
/// The abstract `any` heap type.
///
/// The common supertype (a.k.a. top) of all internal types.
Any,
/// The abstract `none` heap type.
///
/// The common subtype (a.k.a. bottom) of all internal types.
None,
/// The abstract `noextern` heap type.
///
/// The common subtype (a.k.a. bottom) of all external types.
NoExtern,
/// The abstract `nofunc` heap type.
///
/// The common subtype (a.k.a. bottom) of all function types.
NoFunc,
/// The abstract `eq` heap type.
///
/// The common supertype of all referenceable types on which comparison
/// (ref.eq) is allowed.
Eq,
/// The abstract `struct` heap type.
///
/// The common supertype of all struct types.
Struct,
/// The abstract `array` heap type.
///
/// The common supertype of all array types.
Array,
/// The unboxed `i31` heap type.
I31,
/// The abstract `exception` heap type.
Exn,
/// The abstract `noexn` heap type.
NoExn,
/// The abstract `cont` heap type.
Cont,
/// The abstract `nocont` heap type.
NoCont,
}
impl Encode for AbstractHeapType {
fn encode(&self, sink: &mut Vec<u8>) {
use AbstractHeapType::*;
match self {
Func => sink.push(0x70),
Extern => sink.push(0x6F),
Any => sink.push(0x6E),
None => sink.push(0x71),
NoExtern => sink.push(0x72),
NoFunc => sink.push(0x73),
Eq => sink.push(0x6D),
Struct => sink.push(0x6B),
Array => sink.push(0x6A),
I31 => sink.push(0x6C),
Exn => sink.push(0x69),
NoExn => sink.push(0x74),
Cont => sink.push(0x68),
NoCont => sink.push(0x75),
}
}
}
/// An encoder for the type section of WebAssembly modules.
///
/// # Example
///
/// ```rust
/// use wasm_encoder::{Module, TypeSection, ValType};
///
/// let mut types = TypeSection::new();
///
/// types.ty().function([ValType::I32, ValType::I32], [ValType::I64]);
///
/// let mut module = Module::new();
/// module.section(&types);
///
/// let bytes = module.finish();
/// ```
#[derive(Clone, Debug, Default)]
pub struct TypeSection {
bytes: Vec<u8>,
num_added: u32,
}
impl TypeSection {
/// Create a new module type section encoder.
pub fn new() -> Self {
Self::default()
}
/// The number of types in the section.
pub fn len(&self) -> u32 {
self.num_added
}
/// Determines if the section is empty.
pub fn is_empty(&self) -> bool {
self.num_added == 0
}
/// Encode a function type in this type section.
#[must_use = "the encoder must be used to encode the type"]
pub fn ty(&mut self) -> CoreTypeEncoder<'_> {
self.num_added += 1;
CoreTypeEncoder {
bytes: &mut self.bytes,
push_prefix_if_component_core_type: false,
}
}
}
impl Encode for TypeSection {
fn encode(&self, sink: &mut Vec<u8>) {
encode_section(sink, self.num_added, &self.bytes);
}
}
impl Section for TypeSection {
fn id(&self) -> u8 {
SectionId::Type.into()
}
}
/// A single-use encoder for encoding a type; this forces all encoding for a
/// type to be done in a single shot.
#[derive(Debug)]
pub struct CoreTypeEncoder<'a> {
pub(crate) bytes: &'a mut Vec<u8>,
// For the time being, this flag handles an ambiguous encoding in the
// component model: the `0x50` opcode represents both a core module type as
// well as a GC non-final `sub` type. To avoid this, the component model
// specification requires us to prefix a non-final `sub` type with `0x00`
// when it is used as a top-level core type of a component. Eventually
// (prior to the component model's v1.0 release), a module type will get a
// new opcode and this special logic can go away.
pub(crate) push_prefix_if_component_core_type: bool,
}
impl<'a> CoreTypeEncoder<'a> {
/// Define a function type in this type section.
pub fn function<P, R>(mut self, params: P, results: R)
where
P: IntoIterator<Item = ValType>,
P::IntoIter: ExactSizeIterator,
R: IntoIterator<Item = ValType>,
R::IntoIter: ExactSizeIterator,
{
self.encode_function(params, results);
}
/// Define a function type in this type section.
pub fn func_type(mut self, ty: &FuncType) {
self.encode_function(ty.params().iter().cloned(), ty.results().iter().cloned());
}
fn encode_function<P, R>(&mut self, params: P, results: R)
where
P: IntoIterator<Item = ValType>,
P::IntoIter: ExactSizeIterator,
R: IntoIterator<Item = ValType>,
R::IntoIter: ExactSizeIterator,
{
let params = params.into_iter();
let results = results.into_iter();
self.bytes.push(0x60);
params.len().encode(self.bytes);
params.for_each(|p| p.encode(self.bytes));
results.len().encode(self.bytes);
results.for_each(|p| p.encode(self.bytes));
}
/// Define an array type in this type section.
pub fn array(mut self, ty: &StorageType, mutable: bool) {
self.encode_array(ty, mutable);
}
fn encode_array(&mut self, ty: &StorageType, mutable: bool) {
self.bytes.push(0x5e);
self.encode_field(ty, mutable);
}
fn encode_field(&mut self, ty: &StorageType, mutable: bool) {
ty.encode(self.bytes);
self.bytes.push(mutable as u8);
}
/// Define a struct type in this type section.
pub fn struct_<F>(mut self, fields: F)
where
F: IntoIterator<Item = FieldType>,
F::IntoIter: ExactSizeIterator,
{
self.encode_struct(fields);
}
fn encode_struct<F>(&mut self, fields: F)
where
F: IntoIterator<Item = FieldType>,
F::IntoIter: ExactSizeIterator,
{
let fields = fields.into_iter();
self.bytes.push(0x5f);
fields.len().encode(self.bytes);
for f in fields {
self.encode_field(&f.element_type, f.mutable);
}
}
/// Define a continuation type in this subsection
pub fn cont(mut self, ty: &ContType) {
self.encode_cont(ty)
}
fn encode_cont(&mut self, ty: &ContType) {
self.bytes.push(0x5d);
i64::from(ty.0).encode(self.bytes);
}
/// Define an explicit subtype in this type section.
pub fn subtype(mut self, ty: &SubType) {
self.encode_subtype(ty)
}
/// Define an explicit subtype in this type section.
fn encode_subtype(&mut self, ty: &SubType) {
// We only need to emit a prefix byte before the actual composite type
// when either the `sub` type is not final or it has a declared super
// type (see notes on `push_prefix_if_component_core_type`).
if ty.supertype_idx.is_some() || !ty.is_final {
if ty.is_final {
self.bytes.push(0x4f);
} else {
if self.push_prefix_if_component_core_type {
self.bytes.push(0x00);
}
self.bytes.push(0x50);
}
ty.supertype_idx.encode(self.bytes);
}
if ty.composite_type.shared {
self.bytes.push(0x65);
}
if let Some(index) = ty.composite_type.describes {
self.bytes.push(0x4c);
index.encode(self.bytes);
}
if let Some(index) = ty.composite_type.descriptor {
self.bytes.push(0x4d);
index.encode(self.bytes);
}
match &ty.composite_type.inner {
CompositeInnerType::Func(ty) => {
self.encode_function(ty.params().iter().copied(), ty.results().iter().copied())
}
CompositeInnerType::Array(ArrayType(ty)) => {
self.encode_array(&ty.element_type, ty.mutable)
}
CompositeInnerType::Struct(ty) => self.encode_struct(ty.fields.iter().cloned()),
CompositeInnerType::Cont(ty) => self.encode_cont(ty),
}
}
/// Define an explicit recursion group in this type section.
pub fn rec<T>(mut self, types: T)
where
T: IntoIterator<Item = SubType>,
T::IntoIter: ExactSizeIterator,
{
// When emitting a `rec` group, we will never emit `sub`'s special
// `0x00` prefix; that is only necessary when `sub` is not wrapped by
// `rec` (see notes on `push_prefix_if_component_core_type`).
self.push_prefix_if_component_core_type = false;
let types = types.into_iter();
self.bytes.push(0x4e);
types.len().encode(self.bytes);
types.for_each(|t| {
self.encode_subtype(&t);
});
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::Module;
use wasmparser::WasmFeatures;
#[test]
fn func_types_dont_require_wasm_gc() {
let mut types = TypeSection::new();
types.ty().subtype(&SubType {
is_final: true,
supertype_idx: None,
composite_type: CompositeType {
inner: CompositeInnerType::Func(FuncType::new([], [])),
shared: false,
descriptor: None,
describes: None,
},
});
let mut module = Module::new();
module.section(&types);
let wasm_bytes = module.finish();
let mut validator =
wasmparser::Validator::new_with_features(WasmFeatures::default() & !WasmFeatures::GC);
validator.validate_all(&wasm_bytes).expect(
"Encoding pre Wasm GC type should not accidentally use Wasm GC specific encoding",
);
}
}