Skip to content

Commit 659f4a6

Browse files
juntyralexcrichton
andauthored
Implement a wasmparser -> wasm-encoder trait (#1628)
* Implement a reencoder helper trait * Use new error type in all conversions * Centralise from impls * Remove mut ref returns * rename trait * reencode the data count section * refactor core module parsing helper * Add some more docs * reorder trait members * Review comments plus a reencoder fuzzer * Use `Reencode` in `wit-component` * Add user error variant * Fix Reencode impl * Add an intersperse section hook to allow more complex user module building * Add docs to section intersperse hook --------- Co-authored-by: Alex Crichton <alex@alexcrichton.com>
1 parent 28e96f6 commit 659f4a6

21 files changed

Lines changed: 1877 additions & 954 deletions

File tree

crates/wasm-encoder/src/component/types.rs

Lines changed: 0 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -527,27 +527,6 @@ impl Encode for PrimitiveValType {
527527
}
528528
}
529529

530-
#[cfg(feature = "wasmparser")]
531-
impl From<wasmparser::PrimitiveValType> for PrimitiveValType {
532-
fn from(ty: wasmparser::PrimitiveValType) -> Self {
533-
match ty {
534-
wasmparser::PrimitiveValType::Bool => PrimitiveValType::Bool,
535-
wasmparser::PrimitiveValType::S8 => PrimitiveValType::S8,
536-
wasmparser::PrimitiveValType::U8 => PrimitiveValType::U8,
537-
wasmparser::PrimitiveValType::S16 => PrimitiveValType::S16,
538-
wasmparser::PrimitiveValType::U16 => PrimitiveValType::U16,
539-
wasmparser::PrimitiveValType::S32 => PrimitiveValType::S32,
540-
wasmparser::PrimitiveValType::U32 => PrimitiveValType::U32,
541-
wasmparser::PrimitiveValType::S64 => PrimitiveValType::S64,
542-
wasmparser::PrimitiveValType::U64 => PrimitiveValType::U64,
543-
wasmparser::PrimitiveValType::F32 => PrimitiveValType::F32,
544-
wasmparser::PrimitiveValType::F64 => PrimitiveValType::F64,
545-
wasmparser::PrimitiveValType::Char => PrimitiveValType::Char,
546-
wasmparser::PrimitiveValType::String => PrimitiveValType::String,
547-
}
548-
}
549-
}
550-
551530
/// Represents a component value type.
552531
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
553532
pub enum ComponentValType {

crates/wasm-encoder/src/core/code.rs

Lines changed: 0 additions & 243 deletions
Original file line numberDiff line numberDiff line change
@@ -103,30 +103,6 @@ impl CodeSection {
103103
self.num_added += 1;
104104
self
105105
}
106-
107-
/// Parses the input `section` given from the `wasmparser` crate and adds
108-
/// all the code to this section.
109-
#[cfg(feature = "wasmparser")]
110-
pub fn parse_section(
111-
&mut self,
112-
section: wasmparser::CodeSectionReader<'_>,
113-
) -> wasmparser::Result<&mut Self> {
114-
for code in section {
115-
self.parse(code?)?;
116-
}
117-
Ok(self)
118-
}
119-
120-
/// Parses a single [`wasmparser::Code`] and adds it to this section.
121-
#[cfg(feature = "wasmparser")]
122-
pub fn parse(&mut self, func: wasmparser::FunctionBody<'_>) -> wasmparser::Result<&mut Self> {
123-
let mut f = Function::new_parsed_locals(&func)?;
124-
let mut reader = func.get_operators_reader()?;
125-
while !reader.eof() {
126-
f.parse(&mut reader)?;
127-
}
128-
Ok(self.function(&f))
129-
}
130106
}
131107

