#[cfg(feature = "component-model")] usecrate::component::Component; usecrate::core::*; usecrate::encode::Encode; usecrate::token::*; usecrate::Wat; use std::borrow::Cow; use std::marker; #[cfg(feature = "dwarf")] use std::path::Path;
/// Options that can be specified when encoding a component or a module to /// customize what the final binary looks like. /// /// Methods such as [`Module::encode`], [`Wat::encode`], and /// [`Component::encode`] will use the default options. #[derive(Default)] pubstruct EncodeOptions<'a> { #[cfg(feature = "dwarf")]
dwarf_info: Option<(&'a Path, &'a str, GenerateDwarf)>,
_marker: marker::PhantomData<&'a str>,
}
#[cfg(feature = "dwarf")] mod dwarf;
#[cfg(not(feature = "dwarf"))] mod dwarf_disabled; #[cfg(not(feature = "dwarf"))] useself::dwarf_disabled as dwarf;
/// Configuration of how DWARF debugging information may be generated. #[derive(Copy, Clone, Debug)] #[non_exhaustive] pubenum GenerateDwarf { /// Only generate line tables to map binary offsets back to source /// locations.
Lines,
/// Generate full debugging information for both line numbers and /// variables/locals/operands.
Full,
}
impl<'a> EncodeOptions<'a> { /// Creates a new set of default encoding options. pubfn new() -> EncodeOptions<'a> {
EncodeOptions::default()
}
/// Enables emission of DWARF debugging information in the final binary. /// /// This method will use the `file` specified as the source file for the /// `*.wat` file whose `contents` must also be supplied here. These are /// used to calculate filenames/line numbers and are referenced from the /// generated DWARF. #[cfg(feature = "dwarf")] pubfn dwarf(&mutself, file: &'a Path, contents: &'a str, style: GenerateDwarf) -> &mutSelf { self.dwarf_info = Some((file, contents, style)); self
}
/// Encodes the given [`Module`] with these options. /// /// For more information see [`Module::encode`]. pubfn encode_module(
&self,
module: &mut Module<'_>,
) -> std::result::Result<Vec<u8>, crate::Error> {
module.resolve()?;
Ok(match &module.kind {
ModuleKind::Text(fields) => encode(&module.id, &module.name, fields, self),
ModuleKind::Binary(blobs) => blobs.iter().flat_map(|b| b.iter().cloned()).collect(),
})
}
/// Encodes the given [`Component`] with these options. /// /// For more information see [`Component::encode`]. #[cfg(feature = "component-model")] pubfn encode_component(
&self,
component: &mut Component<'_>,
) -> std::result::Result<Vec<u8>, crate::Error> {
component.resolve()?;
Ok(crate::component::binary::encode(component, self))
}
/// Encodes the given [`Wat`] with these options. /// /// For more information see [`Wat::encode`]. pubfn encode_wat(&self, wat: &mut Wat<'_>) -> std::result::Result<Vec<u8>, crate::Error> { match wat {
Wat::Module(m) => self.encode_module(m), #[cfg(feature = "component-model")]
Wat::Component(c) => self.encode_component(c), #[cfg(not(feature = "component-model"))]
Wat::Component(_) => unreachable!(),
}
}
}
pub(crate) fn encode(
module_id: &Option<Id<'_>>,
module_name: &Option<NameAnnotation<'_>>,
fields: &[ModuleField<'_>],
opts: &EncodeOptions,
) -> Vec<u8> { use CustomPlace::*; use CustomPlaceAnchor::*;
// Prepare to and emit the code section. This is where DWARF may optionally // be emitted depending on configuration settings. Note that `code_section` // will internally emit the branch hints section if necessary. let names = find_names(module_id, module_name, fields); let num_import_funcs = imports
.iter()
.filter(|i| matches!(i.item.kind, ItemKind::Func(..)))
.count() as u32; letmut dwarf = dwarf::Dwarf::new(num_import_funcs, opts, &names, &types);
e.code_section(&funcs, num_import_funcs, dwarf.as_mut());
impl Encoder<'_> { fn custom_sections(&mutself, place: CustomPlace) { for entry inself.customs.iter() { if entry.place() == place {
entry.encode(&mutself.wasm);
}
}
}
fn typed_section<T>(&mutself, list: &[T]) where
T: SectionItem,
{ self.custom_sections(CustomPlace::Before(T::ANCHOR)); if !list.is_empty() { letmut section = T::Section::default(); for item in list {
item.encode(&mut section);
} self.wasm.section(§ion);
} self.custom_sections(CustomPlace::After(T::ANCHOR));
}
/// Encodes the code section of a wasm module module while additionally /// handling the branch hinting proposal. /// /// The branch hinting proposal requires to encode the offsets of the /// instructions relative from the beginning of the function. Here we encode /// each instruction and we save its offset. If needed, we use this /// information to build the branch hint section and insert it before the /// code section. /// /// The `list` provided is the list of functions that are emitted into the /// code section. The `func_index` provided is the initial index of defined /// functions, so it's the count of imported functions. The `dwarf` field is /// optionally used to track debugging information. fn code_section<'a>(
&'a mut self,
list: &[&'a Func<'_>], mut func_index: u32, mut dwarf: Option<&mut dwarf::Dwarf>,
) { self.custom_sections(CustomPlace::Before(CustomPlaceAnchor::Code));
for func in list.iter() { let hints = func.encode(&mut code_section, dwarf.as_deref_mut()); if !hints.is_empty() {
branch_hints.function_hints(func_index, hints.into_iter());
}
func_index += 1;
}
// Branch hints section has to be inserted before the Code section // Insert the section only if we have some hints if !branch_hints.is_empty() { self.wasm.section(&branch_hints);
}
// Finally, insert the Code section from the tmp buffer self.wasm.section(&code_section);
impl From<Index<'_>> for u32 { fn from(i: Index<'_>) -> Self { match i {
Index::Num(i, _) => i,
Index::Id(_) => unreachable!("unresolved index in encoding: {:?}", i),
}
}
}
impl SectionItem for Table<'_> { type Section = wasm_encoder::TableSection; const ANCHOR: CustomPlaceAnchor = CustomPlaceAnchor::Table;
fn encode(&self, section: &mut wasm_encoder::TableSection) {
assert!(self.exports.names.is_empty()); match &self.kind {
TableKind::Normal {
ty,
init_expr: None,
} => {
section.table(ty.to_table_type());
}
TableKind::Normal {
ty,
init_expr: Some(init_expr),
} => {
section.table_with_init(ty.to_table_type(), &init_expr.to_const_expr());
}
_ => panic!("TableKind should be normal during encoding"),
}
}
}
impl SectionItem for Memory<'_> { type Section = wasm_encoder::MemorySection; const ANCHOR: CustomPlaceAnchor = CustomPlaceAnchor::Memory;
fn encode(&self, section: &mut wasm_encoder::MemorySection) {
assert!(self.exports.names.is_empty()); match &self.kind {
MemoryKind::Normal(t) => {
section.memory(t.to_memory_type());
}
_ => panic!("MemoryKind should be normal during encoding"),
}
}
}
impl SectionItem for Global<'_> { type Section = wasm_encoder::GlobalSection; const ANCHOR: CustomPlaceAnchor = CustomPlaceAnchor::Global;
fn encode(&self, section: &mut wasm_encoder::GlobalSection) {
assert!(self.exports.names.is_empty()); let init = match &self.kind {
GlobalKind::Inline(expr) => expr.to_const_expr(),
_ => panic!("GlobalKind should be inline during encoding"),
};
section.global(self.ty.to_global_type(), &init);
}
}
impl SectionItem for Export<'_> { type Section = wasm_encoder::ExportSection; const ANCHOR: CustomPlaceAnchor = CustomPlaceAnchor::Export;
impl SectionItem for Data<'_> { type Section = wasm_encoder::DataSection; const ANCHOR: CustomPlaceAnchor = CustomPlaceAnchor::Data;
fn encode(&self, section: &mut wasm_encoder::DataSection) { letmut data = Vec::new(); for val inself.data.iter() {
val.push_onto(&mut data);
} match &self.kind {
DataKind::Passive => {
section.passive(data);
}
DataKind::Active { memory, offset } => {
section.active(memory.unwrap_u32(), &offset.to_const_expr(), data);
}
}
}
}
impl Func<'_> { /// Encodes the function into `e` while returning all branch hints with /// known relative offsets after encoding. /// /// The `dwarf` field is optional and used to track debugging information /// for each instruction. fn encode(
&self,
section: &mut wasm_encoder::CodeSection, mut dwarf: Option<&mut dwarf::Dwarf>,
) -> Vec<wasm_encoder::BranchHint> {
assert!(self.exports.names.is_empty()); let (expr, locals) = match &self.kind {
FuncKind::Inline { expression, locals } => (expression, locals),
_ => panic!("should only have inline functions in emission"),
};
// Encode the function into a temporary vector because functions are // prefixed with their length. The temporary vector, when encoded, // encodes its length first then the body. letmut func =
wasm_encoder::Function::new_with_locals_types(locals.iter().map(|t| t.ty.into())); let branch_hints = expr.encode(&mut func, dwarf.as_deref_mut()); let func_size = func.byte_len();
section.function(&func);
impl Expression<'_> { /// Encodes this expression into `e` and optionally tracks debugging /// information for each instruction in `dwarf`. /// /// Returns all branch hints, if any, found while parsing this function. fn encode(
&self,
func: &mut wasm_encoder::Function, mut dwarf: Option<&mut dwarf::Dwarf>,
) -> Vec<wasm_encoder::BranchHint> { letmut hints = Vec::with_capacity(self.branch_hints.len()); letmut next_hint = self.branch_hints.iter().peekable(); letmut tmp = Vec::new();
for (i, instr) inself.instrs.iter().enumerate() { // Branch hints are stored in order of increasing `instr_index` so // check to see if the next branch hint matches this instruction's // index. iflet Some(hint) = next_hint.next_if(|h| h.instr_index == i) {
hints.push(wasm_encoder::BranchHint {
branch_func_offset: u32::try_from(func.byte_len() + tmp.len()).unwrap(),
branch_hint_value: hint.value,
});
}
// If DWARF is enabled then track this instruction's binary offset // and source location. iflet Some(dwarf) = &mut dwarf { iflet Some(span) = self.instr_spans.as_ref().map(|s| s[i]) {
dwarf.instr(func.byte_len() + tmp.len(), span);
}
}
// Finally emit the instruction and move to the next.
instr.encode(&mut tmp);
}
func.raw(tmp.iter().copied());
func.instruction(&wasm_encoder::Instruction::End);
impl Encode for BlockType<'_> { fn encode(&self, e: &mut Vec<u8>) { // block types using an index are encoded as an sleb, not a uleb iflet Some(Index::Num(n, _)) = &self.ty.index { return i64::from(*n).encode(e);
} let ty = self
.ty
.inline
.as_ref()
.expect("function type not filled in"); if ty.params.is_empty() && ty.results.is_empty() { return e.push(0x40);
} if ty.params.is_empty() && ty.results.len() == 1 { return ty.results[0].encode(e);
}
panic!("multi-value block types should have an index");
}
}
// Consult the inline type listed for local names of parameters. // This is specifically preserved during the name resolution // pass, but only for functions, so here we can look at the // original source's names. iflet Some(ty) = &f.ty.inline { for (id, name, _) in ty.params.iter() { iflet Some(name) = get_name(id, name) {
local_names.push((local_idx, name));
}
local_idx += 1;
}
} iflet FuncKind::Inline {
locals, expression, ..
} = &f.kind
{ for local in locals.iter() { iflet Some(name) = get_name(&local.id, &local.name) {
local_names.push((local_idx, name));
}
local_idx += 1;
}
for i in expression.instrs.iter() { match i {
Instruction::If(block)
| Instruction::Block(block)
| Instruction::Loop(block)
| Instruction::Try(block)
| Instruction::TryTable(TryTable { block, .. }) => { iflet Some(name) = get_name(&block.label, &block.label_name) {
label_names.push((label_idx, name));
}
label_idx += 1;
}
_ => {}
}
}
} if local_names.len() > 0 {
ret.locals.push((*idx, local_names));
} if label_names.len() > 0 {
ret.labels.push((*idx, label_names));
}
}
// Handle struct fields separately from above iflet ModuleField::Type(ty) = field { letmut field_names = vec![]; match &ty.def.kind {
InnerTypeKind::Func(_) | InnerTypeKind::Array(_) | InnerTypeKind::Cont(_) => {}
InnerTypeKind::Struct(ty_struct) => { for (idx, field) in ty_struct.fields.iter().enumerate() { iflet Some(name) = get_name(&field.id, &None) {
field_names.push((idx as u32, name))
}
}
}
} if field_names.len() > 0 {
ret.fields.push((*idx, field_names))
}
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.