Skip to content

Commit 8afdf05

Browse files
juntyralexcrichton
andauthored
Add parsing methods (#1627)
Co-authored-by: Alex Crichton <alex@alexcrichton.com>
1 parent d4b0ccd commit 8afdf05

22 files changed

Lines changed: 478 additions & 110 deletions

File tree

crates/wasm-encoder/Cargo.toml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,9 @@ A low-level WebAssembly encoder.
1313
"""
1414
rust-version.workspace = true
1515

16+
[package.metadata.docs.rs]
17+
all-features = true
18+
1619
[lints]
1720
workspace = true
1821

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

Lines changed: 171 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,30 @@ 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+
}
106130
}
107131

108132
impl Encode for CodeSection {
@@ -214,6 +238,18 @@ impl Function {
214238
Function::new(locals_collected)
215239
}
216240

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+
217253
/// Write an instruction into this function body.
218254
pub fn instruction(&mut self, instruction: &Instruction) -> &mut Self {
219255
instruction.encode(&mut self.bytes);
@@ -237,6 +273,15 @@ impl Function {
237273
pub fn byte_len(&self) -> usize {
238274
self.bytes.len()
239275
}
276+
277+
/// Parses a single instruction from `reader` and adds it to `self`.
278+
#[cfg(feature = "wasmparser")]
279+
pub fn parse(
280+
&mut self,
281+
reader: &mut wasmparser::OperatorsReader<'_>,
282+
) -> wasmparser::Result<&mut Self> {
283+
Ok(self.instruction(&reader.read()?.try_into().unwrap()))
284+
}
240285
}
241286

242287
impl Encode for Function {
@@ -276,6 +321,17 @@ impl Encode for MemArg {
276321
}
277322
}
278323

324+
#[cfg(feature = "wasmparser")]
325+
impl From<wasmparser::MemArg> for MemArg {
326+
fn from(arg: wasmparser::MemArg) -> MemArg {
327+
MemArg {
328+
offset: arg.offset,
329+
align: arg.align.into(),
330+
memory_index: arg.memory,
331+
}
332+
}
333+
}
334+
279335
/// The memory ordering for atomic instructions.
280336
///
281337
/// For an in-depth explanation of memory orderings, see the C++ documentation
@@ -304,6 +360,16 @@ impl Encode for Ordering {
304360
}
305361
}
306362

363+
#[cfg(feature = "wasmparser")]
364+
impl From<wasmparser::Ordering> for Ordering {
365+
fn from(arg: wasmparser::Ordering) -> Ordering {
366+
match arg {
367+
wasmparser::Ordering::SeqCst => Ordering::SeqCst,
368+
wasmparser::Ordering::AcqRel => Ordering::AcqRel,
369+
}
370+
}
371+
}
372+
307373
/// Describe an unchecked SIMD lane index.
308374
pub type Lane = u8;
309375

@@ -328,6 +394,18 @@ impl Encode for BlockType {
328394
}
329395
}
330396

397+
#[cfg(feature = "wasmparser")]
398+
impl TryFrom<wasmparser::BlockType> for BlockType {
399+
type Error = ();
400+
fn try_from(arg: wasmparser::BlockType) -> Result<BlockType, ()> {
401+
match arg {
402+
wasmparser::BlockType::Empty => Ok(BlockType::Empty),
403+
wasmparser::BlockType::FuncType(n) => Ok(BlockType::FunctionType(n)),
404+
wasmparser::BlockType::Type(t) => Ok(BlockType::Result(t.try_into()?)),
405+
}
406+
}
407+
}
408+
331409
/// WebAssembly instructions.
332410
#[derive(Clone, Debug)]
333411
#[non_exhaustive]
@@ -350,14 +428,14 @@ pub enum Instruction<'a> {
350428
Call(u32),
351429
CallRef(u32),
352430
CallIndirect {
353-
ty: u32,
354-
table: u32,
431+
type_index: u32,
432+
table_index: u32,
355433
},
356434
ReturnCallRef(u32),
357435
ReturnCall(u32),
358436
ReturnCallIndirect {
359-
ty: u32,
360-
table: u32,
437+
type_index: u32,
438+
table_index: u32,
361439
},
362440
TryTable(BlockType, Cow<'a, [Catch]>),
363441
Throw(u32),
@@ -1119,10 +1197,13 @@ impl Encode for Instruction<'_> {
11191197
sink.push(0x14);
11201198
ty.encode(sink);
11211199
}
1122-
Instruction::CallIndirect { ty, table } => {
1200+
Instruction::CallIndirect {
1201+
type_index,
1202+
table_index,
1203+
} => {
11231204
sink.push(0x11);
1124-
ty.encode(sink);
1125-
table.encode(sink);
1205+
type_index.encode(sink);
1206+
table_index.encode(sink);
11261207
}
11271208
Instruction::ReturnCallRef(ty) => {
11281209
sink.push(0x15);
@@ -1133,10 +1214,13 @@ impl Encode for Instruction<'_> {
11331214
sink.push(0x12);
11341215
f.encode(sink);
11351216
}
1136-
Instruction::ReturnCallIndirect { ty, table } => {
1217+
Instruction::ReturnCallIndirect {
1218+
type_index,
1219+
table_index,
1220+
} => {
11371221
sink.push(0x13);
1138-
ty.encode(sink);
1139-
table.encode(sink);
1222+
type_index.encode(sink);
1223+
table_index.encode(sink);
11401224
}
11411225
Instruction::Delegate(l) => {
11421226
sink.push(0x18);
@@ -3278,6 +3362,64 @@ impl Encode for Instruction<'_> {
32783362
}
32793363
}
32803364

3365+
#[cfg(feature = "wasmparser")]
3366+
impl TryFrom<wasmparser::Operator<'_>> for Instruction<'_> {
3367+
type Error = ();
3368+
3369+
fn try_from(arg: wasmparser::Operator<'_>) -> Result<Self, ()> {
3370+
use Instruction::*;
3371+
3372+
macro_rules! define_match {
3373+
($(@$p:ident $op:ident $({ $($arg:ident: $argty:ty),* })? => $visit:ident)*) => {
3374+
match arg {
3375+
$(
3376+
wasmparser::Operator::$op $({ $($arg),* })? => {
3377+
$(
3378+
$(let $arg = define_match!(map $arg $arg);)*
3379+
)?
3380+
Ok(define_match!(mk $op $($($arg)*)?))
3381+
}
3382+
)*
3383+
}
3384+
};
3385+
3386+
// No-payload instructions are named the same in wasmparser as they are in
3387+
// wasm-encoder
3388+
(mk $op:ident) => ($op);
3389+
3390+
// Instructions which need "special care" to map from wasmparser to
3391+
// wasm-encoder
3392+
(mk BrTable $arg:ident) => ({BrTable($arg.0, $arg.1)});
3393+
(mk TryTable $arg:ident) => ({TryTable($arg.0, $arg.1)});
3394+
3395+
// Catch-all for the translation of one payload argument which is typically
3396+
// represented as a tuple-enum in wasm-encoder.
3397+
(mk $op:ident $arg:ident) => ($op($arg));
3398+
3399+
// Catch-all of everything else where the wasmparser fields are simply
3400+
// translated to wasm-encoder fields.
3401+
(mk $op:ident $($arg:ident)*) => ($op { $($arg),* });
3402+
3403+
// Special-case BrTable/TryTable conversion of arguments.
3404+
(map $arg:ident targets) => ((
3405+
$arg.targets().map(|i| i.unwrap()).collect::<Vec<_>>().into(),
3406+
$arg.default(),
3407+
));
3408+
(map $arg:ident try_table) => ((
3409+
$arg.ty.try_into().unwrap(),
3410+
$arg.catches.into_iter().map(|i| i.into()).collect::<Vec<_>>().into(),
3411+
));
3412+
3413+
// Everything else is converted with `TryFrom`/`From`. Note that the
3414+
// fallibility here has to do with how indexes are represented in
3415+
// `wasmparser` which we know when reading directly we'll never hit the
3416+
// erroneous cases here, hence the unwrap.
3417+
(map $arg:ident $other:ident) => {$other.try_into().unwrap()};
3418+
}
3419+
wasmparser::for_each_operator!(define_match)
3420+
}
3421+
}
3422+
32813423
#[derive(Clone, Debug)]
32823424
#[allow(missing_docs)]
32833425
pub enum Catch {
@@ -3312,6 +3454,18 @@ impl Encode for Catch {
33123454
}
33133455
}
33143456

3457+
#[cfg(feature = "wasmparser")]
3458+
impl From<wasmparser::Catch> for Catch {
3459+
fn from(arg: wasmparser::Catch) -> Catch {
3460+
match arg {
3461+
wasmparser::Catch::One { tag, label } => Catch::One { tag, label },
3462+
wasmparser::Catch::OneRef { tag, label } => Catch::OneRef { tag, label },
3463+
wasmparser::Catch::All { label } => Catch::All { label },
3464+
wasmparser::Catch::AllRef { label } => Catch::AllRef { label },
3465+
}
3466+
}
3467+
}
3468+
33153469
/// A constant expression.
33163470
///
33173471
/// Usable in contexts such as offsets or initializers.
@@ -3494,6 +3648,13 @@ pub enum ConstExprConversionError {
34943648
CanonicalizedTypeReference,
34953649
}
34963650

3651+
#[cfg(feature = "wasmparser")]
3652+
impl From<wasmparser::BinaryReaderError> for ConstExprConversionError {
3653+
fn from(err: wasmparser::BinaryReaderError) -> ConstExprConversionError {
3654+
ConstExprConversionError::ParseError(err)
3655+
}
3656+
}
3657+
34973658
#[cfg(feature = "wasmparser")]
34983659
impl std::fmt::Display for ConstExprConversionError {
34993660
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {

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

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,16 @@ 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+
4757
#[cfg(test)]
4858
mod tests {
4959
use super::*;

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

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -151,6 +151,38 @@ 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+
}
154186
}
155187

156188
impl Encode for DataSection {

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

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -206,6 +206,54 @@ impl ElementSection {
206206
self.num_added += 1;
207207
self
208208
}
209+
210+
/// Parses the input `section` given from the `wasmparser` crate and adds
211+
/// all the elements to this section.
212+
#[cfg(feature = "wasmparser")]
213+
pub fn parse_section(
214+
&mut self,
215+
section: wasmparser::ElementSectionReader<'_>,
216+
) -> Result<&mut Self, crate::ConstExprConversionError> {
217+
for element in section {
218+
self.parse(element?)?;
219+
}
220+
Ok(self)
221+
}
222+
223+
/// Parses the single [`wasmparser::Element`] provided and adds it to this
224+
/// section.
225+
#[cfg(feature = "wasmparser")]
226+
pub fn parse(
227+
&mut self,
228+
element: wasmparser::Element<'_>,
229+
) -> Result<&mut Self, crate::ConstExprConversionError> {
230+
let mut funcs;
231+
let mut exprs;
232+
let elements = match element.items {
233+
wasmparser::ElementItems::Functions(f) => {
234+
funcs = Vec::new();
235+
for func in f {
236+
funcs.push(func?);
237+
}
238+
Elements::Functions(&funcs)
239+
}
240+
wasmparser::ElementItems::Expressions(ty, e) => {
241+
exprs = Vec::new();
242+
for expr in e {
243+
exprs.push(ConstExpr::try_from(expr?)?);
244+
}
245+
Elements::Expressions(ty.try_into().unwrap(), &exprs)
246+
}
247+
};
248+
match element.kind {
249+
wasmparser::ElementKind::Active {
250+
table_index,
251+
offset_expr,
252+
} => Ok(self.active(table_index, &ConstExpr::try_from(offset_expr)?, elements)),
253+
wasmparser::ElementKind::Passive => Ok(self.passive(elements)),
254+
wasmparser::ElementKind::Declared => Ok(self.declared(elements)),
255+
}
256+
}
209257
}
210258

211259
impl Encode for ElementSection {

0 commit comments

Comments
 (0)