132108
impl Encode for CodeSection {
@@ -238,18 +214,6 @@ impl Function {
238214
Function::new(locals_collected)
239215
}
240216

241-
/// Create a new [`Function`] by parsing the locals declarations from the
242-
/// provided [`wasmparser::FunctionBody`].
243-
#[cfg(feature = "wasmparser")]
244-
pub fn new_parsed_locals(func: &wasmparser::FunctionBody<'_>) -> wasmparser::Result<Self> {
245-
let mut locals = Vec::new();
246-
for pair in func.get_locals_reader()? {
247-
let (cnt, ty) = pair?;
248-
locals.push((cnt, ty.try_into().unwrap()));
249-
}
250-
Ok(Function::new(locals))
251-
}
252-
253217
/// Write an instruction into this function body.
254218
pub fn instruction(&mut self, instruction: &Instruction) -> &mut Self {
255219
instruction.encode(&mut self.bytes);
@@ -312,15 +276,6 @@ impl Function {
312276
pub fn into_raw_body(self) -> Vec<u8> {
313277
self.bytes
314278
}
315-
316-
/// Parses a single instruction from `reader` and adds it to `self`.
317-
#[cfg(feature = "wasmparser")]
318-
pub fn parse(
319-
&mut self,
320-
reader: &mut wasmparser::OperatorsReader<'_>,
321-
) -> wasmparser::Result<&mut Self> {
322-
Ok(self.instruction(&reader.read()?.try_into().unwrap()))
323-
}
324279
}
325280

326281
impl Encode for Function {
@@ -360,17 +315,6 @@ impl Encode for MemArg {
360315
}
361316
}
362317

363-
#[cfg(feature = "wasmparser")]
364-
impl From<wasmparser::MemArg> for MemArg {
365-
fn from(arg: wasmparser::MemArg) -> MemArg {
366-
MemArg {
367-
offset: arg.offset,
368-
align: arg.align.into(),
369-
memory_index: arg.memory,
370-
}
371-
}
372-
}
373-
374318
/// The memory ordering for atomic instructions.
375319
///
376320
/// For an in-depth explanation of memory orderings, see the C++ documentation
@@ -399,16 +343,6 @@ impl Encode for Ordering {
399343
}
400344
}
401345

402-
#[cfg(feature = "wasmparser")]
403-
impl From<wasmparser::Ordering> for Ordering {
404-
fn from(arg: wasmparser::Ordering) -> Ordering {
405-
match arg {
406-
wasmparser::Ordering::SeqCst => Ordering::SeqCst,
407-
wasmparser::Ordering::AcqRel => Ordering::AcqRel,
408-
}
409-
}
410-
}
411-
412346
/// Describe an unchecked SIMD lane index.
413347
pub type Lane = u8;
414348

@@ -433,18 +367,6 @@ impl Encode for BlockType {
433367
}
434368
}
435369

436-
#[cfg(feature = "wasmparser")]
437-
impl TryFrom<wasmparser::BlockType> for BlockType {
438-
type Error = ();
439-
fn try_from(arg: wasmparser::BlockType) -> Result<BlockType, ()> {
440-
match arg {
441-
wasmparser::BlockType::Empty => Ok(BlockType::Empty),
442-
wasmparser::BlockType::FuncType(n) => Ok(BlockType::FunctionType(n)),
443-
wasmparser::BlockType::Type(t) => Ok(BlockType::Result(t.try_into()?)),
444-
}
445-
}
446-
}
447-
448370
/// WebAssembly instructions.
449371
#[derive(Clone, Debug)]
450372
#[non_exhaustive]
@@ -3401,64 +3323,6 @@ impl Encode for Instruction<'_> {
34013323
}
34023324
}
34033325

