diff options
Diffstat (limited to 'crates/parser')
| -rw-r--r-- | crates/parser/src/conversion.rs | 45 | ||||
| -rw-r--r-- | crates/parser/src/lib.rs | 19 | ||||
| -rw-r--r-- | crates/parser/src/macros.rs | 65 | ||||
| -rw-r--r-- | crates/parser/src/optimize.rs | 210 | ||||
| -rw-r--r-- | crates/parser/src/parallel.rs | 96 | ||||
| -rw-r--r-- | crates/parser/src/visit.rs | 31 |
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); |
