summaryrefslogtreecommitdiff
path: root/crates/parser/src
diff options
context:
space:
mode:
Diffstat (limited to 'crates/parser/src')
-rw-r--r--crates/parser/src/conversion.rs45
-rw-r--r--crates/parser/src/lib.rs19
-rw-r--r--crates/parser/src/macros.rs65
-rw-r--r--crates/parser/src/optimize.rs210
-rw-r--r--crates/parser/src/parallel.rs96
-rw-r--r--crates/parser/src/visit.rs31
6 files changed, 154 insertions, 312 deletions
diff --git a/crates/parser/src/conversion.rs b/crates/parser/src/conversion.rs
index 4561974..99cf1ba 100644
--- a/crates/parser/src/conversion.rs
+++ b/crates/parser/src/conversion.rs
@@ -58,18 +58,11 @@ pub(crate) fn convert_module_data(data: wasmparser::Data<'_>) -> Result<tinywasm
pub(crate) fn convert_module_import(import: wasmparser::Import<'_>) -> Result<Import> {
let kind = match import.ty {
wasmparser::TypeRef::Func(ty) => ImportKind::Function(ty),
- wasmparser::TypeRef::Table(ty) => ImportKind::Table(TableType {
- element_type: convert_reftype(ty.element_type)?,
- size_initial: ty.initial.try_into().map_err(|_| {
- crate::ParseError::UnsupportedOperator(format!("Table size initial is too large: {}", ty.initial))
- })?,
- size_max: match ty.maximum {
- Some(max) => Some(max.try_into().map_err(|_| {
- crate::ParseError::UnsupportedOperator(format!("Table size max is too large: {max}"))
- })?),
- None => None,
- },
- }),
+ wasmparser::TypeRef::Table(ty) => {
+ let element_type = convert_reftype(ty.element_type)?;
+ let (size_initial, size_max) = convert_table_limits(ty)?;
+ ImportKind::Table(TableType { element_type, size_initial, size_max })
+ }
wasmparser::TypeRef::Memory(ty) => ImportKind::Memory(convert_module_memory(ty)),
wasmparser::TypeRef::Global(ty) => {
ImportKind::Global(GlobalType::new(convert_valtype(&ty.content_type)?, ty.mutable))
@@ -95,16 +88,24 @@ pub(crate) fn convert_module_memory(memory: wasmparser::MemoryType) -> MemoryTyp
}
pub(crate) fn convert_module_table(table: wasmparser::Table<'_>) -> Result<TableType> {
- let size_initial = table.ty.initial.try_into().map_err(|_| {
- crate::ParseError::UnsupportedOperator(format!("Table size initial is too large: {}", table.ty.initial))
- })?;
-
- let size_max = table.ty.maximum.map(|max| max.try_into()).transpose();
- let size_max =
- size_max.map_err(|e| crate::ParseError::UnsupportedOperator(format!("Table size max is too large: {e}")))?;
+ let (size_initial, size_max) = convert_table_limits(table.ty)?;
Ok(TableType { element_type: convert_reftype(table.ty.element_type)?, size_initial, size_max })
}
+fn convert_table_limits(table: wasmparser::TableType) -> Result<(u32, Option<u32>)> {
+ let size_initial = table.initial.try_into().map_err(|_| {
+ crate::ParseError::UnsupportedOperator(format!("Table size initial is too large: {}", table.initial))
+ })?;
+ let size_max = table
+ .maximum
+ .map(|max| {
+ u32::try_from(max)
+ .map_err(|_| crate::ParseError::UnsupportedOperator(format!("Table size max is too large: {max}")))
+ })
+ .transpose()?;
+ Ok((size_initial, size_max))
+}
+
pub(crate) fn convert_module_globals(
globals: wasmparser::SectionLimited<'_, wasmparser::Global<'_>>,
) -> Result<Box<[Global]>> {
@@ -153,7 +154,7 @@ pub(crate) fn convert_module_code(
for i in 0..validator.len_locals() {
match validator.get_local_type(i) {
- Some(wasmparser::ValType::I32 | wasmparser::ValType::F32) => {
+ Some(wasmparser::ValType::I32 | wasmparser::ValType::F32 | wasmparser::ValType::Ref(_)) => {
local_addr_map.push(local_counts.c32);
local_counts.c32 += 1;
}
@@ -165,10 +166,6 @@ pub(crate) fn convert_module_code(
local_addr_map.push(local_counts.c128);
local_counts.c128 += 1;
}
- Some(wasmparser::ValType::Ref(_)) => {
- local_addr_map.push(local_counts.c32);
- local_counts.c32 += 1;
- }
None => return Err(crate::ParseError::UnsupportedOperator("Unknown local type".to_string())),
}
}
diff --git a/crates/parser/src/lib.rs b/crates/parser/src/lib.rs
index c6ae326..42fddf6 100644
--- a/crates/parser/src/lib.rs
+++ b/crates/parser/src/lib.rs
@@ -250,18 +250,15 @@ impl Parser {
#[cfg(not(parallel_parser))]
let _ = defer;
-
- buffer.drain(..consumed);
}
wasmparser::Payload::CodeSectionEntry(function) => {
reader.process_inline_code_section_entry(function, &mut validator, &self.options)?;
- buffer.drain(..consumed);
}
payload => {
reader.process_payload(payload, &mut validator)?;
- buffer.drain(..consumed);
}
}
+ buffer.drain(..consumed);
#[cfg(parallel_parser)]
if let Some((count, body_offset, section_size)) = deferred_code_section {
@@ -296,12 +293,9 @@ impl Parser {
return Err(ParseError::Other("trailing bytes after end of module".into()));
}
}
-
- reader.process_pending_functions(&self.options)?;
- return reader.into_module(&self.options);
}
- if eof {
+ if reader.end_reached || eof {
reader.process_pending_functions(&self.options)?;
return reader.into_module(&self.options);
}
@@ -321,20 +315,17 @@ impl TryFrom<ModuleReader<'_>> for Module {
/// Parse a module from bytes
pub fn parse_bytes(wasm: &[u8]) -> Result<Module> {
- let data = Parser::new().parse_module_bytes(wasm)?;
- Ok(data)
+ Parser::new().parse_module_bytes(wasm)
}
#[cfg(feature = "std")]
/// Parse a module from a file. Requires the `std` feature.
pub fn parse_file(path: impl AsRef<crate::std::path::Path> + Clone) -> Result<Module> {
- let data = Parser::new().parse_module_file(path)?;
- Ok(data)
+ Parser::new().parse_module_file(path)
}
#[cfg(feature = "std")]
/// Parse a module from a stream. Requires `parser` and `std` features.
pub fn parse_stream(stream: impl crate::std::io::Read) -> Result<Module> {
- let data = Parser::new().parse_module_stream(stream)?;
- Ok(data)
+ Parser::new().parse_module_stream(stream)
}
diff --git a/crates/parser/src/macros.rs b/crates/parser/src/macros.rs
index b21c1e8..8a5330a 100644
--- a/crates/parser/src/macros.rs
+++ b/crates/parser/src/macros.rs
@@ -105,61 +105,18 @@ pub(crate) mod visit {
pub(crate) mod optimize {
macro_rules! replace {
- ($instructions:ident, $read:ident, 1 => [$a:expr $(,)?]) => {{
- $instructions[$read - 1] = Instruction::Nop;
- $instructions[$read] = $a;
- }};
- ($instructions:ident, $read:ident, 1 => [$a:expr, $b:expr $(,)?]) => {{
- $instructions[$read - 1] = $a;
- $instructions[$read] = $b;
- }};
- ($instructions:ident, $read:ident, 2 => [$a:expr $(,)?]) => {{
- $instructions[$read - 2] = Instruction::Nop;
- $instructions[$read - 1] = Instruction::Nop;
- $instructions[$read] = $a;
- }};
- ($instructions:ident, $read:ident, 2 => [$a:expr, $b:expr $(,)?]) => {{
- $instructions[$read - 2] = Instruction::Nop;
- $instructions[$read - 1] = $a;
- $instructions[$read] = $b;
- }};
- ($instructions:ident, $read:ident, 2 => [$a:expr, $b:expr, $c:expr $(,)?]) => {{
- $instructions[$read - 2] = $a;
- $instructions[$read - 1] = $b;
- $instructions[$read] = $c;
- }};
- ($instructions:ident, $read:ident, 3 => [$a:expr $(,)?]) => {{
- $instructions[$read - 3] = Instruction::Nop;
- $instructions[$read - 2] = Instruction::Nop;
- $instructions[$read - 1] = Instruction::Nop;
- $instructions[$read] = $a;
- }};
- ($instructions:ident, $read:ident, 3 => [$a:expr, $b:expr $(,)?]) => {{
- $instructions[$read - 3] = Instruction::Nop;
- $instructions[$read - 2] = Instruction::Nop;
- $instructions[$read - 1] = $a;
- $instructions[$read] = $b;
- }};
- ($instructions:ident, $read:ident, 3 => [$a:expr, $b:expr, $c:expr $(,)?]) => {{
- $instructions[$read - 3] = Instruction::Nop;
- $instructions[$read - 2] = $a;
- $instructions[$read - 1] = $b;
- $instructions[$read] = $c;
- }};
- ($instructions:ident, $read:ident, 3 => [$a:expr, $b:expr, $c:expr, $d:expr $(,)?]) => {{
- $instructions[$read - 3] = $a;
- $instructions[$read - 2] = $b;
- $instructions[$read - 1] = $c;
- $instructions[$read] = $d;
+ ($instructions:ident, $read:ident, $consumed:literal => [$($out:expr),+ $(,)?]) => {{
+ const {
+ assert!($consumed >= 1 && $consumed <= 3);
+ assert!([$(stringify!($out)),+].len() <= $consumed + 1);
+ }
+ let replacements = [$($out),+];
+ let replacement_start = $read + 1 - replacements.len();
+ $instructions[$read - $consumed..replacement_start].fill(Instruction::Nop);
+ $instructions[replacement_start..=$read].copy_from_slice(&replacements);
}};
- ($instructions:ident, $read:ident, 1 => $out:expr) => {
- replace!($instructions, $read, 1 => [$out]);
- };
- ($instructions:ident, $read:ident, 2 => $out:expr) => {
- replace!($instructions, $read, 2 => [$out]);
- };
- ($instructions:ident, $read:ident, 3 => $out:expr) => {
- replace!($instructions, $read, 3 => [$out]);
+ ($instructions:ident, $read:ident, $consumed:literal => $out:expr) => {
+ replace!($instructions, $read, $consumed => [$out]);
};
}
diff --git a/crates/parser/src/optimize.rs b/crates/parser/src/optimize.rs
index aad5b1a..e94e517 100644
--- a/crates/parser/src/optimize.rs
+++ b/crates/parser/src/optimize.rs
@@ -53,7 +53,7 @@ fn rewrite(
ReturnCall(addr) if addr == self_func_addr => instrs[i] = ReturnCallSelf,
Return if let Some(return_instr) = return_instr => instrs[i] = return_instr,
instr @ (I32Add | I32Mul | I32And | I32Or | I32Xor) => {
- let Some(op) = int_bin_op_32(instr) else { unreachable!() };
+ let Some(op) = int_bin_op(instr) else { unreachable!() };
rewrite!(instrs, i, [LocalGet32(a), LocalGet32(b)] => BinOpLocalLocal32(op, a, b));
rewrite!(instrs, i, [LocalGet32(local), Const32(c)] => BinOpLocalConst32(op, local, c));
rewrite!(instrs, i, [Const32(c), LocalGet32(local)] => BinOpLocalConst32(op, local, c));
@@ -64,7 +64,7 @@ fn rewrite(
}
}
instr @ (I32Sub | I32Shl | I32ShrS | I32ShrU | I32Rotl | I32Rotr) => {
- let Some(op) = int_bin_op_32(instr) else { unreachable!() };
+ let Some(op) = int_bin_op(instr) else { unreachable!() };
rewrite!(instrs, i, [LocalGet32(a), LocalGet32(b)] => BinOpLocalLocal32(op, a, b));
rewrite!(instrs, i, [LocalGet32(local), Const32(c)] => BinOpLocalConst32(op, local, c));
rewrite!(instrs, i, [GlobalGet(global)] => [Nop, BinOpStackGlobal32(op, global)]);
@@ -74,7 +74,7 @@ fn rewrite(
}
}
instr @ (I64Add | I64Mul | I64And | I64Or | I64Xor) => {
- let Some(op) = int_bin_op_64(instr) else { unreachable!() };
+ let Some(op) = int_bin_op(instr) else { unreachable!() };
rewrite!(instrs, i, [LocalGet64(a), LocalGet64(b)] => BinOpLocalLocal64(op, a, b));
rewrite!(instrs, i, [LocalGet64(local), Const64(c)] => BinOpLocalConst64(op, local, c));
rewrite!(instrs, i, [Const64(c), LocalGet64(local)] => BinOpLocalConst64(op, local, c));
@@ -85,7 +85,7 @@ fn rewrite(
}
}
instr @ (I64Sub | I64Shl | I64ShrS | I64ShrU | I64Rotl | I64Rotr) => {
- let Some(op) = int_bin_op_64(instr) else { unreachable!() };
+ let Some(op) = int_bin_op(instr) else { unreachable!() };
rewrite!(instrs, i, [LocalGet64(a), LocalGet64(b)] => BinOpLocalLocal64(op, a, b));
rewrite!(instrs, i, [LocalGet64(local), Const64(c)] => BinOpLocalConst64(op, local, c));
rewrite!(instrs, i, [GlobalGet(global)] => [Nop, BinOpStackGlobal64(op, global)]);
@@ -96,24 +96,24 @@ fn rewrite(
}
}
instr @ (F32Add | F32Mul | F32Min | F32Max) => {
- let Some(op) = float_bin_op_32(instr) else { unreachable!() };
+ let Some(op) = float_bin_op(instr) else { unreachable!() };
rewrite!(instrs, i, [LocalGet32(a), LocalGet32(b)] => BinOpLocalLocal32(op, a, b));
rewrite!(instrs, i, [LocalGet32(local), Const32(c)] => BinOpLocalConst32(op, local, c));
rewrite!(instrs, i, [Const32(c), LocalGet32(local)] => BinOpLocalConst32(op, local, c));
}
instr @ (F32Sub | F32Div | F32Copysign) => {
- let Some(op) = float_bin_op_32(instr) else { unreachable!() };
+ let Some(op) = float_bin_op(instr) else { unreachable!() };
rewrite!(instrs, i, [LocalGet32(a), LocalGet32(b)] => BinOpLocalLocal32(op, a, b));
rewrite!(instrs, i, [LocalGet32(local), Const32(c)] => BinOpLocalConst32(op, local, c));
}
instr @ (F64Add | F64Mul | F64Min | F64Max) => {
- let Some(op) = float_bin_op_64(instr) else { unreachable!() };
+ let Some(op) = float_bin_op(instr) else { unreachable!() };
rewrite!(instrs, i, [LocalGet64(a), LocalGet64(b)] => BinOpLocalLocal64(op, a, b));
rewrite!(instrs, i, [LocalGet64(local), Const64(c)] => BinOpLocalConst64(op, local, c));
rewrite!(instrs, i, [Const64(c), LocalGet64(local)] => BinOpLocalConst64(op, local, c));
}
instr @ (F64Sub | F64Div | F64Copysign) => {
- let Some(op) = float_bin_op_64(instr) else { unreachable!() };
+ let Some(op) = float_bin_op(instr) else { unreachable!() };
rewrite!(instrs, i, [LocalGet64(a), LocalGet64(b)] => BinOpLocalLocal64(op, a, b));
rewrite!(instrs, i, [LocalGet64(local), Const64(c)] => BinOpLocalConst64(op, local, c));
}
@@ -166,7 +166,7 @@ fn rewrite(
fold_local_binop!(
instrs, i, dst,
source = resolve_local_source_32,
- op = scalar_bin_op_32,
+ op = scalar_bin_op,
const = scalar_const_32,
local_local = BinOpLocalLocalSet32,
local_const = |dst, lhs, op, imm| match (dst == lhs, op) {
@@ -205,7 +205,7 @@ fn rewrite(
fold_local_binop!(
instrs, i, dst,
source = resolve_local_source_64,
- op = scalar_bin_op_64,
+ op = scalar_bin_op,
const = scalar_const_64,
local_local = BinOpLocalLocalSet64,
local_const = |dst, lhs, op, imm| match (dst == lhs, op) {
@@ -266,7 +266,7 @@ fn rewrite(
fold_local_binop!(
instrs, i, dst,
source = resolve_local_source_32,
- op = scalar_bin_op_32,
+ op = scalar_bin_op,
const = scalar_const_32,
local_local = BinOpLocalLocalTee32,
local_const = |dst, lhs, op, imm| Instruction::BinOpLocalConstTee32(op, lhs, imm, dst)
@@ -302,7 +302,7 @@ fn rewrite(
fold_local_binop!(
instrs, i, dst,
source = resolve_local_source_64,
- op = scalar_bin_op_64,
+ op = scalar_bin_op,
const = scalar_const_64,
local_local = BinOpLocalLocalTee64,
local_const = |dst, lhs, op, imm| Instruction::BinOpLocalConstTee64(op, lhs, imm, dst)
@@ -423,7 +423,7 @@ fn rewrite(
);
rewrite!(instrs, i,
[LocalGet64(local), Const64(imm), cmp] if
- (let Some(op) = cmp_op_64(cmp) && let Ok(imm) = i32::try_from(imm)) =>
+ (let Some(op) = cmp_op(cmp) && let Ok(imm) = i32::try_from(imm)) =>
match (imm, inverse_cmp_op(op)) {
(0, CmpOp::Eq) => JumpIfLocalZero64 { target_ip: target, local },
(0, CmpOp::Ne) => JumpIfLocalNonZero64 { target_ip: target, local },
@@ -435,7 +435,7 @@ fn rewrite(
JumpCmpLocalLocal32 { target_ip: target, left, right, op: inverse_cmp_op(op) }
);
rewrite!(instrs, i,
- [LocalGet64(left), LocalGet64(right), cmp] if (let Some(op) = cmp_op_64(cmp)) =>
+ [LocalGet64(left), LocalGet64(right), cmp] if (let Some(op) = cmp_op(cmp)) =>
JumpCmpLocalLocal64 { target_ip: target, left, right, op: inverse_cmp_op(op) }
);
rewrite!(instrs, i, [Const32(imm), cmp] if (let Some(op) = cmp_op(cmp)) => match (imm, inverse_cmp_op(op)) {
@@ -443,7 +443,7 @@ fn rewrite(
(0, CmpOp::Ne) => JumpIfNonZero32(target),
(imm, op) => JumpCmpStackConst32 { target_ip: target, imm, op },
});
- rewrite!(instrs, i, [Const64(imm), cmp] if (let Some(op) = cmp_op_64(cmp)) => match (imm, inverse_cmp_op(op)) {
+ rewrite!(instrs, i, [Const64(imm), cmp] if (let Some(op) = cmp_op(cmp)) => match (imm, inverse_cmp_op(op)) {
(0, CmpOp::Eq) => JumpIfZero64(target),
(0, CmpOp::Ne) => JumpIfNonZero64(target),
(imm, op) => JumpCmpStackConst64 { target_ip: target, imm, op },
@@ -479,7 +479,7 @@ fn rewrite(
);
rewrite!(instrs, i,
[LocalGet64(local), Const64(imm), cmp] if
- (let Some(op) = cmp_op_64(cmp) && let Ok(imm) = i32::try_from(imm)) =>
+ (let Some(op) = cmp_op(cmp) && let Ok(imm) = i32::try_from(imm)) =>
match (imm, op) {
(0, CmpOp::Eq) => JumpIfLocalZero64 { target_ip: target, local },
(0, CmpOp::Ne) => JumpIfLocalNonZero64 { target_ip: target, local },
@@ -491,7 +491,7 @@ fn rewrite(
JumpCmpLocalLocal32 { target_ip: target, left, right, op }
);
rewrite!(instrs, i,
- [LocalGet64(left), LocalGet64(right), cmp] if (let Some(op) = cmp_op_64(cmp)) =>
+ [LocalGet64(left), LocalGet64(right), cmp] if (let Some(op) = cmp_op(cmp)) =>
JumpCmpLocalLocal64 { target_ip: target, left, right, op }
);
rewrite!(instrs, i, [Const32(imm), cmp] if (let Some(op) = cmp_op(cmp)) => match (imm, op) {
@@ -499,7 +499,7 @@ fn rewrite(
(0, CmpOp::Ne) => JumpIfNonZero32(target),
(imm, op) => JumpCmpStackConst32 { target_ip: target, imm, op },
});
- rewrite!(instrs, i, [Const64(imm), cmp] if (let Some(op) = cmp_op_64(cmp)) => match (imm, op) {
+ rewrite!(instrs, i, [Const64(imm), cmp] if (let Some(op) = cmp_op(cmp)) => match (imm, op) {
(0, CmpOp::Eq) => JumpIfZero64(target),
(0, CmpOp::Ne) => JumpIfNonZero64(target),
(imm, op) => JumpCmpStackConst64 { target_ip: target, imm, op },
@@ -573,98 +573,64 @@ fn rewrite(
fn cmp_op(instr: Instruction) -> Option<CmpOp> {
Some(match instr {
- Instruction::I32Eq => CmpOp::Eq,
- Instruction::I32Ne => CmpOp::Ne,
- Instruction::I32LtS => CmpOp::LtS,
- Instruction::I32LtU => CmpOp::LtU,
- Instruction::I32GtS => CmpOp::GtS,
- Instruction::I32GtU => CmpOp::GtU,
- Instruction::I32LeS => CmpOp::LeS,
- Instruction::I32LeU => CmpOp::LeU,
- Instruction::I32GeS => CmpOp::GeS,
- Instruction::I32GeU => CmpOp::GeU,
+ Instruction::I32Eq | Instruction::I64Eq => CmpOp::Eq,
+ Instruction::I32Ne | Instruction::I64Ne => CmpOp::Ne,
+ Instruction::I32LtS | Instruction::I64LtS => CmpOp::LtS,
+ Instruction::I32LtU | Instruction::I64LtU => CmpOp::LtU,
+ Instruction::I32GtS | Instruction::I64GtS => CmpOp::GtS,
+ Instruction::I32GtU | Instruction::I64GtU => CmpOp::GtU,
+ Instruction::I32LeS | Instruction::I64LeS => CmpOp::LeS,
+ Instruction::I32LeU | Instruction::I64LeU => CmpOp::LeU,
+ Instruction::I32GeS | Instruction::I64GeS => CmpOp::GeS,
+ Instruction::I32GeU | Instruction::I64GeU => CmpOp::GeU,
_ => return None,
})
}
-fn int_bin_op_32(instr: Instruction) -> Option<BinOp> {
+fn int_bin_op(instr: Instruction) -> Option<BinOp> {
Some(match instr {
- Instruction::I32Add => BinOp::IAdd,
- Instruction::I32Sub => BinOp::ISub,
- Instruction::I32Mul => BinOp::IMul,
- Instruction::I32And => BinOp::IAnd,
- Instruction::I32Or => BinOp::IOr,
- Instruction::I32Xor => BinOp::IXor,
- Instruction::I32Shl => BinOp::IShl,
- Instruction::I32ShrS => BinOp::IShrS,
- Instruction::I32ShrU => BinOp::IShrU,
- Instruction::I32Rotl => BinOp::IRotl,
- Instruction::I32Rotr => BinOp::IRotr,
+ Instruction::I32Add | Instruction::I64Add => BinOp::IAdd,
+ Instruction::I32Sub | Instruction::I64Sub => BinOp::ISub,
+ Instruction::I32Mul | Instruction::I64Mul => BinOp::IMul,
+ Instruction::I32And | Instruction::I64And => BinOp::IAnd,
+ Instruction::I32Or | Instruction::I64Or => BinOp::IOr,
+ Instruction::I32Xor | Instruction::I64Xor => BinOp::IXor,
+ Instruction::I32Shl | Instruction::I64Shl => BinOp::IShl,
+ Instruction::I32ShrS | Instruction::I64ShrS => BinOp::IShrS,
+ Instruction::I32ShrU | Instruction::I64ShrU => BinOp::IShrU,
+ Instruction::I32Rotl | Instruction::I64Rotl => BinOp::IRotl,
+ Instruction::I32Rotr | Instruction::I64Rotr => BinOp::IRotr,
_ => return None,
})
}
-fn int_bin_op_64(instr: Instruction) -> Option<BinOp> {
+fn float_bin_op(instr: Instruction) -> Option<BinOp> {
Some(match instr {
- Instruction::I64Add => BinOp::IAdd,
- Instruction::I64Sub => BinOp::ISub,
- Instruction::I64Mul => BinOp::IMul,
- Instruction::I64And => BinOp::IAnd,
- Instruction::I64Or => BinOp::IOr,
- Instruction::I64Xor => BinOp::IXor,
- Instruction::I64Shl => BinOp::IShl,
- Instruction::I64ShrS => BinOp::IShrS,
- Instruction::I64ShrU => BinOp::IShrU,
- Instruction::I64Rotl => BinOp::IRotl,
- Instruction::I64Rotr => BinOp::IRotr,
+ Instruction::F32Add | Instruction::F64Add => BinOp::FAdd,
+ Instruction::F32Sub | Instruction::F64Sub => BinOp::FSub,
+ Instruction::F32Mul | Instruction::F64Mul => BinOp::FMul,
+ Instruction::F32Div | Instruction::F64Div => BinOp::FDiv,
+ Instruction::F32Min | Instruction::F64Min => BinOp::FMin,
+ Instruction::F32Max | Instruction::F64Max => BinOp::FMax,
+ Instruction::F32Copysign | Instruction::F64Copysign => BinOp::FCopysign,
_ => return None,
})
}
-fn float_bin_op_32(instr: Instruction) -> Option<BinOp> {
- Some(match instr {
- Instruction::F32Add => BinOp::FAdd,
- Instruction::F32Sub => BinOp::FSub,
- Instruction::F32Mul => BinOp::FMul,
- Instruction::F32Div => BinOp::FDiv,
- Instruction::F32Min => BinOp::FMin,
- Instruction::F32Max => BinOp::FMax,
- Instruction::F32Copysign => BinOp::FCopysign,
- _ => return None,
- })
-}
-
-fn float_bin_op_64(instr: Instruction) -> Option<BinOp> {
- Some(match instr {
- Instruction::F64Add => BinOp::FAdd,
- Instruction::F64Sub => BinOp::FSub,
- Instruction::F64Mul => BinOp::FMul,
- Instruction::F64Div => BinOp::FDiv,
- Instruction::F64Min => BinOp::FMin,
- Instruction::F64Max => BinOp::FMax,
- Instruction::F64Copysign => BinOp::FCopysign,
- _ => return None,
- })
-}
-
-fn scalar_bin_op_32(instr: Instruction) -> Option<BinOp> {
- int_bin_op_32(instr).or_else(|| float_bin_op_32(instr))
-}
-
-fn scalar_bin_op_64(instr: Instruction) -> Option<BinOp> {
- int_bin_op_64(instr).or_else(|| float_bin_op_64(instr))
+fn scalar_bin_op(instr: Instruction) -> Option<BinOp> {
+ int_bin_op(instr).or_else(|| float_bin_op(instr))
}
fn scalar_const_32(instr: Instruction, op_instr: Instruction) -> Option<i32> {
match instr {
- Instruction::Const32(c) if int_bin_op_32(op_instr).is_some() || float_bin_op_32(op_instr).is_some() => Some(c),
+ Instruction::Const32(c) if scalar_bin_op(op_instr).is_some() => Some(c),
_ => None,
}
}
fn scalar_const_64(instr: Instruction, op_instr: Instruction) -> Option<i64> {
match instr {
- Instruction::Const64(c) if int_bin_op_64(op_instr).is_some() || float_bin_op_64(op_instr).is_some() => Some(c),
+ Instruction::Const64(c) if scalar_bin_op(op_instr).is_some() => Some(c),
_ => None,
}
}
@@ -725,22 +691,6 @@ fn bin_op_128(instr: Instruction) -> Option<BinOp128> {
})
}
-fn cmp_op_64(instr: Instruction) -> Option<CmpOp> {
- Some(match instr {
- Instruction::I64Eq => CmpOp::Eq,
- Instruction::I64Ne => CmpOp::Ne,
- Instruction::I64LtS => CmpOp::LtS,
- Instruction::I64LtU => CmpOp::LtU,
- Instruction::I64GtS => CmpOp::GtS,
- Instruction::I64GtU => CmpOp::GtU,
- Instruction::I64LeS => CmpOp::LeS,
- Instruction::I64LeU => CmpOp::LeU,
- Instruction::I64GeS => CmpOp::GeS,
- Instruction::I64GeU => CmpOp::GeU,
- _ => return None,
- })
-}
-
fn inverse_cmp_op(op: CmpOp) -> CmpOp {
match op {
CmpOp::Eq => CmpOp::Ne,
@@ -806,33 +756,12 @@ fn resolve_jump_target(instrs: &[Instruction], target: u32) -> u32 {
idx as u32
}
-fn jump_target(instr: Instruction) -> Option<u32> {
+fn instruction_target_mut(instr: &mut Instruction, include_branch_table: bool) -> Option<&mut u32> {
Some(match instr {
Instruction::Jump(ip)
| Instruction::JumpIfZero32(ip)
| Instruction::JumpIfNonZero32(ip)
| Instruction::JumpIfZero64(ip)
- | Instruction::JumpIfNonZero64(ip) => ip,
- Instruction::JumpCmpStackConst32 { target_ip, .. }
- | Instruction::JumpCmpStackConst64 { target_ip, .. }
- | Instruction::JumpIfLocalZero32 { target_ip, .. }
- | Instruction::JumpIfLocalNonZero32 { target_ip, .. }
- | Instruction::JumpIfLocalZero64 { target_ip, .. }
- | Instruction::JumpIfLocalNonZero64 { target_ip, .. }
- | Instruction::JumpCmpLocalConst32 { target_ip, .. }
- | Instruction::JumpCmpLocalConst64 { target_ip, .. }
- | Instruction::JumpCmpLocalLocal32 { target_ip, .. }
- | Instruction::JumpCmpLocalLocal64 { target_ip, .. } => target_ip,
- _ => return None,
- })
-}
-
-fn set_jump_target(instr: &mut Instruction, target: u32) {
- match instr {
- Instruction::Jump(ip)
- | Instruction::JumpIfZero32(ip)
- | Instruction::JumpIfNonZero32(ip)
- | Instruction::JumpIfZero64(ip)
| Instruction::JumpIfNonZero64(ip)
| Instruction::JumpCmpStackConst32 { target_ip: ip, .. }
| Instruction::JumpCmpStackConst64 { target_ip: ip, .. }
@@ -843,13 +772,14 @@ fn set_jump_target(instr: &mut Instruction, target: u32) {
| Instruction::JumpCmpLocalConst32 { target_ip: ip, .. }
| Instruction::JumpCmpLocalConst64 { target_ip: ip, .. }
| Instruction::JumpCmpLocalLocal32 { target_ip: ip, .. }
- | Instruction::JumpCmpLocalLocal64 { target_ip: ip, .. } => *ip = target,
- _ => {}
- }
+ | Instruction::JumpCmpLocalLocal64 { target_ip: ip, .. } => ip,
+ Instruction::BranchTable(ip, _, _) if include_branch_table => ip,
+ _ => return None,
+ })
}
fn canonicalize_jump_like(instrs: &mut [Instruction], idx: usize) {
- let Some(target) = jump_target(instrs[idx]) else {
+ let Some(target) = instruction_target_mut(&mut instrs[idx], false).map(|target| *target) else {
return;
};
@@ -859,8 +789,8 @@ fn canonicalize_jump_like(instrs: &mut [Instruction], idx: usize) {
fn canonicalize_jump_like_with_target(instrs: &mut [Instruction], idx: usize, target: u32) {
if matches!(instrs[idx], Instruction::Jump(_)) && target == next_non_nop(instrs, idx + 1) as u32 {
instrs[idx] = Instruction::Nop;
- } else {
- set_jump_target(&mut instrs[idx], target);
+ } else if let Some(ip) = instruction_target_mut(&mut instrs[idx], false) {
+ *ip = target;
}
}
@@ -894,24 +824,8 @@ fn remove_nop(instructions: &mut Vec<Instruction>, function_data: &mut WasmFunct
});
instructions.retain_mut(|instr| {
- let ip = match instr {
- Instruction::Jump(ip)
- | Instruction::JumpIfZero32(ip)
- | Instruction::JumpIfNonZero32(ip)
- | Instruction::JumpIfZero64(ip)
- | Instruction::JumpIfNonZero64(ip)
- | Instruction::JumpIfLocalZero32 { target_ip: ip, .. }
- | Instruction::JumpIfLocalNonZero32 { target_ip: ip, .. }
- | Instruction::JumpIfLocalZero64 { target_ip: ip, .. }
- | Instruction::JumpIfLocalNonZero64 { target_ip: ip, .. }
- | Instruction::JumpCmpStackConst32 { target_ip: ip, .. }
- | Instruction::JumpCmpStackConst64 { target_ip: ip, .. }
- | Instruction::JumpCmpLocalConst32 { target_ip: ip, .. }
- | Instruction::JumpCmpLocalConst64 { target_ip: ip, .. }
- | Instruction::JumpCmpLocalLocal32 { target_ip: ip, .. }
- | Instruction::JumpCmpLocalLocal64 { target_ip: ip, .. }
- | Instruction::BranchTable(ip, _, _) => ip,
- _ => return !matches!(instr, Instruction::Nop | Instruction::MergeBarrier),
+ let Some(ip) = instruction_target_mut(instr, true) else {
+ return !matches!(instr, Instruction::Nop | Instruction::MergeBarrier);
};
let old_target = *ip as usize;
diff --git a/crates/parser/src/parallel.rs b/crates/parser/src/parallel.rs
index 4400053..8833970 100644
--- a/crates/parser/src/parallel.rs
+++ b/crates/parser/src/parallel.rs
@@ -94,10 +94,6 @@ pub(crate) fn process_pending(
imported_func_count: usize,
imported_memory_count: u32,
) -> Result<Vec<FunctionCode>> {
- if pending.is_empty() {
- return Ok(Vec::new());
- }
-
let (small_jobs, large_jobs): (Vec<_>, Vec<_>) =
pending.into_iter().partition(|job| !should_parallelize_function(body_len(&job.body)));
@@ -106,11 +102,6 @@ pub(crate) fn process_pending(
.map(|job| process_function_job(job, options, func_types, imported_func_count, imported_memory_count))
.collect::<Result<Vec<_>>>()?;
- if large_jobs.is_empty() {
- codes.sort_by_key(|(ordinal, _)| *ordinal);
- return Ok(codes.into_iter().map(|(_, code)| code).collect());
- }
-
let num_workers = worker_count(options, large_jobs.len());
if num_workers == 1 {
codes.extend(
@@ -119,54 +110,57 @@ pub(crate) fn process_pending(
.map(|job| process_function_job(job, options, func_types, imported_func_count, imported_memory_count))
.collect::<Result<Vec<_>>>()?,
);
- codes.sort_by_key(|(ordinal, _)| *ordinal);
- return Ok(codes.into_iter().map(|(_, code)| code).collect());
- }
-
- let chunk_size = large_jobs.len().div_ceil(num_workers);
- let chunks = {
- let mut chunks = Vec::with_capacity(num_workers);
- let mut iter = large_jobs.into_iter();
- while let Some(first) = iter.next() {
- let mut chunk = alloc::vec![first];
- for _ in 1..chunk_size {
- match iter.next() {
- Some(job) => chunk.push(job),
- None => break,
+ } else {
+ let chunk_size = large_jobs.len().div_ceil(num_workers);
+ let chunks = {
+ let mut chunks = Vec::with_capacity(num_workers);
+ let mut iter = large_jobs.into_iter();
+ while let Some(first) = iter.next() {
+ let mut chunk = alloc::vec![first];
+ for _ in 1..chunk_size {
+ match iter.next() {
+ Some(job) => chunk.push(job),
+ None => break,
+ }
}
+ chunks.push(chunk);
}
- chunks.push(chunk);
- }
- chunks
- };
+ chunks
+ };
- let results: Vec<Result<(usize, FunctionCode)>> = std::thread::scope(|s| {
- let handles: Vec<_> = chunks
- .into_iter()
- .map(|chunk| {
- s.spawn(move || {
- chunk
- .into_iter()
- .map(|job| {
- process_function_job(job, options, func_types, imported_func_count, imported_memory_count)
- })
- .collect::<Vec<_>>()
+ let results: Vec<Result<(usize, FunctionCode)>> = std::thread::scope(|s| {
+ let handles: Vec<_> = chunks
+ .into_iter()
+ .map(|chunk| {
+ s.spawn(move || {
+ chunk
+ .into_iter()
+ .map(|job| {
+ process_function_job(
+ job,
+ options,
+ func_types,
+ imported_func_count,
+ imported_memory_count,
+ )
+ })
+ .collect::<Vec<_>>()
+ })
})
- })
- .collect();
+ .collect();
- handles
- .into_iter()
- .flat_map(|handle| match handle.join() {
- Ok(results) => results,
- Err(_) => alloc::vec![Err(ParseError::Other("worker thread panicked".into()))],
- })
- .collect()
- });
+ handles
+ .into_iter()
+ .flat_map(|handle| match handle.join() {
+ Ok(results) => results,
+ Err(_) => alloc::vec![Err(ParseError::Other("worker thread panicked".into()))],
+ })
+ .collect()
+ });
- for result in results {
- let (ordinal, code) = result?;
- codes.push((ordinal, code));
+ for result in results {
+ codes.push(result?);
+ }
}
codes.sort_by_key(|(ordinal, _)| *ordinal);
diff --git a/crates/parser/src/visit.rs b/crates/parser/src/visit.rs
index 4d233d3..4e941ad 100644
--- a/crates/parser/src/visit.rs
+++ b/crates/parser/src/visit.rs
@@ -303,7 +303,7 @@ impl<'a, R: WasmModuleResources> wasmparser::VisitOperator<'a> for FunctionBuild
if let Some(ctx) = self.ctx_stack.last_mut() {
ctx.has_else = true;
ctx.branch_jumps.push(jump_ip);
- self.patch_jump_if_zero(cond_jump_ip, self.instructions.len());
+ self.patch_jump(cond_jump_ip, self.instructions.len());
if !matches!(self.instructions.last(), Some(Instruction::Nop | Instruction::MergeBarrier)) {
self.instructions.push(Instruction::MergeBarrier); // prevent superinstructions from merging across block boundaries
}
@@ -343,7 +343,7 @@ impl<'a, R: WasmModuleResources> wasmparser::VisitOperator<'a> for FunctionBuild
}
self.emit_branch_jump_or_return(depth);
- self.patch_jump_if_zero(cond_jump_ip, self.instructions.len());
+ self.patch_jump(cond_jump_ip, self.instructions.len());
}
fn visit_br_table(&mut self, targets: wasmparser::BrTable<'_>) -> Self::Output {
@@ -366,33 +366,28 @@ impl<'a, R: WasmModuleResources> wasmparser::VisitOperator<'a> for FunctionBuild
jump_or_ret_ip: usize,
is_return: bool,
}
- let mut seen = Vec::<(u32, usize)>::new();
let mut pads: Vec<PadInfo> = Vec::new();
for &depth in target_depths.iter().chain(core::iter::once(&default_depth)) {
- if seen.iter().any(|&(seen_depth, _)| seen_depth == depth) {
+ if pads.iter().any(|pad| pad.depth == depth) {
continue;
}
- seen.push((depth, pads.len()));
let (pad_start, jump_or_ret_ip, is_return) = self.emit_br_table_pad(depth);
pads.push(PadInfo { depth, pad_start, jump_or_ret_ip, is_return });
}
for &depth in &target_depths {
- let pad_idx = seen
- .iter()
- .find_map(|&(seen_depth, idx)| (seen_depth == depth).then_some(idx))
- .expect("visit_br_table: missing branch table target");
- self.data.branch_table_targets.push(pads[pad_idx].pad_start as u32);
+ let pad = pads.iter().find(|pad| pad.depth == depth).expect("visit_br_table: missing branch table target");
+ self.data.branch_table_targets.push(pad.pad_start as u32);
}
- let default_pad_idx = seen
+ let default_pad = pads
.iter()
- .find_map(|&(seen_depth, idx)| (seen_depth == default_depth).then_some(idx))
+ .find(|pad| pad.depth == default_depth)
.expect("visit_br_table: missing default branch table target");
if let Instruction::BranchTable(default_ip, _, _) = &mut self.instructions[header_ip] {
- *default_ip = pads[default_pad_idx].pad_start as u32;
+ *default_ip = default_pad.pad_start as u32;
}
for pad in &pads {
@@ -621,19 +616,13 @@ impl<R: WasmModuleResources> FunctionBuilder<R> {
fn patch_jump(&mut self, jump_ip: usize, target: usize) {
match &mut self.instructions[jump_ip] {
- Instruction::Jump(ip) | Instruction::JumpIfNonZero32(ip) => {
+ Instruction::Jump(ip) | Instruction::JumpIfZero32(ip) | Instruction::JumpIfNonZero32(ip) => {
*ip = target as u32;
}
_ => {}
}
}
- fn patch_jump_if_zero(&mut self, jump_ip: usize, target: usize) {
- if let Instruction::JumpIfZero32(ip) = &mut self.instructions[jump_ip] {
- *ip = target as u32;
- }
- }
-
fn label_keep_counts(label_types: &[wasmparser::ValType]) -> (u16, u16, u16) {
let (mut c32, mut c64, mut c128) = (0, 0, 0);
for &ty in label_types {
@@ -738,7 +727,7 @@ impl<R: WasmModuleResources> FunctionBuilder<R> {
BlockKind::If => {
if let Some((&cond_jump_ip, branch_jumps)) = ctx.branch_jumps.split_first() {
if !ctx.has_else {
- self.patch_jump_if_zero(cond_jump_ip, end_ip);
+ self.patch_jump(cond_jump_ip, end_ip);
}
for &jump_ip in branch_jumps {
self.patch_jump(jump_ip, end_ip);