3404-
#[cfg(feature = "wasmparser")]
3405-
impl TryFrom<wasmparser::Operator<'_>> for Instruction<'_> {
3406-
type Error = ();
3407-
3408-
fn try_from(arg: wasmparser::Operator<'_>) -> Result<Self, ()> {
3409-
use Instruction::*;
3410-
3411-
macro_rules! define_match {
3412-
($(@$p:ident $op:ident $({ $($arg:ident: $argty:ty),* })? => $visit:ident)*) => {
3413-
match arg {
3414-
$(
3415-
wasmparser::Operator::$op $({ $($arg),* })? => {
3416-
$(
3417-
$(let $arg = define_match!(map $arg $arg);)*
3418-
)?
3419-
Ok(define_match!(mk $op $($($arg)*)?))
3420-
}
3421-
)*
3422-
}
3423-
};
3424-
3425-
// No-payload instructions are named the same in wasmparser as they are in
3426-
// wasm-encoder
3427-
(mk $op:ident) => ($op);
3428-
3429-
// Instructions which need "special care" to map from wasmparser to
3430-
// wasm-encoder
3431-
(mk BrTable $arg:ident) => ({BrTable($arg.0, $arg.1)});
3432-
(mk TryTable $arg:ident) => ({TryTable($arg.0, $arg.1)});
3433-
3434-
// Catch-all for the translation of one payload argument which is typically
3435-
// represented as a tuple-enum in wasm-encoder.
3436-
(mk $op:ident $arg:ident) => ($op($arg));
3437-
3438-
// Catch-all of everything else where the wasmparser fields are simply
3439-
// translated to wasm-encoder fields.
3440-
(mk $op:ident $($arg:ident)*) => ($op { $($arg),* });
3441-
3442-
// Special-case BrTable/TryTable conversion of arguments.
3443-
(map $arg:ident targets) => ((
3444-
$arg.targets().map(|i| i.unwrap()).collect::<Vec<_>>().into(),
3445-
$arg.default(),
3446-
));
3447-
(map $arg:ident try_table) => ((
3448-
$arg.ty.try_into().unwrap(),
3449-
$arg.catches.into_iter().map(|i| i.into()).collect::<Vec<_>>().into(),
3450-
));
3451-
3452-
// Everything else is converted with `TryFrom`/`From`. Note that the
3453-
// fallibility here has to do with how indexes are represented in
3454-
// `wasmparser` which we know when reading directly we'll never hit the
3455-
// erroneous cases here, hence the unwrap.
3456-
(map $arg:ident $other:ident) => {$other.try_into().unwrap()};
3457-
}
3458-
wasmparser::for_each_operator!(define_match)
3459-
}
3460-
}
3461-
34623326
#[derive(Clone, Debug)]
34633327
#[allow(missing_docs)]
34643328
pub enum Catch {
@@ -3493,18 +3357,6 @@ impl Encode for Catch {
34933357
}
34943358
}
34953359

3496-
#[cfg(feature = "wasmparser")]
3497-
impl From<wasmparser::Catch> for Catch {
3498-
fn from(arg: wasmparser::Catch) -> Catch {
3499-
match arg {
3500-
wasmparser::Catch::One { tag, label } => Catch::One { tag, label },
3501-
wasmparser::Catch::OneRef { tag, label } => Catch::OneRef { tag, label },
3502-
wasmparser::Catch::All { label } => Catch::All { label },
3503-
wasmparser::Catch::AllRef { label } => Catch::AllRef { label },
3504-
}
3505-
}
3506-
}
3507-
35083360
/// A constant expression.
35093361
///
35103362
/// Usable in contexts such as offsets or initializers.
@@ -3669,101 +3521,6 @@ impl Encode for ConstExpr {
36693521
}
36703522
}
36713523

3672-
/// An error when converting a `wasmparser::ConstExpr` into a
3673-
/// `wasm_encoder::ConstExpr`.
3674-
#[cfg(feature = "wasmparser")]
3675-
#[derive(Debug)]
3676-
pub enum ConstExprConversionError {
3677-
/// There was an error when parsing the const expression.
3678-
ParseError(wasmparser::BinaryReaderError),
3679-
3680-
/// The const expression is invalid: not actually constant or something like
3681-
/// that.
3682-
Invalid,
3683-
3684-
/// There was a type reference that was canonicalized and no longer
3685-
/// references an index into a module's types space, so we cannot encode it
3686-
/// into a Wasm binary again.
3687-
CanonicalizedTypeReference,
3688-
}
3689-
3690-
#[cfg(feature = "wasmparser")]
3691-
impl From<wasmparser::BinaryReaderError> for ConstExprConversionError {
3692-
fn from(err: wasmparser::BinaryReaderError) -> ConstExprConversionError {
3693-
ConstExprConversionError::ParseError(err)
3694-
}
3695-
}
3696-
3697-
#[cfg(feature = "wasmparser")]
3698-
impl std::fmt::Display for ConstExprConversionError {
3699-
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
3700-
match self {
3701-
Self::ParseError(_e) => {
3702-
write!(f, "There was an error when parsing the const expression")
3703-
}
3704-
Self::Invalid => write!(f, "The const expression was invalid"),
3705-
Self::CanonicalizedTypeReference => write!(
3706-
f,
3707-
"There was a canonicalized type reference without type index information"
3708-
),
3709-
}
3710-
}
3711-
}
3712-
3713-
#[cfg(feature = "wasmparser")]
3714-
impl std::error::Error for ConstExprConversionError {
3715-
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
3716-
match self {
3717-
Self::ParseError(e) => Some(e),
3718-
Self::Invalid | Self::CanonicalizedTypeReference => None,
3719-
}
3720-
}
3721-
}
3722-
3723-
#[cfg(feature = "wasmparser")]
3724-
impl<'a> TryFrom<wasmparser::ConstExpr<'a>> for ConstExpr {
3725-
type Error = ConstExprConversionError;
3726-
3727-
fn try_from(const_expr: wasmparser::ConstExpr) -> Result<Self, Self::Error> {
3728-
let mut ops = const_expr.get_operators_reader().into_iter();
3729-
3730-
let result = match ops.next() {
3731-
Some(Ok(wasmparser::Operator::I32Const { value })) => ConstExpr::i32_const(value),
3732-
Some(Ok(wasmparser::Operator::I64Const { value })) => ConstExpr::i64_const(value),
3733-
Some(Ok(wasmparser::Operator::F32Const { value })) => {
3734-
ConstExpr::f32_const(f32::from_bits(value.bits()))
3735-
}
3736-
Some(Ok(wasmparser::Operator::F64Const { value })) => {
3737-
ConstExpr::f64_const(f64::from_bits(value.bits()))
3738-
}
3739-
Some(Ok(wasmparser::Operator::V128Const { value })) => {
3740-
ConstExpr::v128_const(i128::from_le_bytes(*value.bytes()))
3741-
}
3742-
Some(Ok(wasmparser::Operator::RefNull { hty })) => ConstExpr::ref_null(
3743-
HeapType::try_from(hty)
3744-
.map_err(|_| ConstExprConversionError::CanonicalizedTypeReference)?,
3745-
),
3746-
Some(Ok(wasmparser::Operator::RefFunc { function_index })) => {
3747-
ConstExpr::ref_func(function_index)
3748-
}
3749-
Some(Ok(wasmparser::Operator::GlobalGet { global_index })) => {
3750-
ConstExpr::global_get(global_index)
3751-
}
3752-
3753-
// TODO: support the extended-const proposal.
3754-
Some(Ok(_op)) => return Err(ConstExprConversionError::Invalid),
3755-
3756-
Some(Err(e)) => return Err(ConstExprConversionError::ParseError(e)),
3757-
None => return Err(ConstExprConversionError::Invalid),
3758-
};
3759-
3760-
match (ops.next(), ops.next()) {
3761-
(Some(Ok(wasmparser::Operator::End)), None) => Ok(result),
3762-
_ => Err(ConstExprConversionError::Invalid),
3763-
}
3764-
}
3765-
}
3766-
37673524
#[cfg(test)]
37683525
mod tests {
37693526
#[test]

crates/wasm-encoder/src/core/custom.rs

Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -44,16 +44,6 @@ impl Section for RawCustomSection<'_> {
4444
}
4545
}
4646

47-
#[cfg(feature = "wasmparser")]
48-
impl<'a> From<wasmparser::CustomSectionReader<'a>> for CustomSection<'a> {
49-
fn from(section: wasmparser::CustomSectionReader<'a>) -> Self {
50-
CustomSection {
51-
data: section.data().into(),
52-
name: section.name().into(),
53-
}
54-
}
55-
}
56-
5747
#[cfg(test)]
5848
mod tests {
5949
use super::*;

crates/wasm-encoder/src/core/data.rs

Lines changed: 0 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -151,38 +151,6 @@ impl DataSection {
151151
self.num_added += 1;
152152
self
153153
}
154-
155-
/// Parses the input `section` given from the `wasmparser` crate and adds
156-
/// all the data to this section.
157-
#[cfg(feature = "wasmparser")]
158-
pub fn parse_section(
159-
&mut self,
160-
section: wasmparser::DataSectionReader<'_>,
161-
) -> Result<&mut Self, crate::ConstExprConversionError> {
162-
for data in section {
163-
self.parse(data?)?;
164-
}
165-
Ok(self)
166-
}
167-
168-
/// Parses a single [`wasmparser::Data`] and adds it to this section.
169-
#[cfg(feature = "wasmparser")]
170-
pub fn parse(
171-
&mut self,
172-
data: wasmparser::Data<'_>,
173-
) -> Result<&mut Self, crate::ConstExprConversionError> {
174-
match data.kind {
175-
wasmparser::DataKind::Active {
176-
memory_index,
177-
offset_expr,
178-
} => Ok(self.active(
179-
memory_index,
180-
&ConstExpr::try_from(offset_expr)?,
181-
data.data.iter().copied(),
182-
)),
183-
wasmparser::DataKind::Passive => Ok(self.passive(data.data.iter().copied())),
184-
}
185-
}
186154
}
187155

188156
impl Encode for DataSection {

0 commit comments

Comments
 (0)