Skip to content

Commit 5aa07fc

Browse files
Feature-gate ser, deser, and parser
- introduce features to enable operation modes: - default (current way) - parser + serialization - deserialization
1 parent 502e18f commit 5aa07fc

File tree

30 files changed

+340
-380
lines changed

30 files changed

+340
-380
lines changed

crates/cli/Cargo.toml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,8 @@ exclude.workspace = true
1717
wasmi = { workspace = true, default-features = false, features = [
1818
"wat",
1919
"serialization",
20-
"deserialization"
20+
"deserialization",
21+
"parser",
2122
] }
2223
wasmi_wasi = { workspace = true }
2324
anyhow = "1"

crates/cli/src/args.rs

Lines changed: 0 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@ use std::{
66
path::{Path, PathBuf},
77
str::FromStr,
88
};
9-
use wasmi::serialization::RequiredFeatures;
109
use wasmi_wasi::{ambient_authority, Dir, TcpListener, WasiCtx, WasiCtxBuilder};
1110

1211
#[derive(Parser, Debug)]
@@ -24,33 +23,6 @@ pub struct SerializeArgs {
2423
/// The output file for the serialized module (or '-' for stdout).
2524
#[clap(long, value_name = "OUTPUT", value_hint = clap::ValueHint::FilePath)]
2625
pub output: Option<PathBuf>,
27-
/// Enable the simd feature.
28-
#[clap(long)]
29-
pub simd: bool,
30-
/// Enable the bulk-memory feature.
31-
#[clap(long = "bulk-memory")]
32-
pub bulk_memory: bool,
33-
/// Enable the reference-types feature.
34-
#[clap(long = "reference-types")]
35-
pub reference_types: bool,
36-
/// Enable the tail-calls feature.
37-
#[clap(long = "tail-calls")]
38-
pub tail_calls: bool,
39-
/// Enable the function-references feature.
40-
#[clap(long = "function-references")]
41-
pub function_references: bool,
42-
}
43-
44-
impl SerializeArgs {
45-
pub fn to_required_features(&self) -> RequiredFeatures {
46-
RequiredFeatures {
47-
simd: self.simd,
48-
bulk_memory: self.bulk_memory,
49-
reference_types: self.reference_types,
50-
tail_calls: self.tail_calls,
51-
function_references: self.function_references,
52-
}
53-
}
5426
}
5527

5628
#[derive(Debug, Clone)]

crates/cli/src/serialize.rs

Lines changed: 5 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,6 @@ use wasmi::{
99
use crate::args::SerializeArgs;
1010

1111
pub(super) fn serialize(args: SerializeArgs) -> Result<()> {
12-
let required_features = args.to_required_features();
13-
println!("req feautures: {required_features:?}");
1412
let engine = wasmi::Engine::default();
1513

1614
let wasm_file = args.module;
@@ -20,16 +18,15 @@ pub(super) fn serialize(args: SerializeArgs) -> Result<()> {
2018
anyhow!("failed to parse and validate Wasm module {wasm_file:?}: {error}")
2119
})?;
2220

23-
let bytes = serialize_module(&module, &required_features)
21+
let bytes = serialize_module(&module, &engine)
2422
.map_err(|error| anyhow!("failed to serialize Wasm module {wasm_file:?}: {error}"))?;
2523

2624
let output = args
2725
.output
2826
.unwrap_or_else(|| wasm_file.with_extension("wasm.ser"));
2927

30-
let other_engine = Engine::default();
31-
let _deser_module =
32-
deserialize_module(&other_engine, &bytes).expect("failed to deserialize back");
28+
let (deser_module, other_engine) =
29+
deserialize_module(&bytes).expect("failed to deserialize back");
3330

3431
if output == PathBuf::from("-") {
3532
std::io::stdout().write_all(&bytes)?;
@@ -38,9 +35,8 @@ pub(super) fn serialize(args: SerializeArgs) -> Result<()> {
3835
}
3936

4037
let read_bytes = fs::read(&output).expect("failed to read bytes");
41-
let other_engine = Engine::default();
42-
let _deser_module =
43-
deserialize_module(&other_engine, &read_bytes).expect("failed to deserialize back");
38+
let (deser_module, other_engine) =
39+
deserialize_module(&read_bytes).expect("failed to deserialize back");
4440

4541
println!("deser from read okay");
4642

crates/wasmi/Cargo.toml

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,10 @@ exclude = ["benches/wat", "benches/wasm", "tests/spec/testsuite", "**.wast"]
1717
wasmi_core = { workspace = true }
1818
wasmi_collections = { workspace = true }
1919
wasmi_ir = { workspace = true }
20-
wasmparser = { workspace = true, features = ["validate", "features"] }
20+
wasmparser = { workspace = true, features = [
21+
"validate",
22+
"features",
23+
], optional = true }
2124
wat = { workspace = true, optional = true }
2225
spin = { version = "0.9", default-features = false, features = [
2326
"mutex",
@@ -40,7 +43,7 @@ assert_matches = "1.5"
4043
criterion = { version = "0.5", default-features = false }
4144

4245
[features]
43-
default = ["std", "wat"]
46+
default = ["std", "wat", "parser"]
4447
std = [
4548
"wasmi_core/std",
4649
"wasmi_collections/std",
@@ -59,6 +62,10 @@ prefer-btree-collections = [
5962
wat = ["dep:wat", "std"]
6063
simd = ["wasmi_core/simd", "wasmi_ir/simd", "wasmparser/simd"]
6164

65+
# New feature flags for parser and translation
66+
parser = ["dep:wasmparser", "wasmparser/validate", "wasmparser/features"]
67+
translation = ["parser"] # Translation implies parser
68+
6269
serialization = [
6370
"dep:serde",
6471
"serde/derive",

crates/wasmi/src/engine/code_map.rs

Lines changed: 78 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -5,25 +5,33 @@
55
//! This is the data structure specialized to handle compiled
66
//! register machine based bytecode functions.
77
8-
use super::{FuncTranslationDriver, FuncTranslator, TranslationError, ValidatingFuncTranslator};
98
use crate::{
109
collections::arena::{Arena, ArenaIndex},
11-
core::{Fuel, FuelCostsProvider, FuelError, UntypedVal},
12-
engine::{utils::unreachable_unchecked, ResumableOutOfFuelError},
10+
core::{Fuel, UntypedVal},
11+
engine::utils::unreachable_unchecked,
1312
ir::{index::InternalFunc, Instruction},
14-
module::{FuncIdx, ModuleHeader},
15-
Config,
16-
Error,
13+
Config, Error,
1714
};
1815
use alloc::boxed::Box;
1916
use core::{
20-
fmt,
21-
mem::{self, MaybeUninit},
17+
mem::{self},
2218
ops::{self, Range},
2319
pin::Pin,
2420
slice,
2521
};
2622
use spin::Mutex;
23+
24+
#[cfg(feature = "parser")]
25+
use super::{FuncTranslationDriver, FuncTranslator, TranslationError, ValidatingFuncTranslator};
26+
#[cfg(feature = "parser")]
27+
use crate::{
28+
core::{FuelCostsProvider, FuelError},
29+
engine::ResumableOutOfFuelError,
30+
module::{FuncIdx, ModuleHeader},
31+
};
32+
#[cfg(feature = "parser")]
33+
use core::{fmt, mem::MaybeUninit};
34+
#[cfg(feature = "parser")]
2735
use wasmparser::{FuncToValidate, ValidatorResources, WasmFeatures};
2836

2937
/// A reference to a compiled function stored in the [`CodeMap`] of an [`Engine`](crate::Engine).
@@ -71,6 +79,7 @@ impl ArenaIndex for EngineFunc {
7179
#[derive(Debug)]
7280
pub struct CodeMap {
7381
funcs: Mutex<Arena<EngineFunc, FuncEntity>>,
82+
#[cfg(feature = "parser")]
7483
features: WasmFeatures,
7584
}
7685

@@ -213,6 +222,7 @@ impl CodeMap {
213222
pub fn new(config: &Config) -> Self {
214223
Self {
215224
funcs: Mutex::new(Arena::default()),
225+
#[cfg(feature = "parser")]
216226
features: config.wasm_features(),
217227
}
218228
}
@@ -244,32 +254,6 @@ impl CodeMap {
244254
func.init_compiled(entity);
245255
}
246256

247-
/// Initializes the [`EngineFunc`] for lazy translation.
248-
///
249-
/// # Panics
250-
///
251-
/// - If `func` is an invalid [`EngineFunc`] reference for this [`CodeMap`].
252-
/// - If `func` refers to an already initialized [`EngineFunc`].
253-
pub fn init_func_as_uncompiled(
254-
&self,
255-
func: EngineFunc,
256-
func_idx: FuncIdx,
257-
bytes: &[u8],
258-
module: &ModuleHeader,
259-
func_to_validate: Option<FuncToValidate<ValidatorResources>>,
260-
) {
261-
let mut funcs = self.funcs.lock();
262-
let Some(func) = funcs.get_mut(func) else {
263-
panic!("encountered invalid internal function: {func:?}")
264-
};
265-
func.init_uncompiled(UncompiledFuncEntity::new(
266-
func_idx,
267-
bytes,
268-
module.clone(),
269-
func_to_validate,
270-
));
271-
}
272-
273257
/// Returns the [`FuncEntity`] of the [`EngineFunc`].
274258
///
275259
/// # Errors
@@ -285,26 +269,12 @@ impl CodeMap {
285269
) -> Result<CompiledFuncRef<'a>, Error> {
286270
match self.get_compiled(func) {
287271
Some(cref) => Ok(cref),
272+
#[cfg(feature = "parser")]
288273
None => self.compile_or_wait(fuel, func),
289-
}
290-
}
291-
292-
/// Compile `func` or wait for result if another process already started compilation.
293-
///
294-
/// # Errors
295-
///
296-
/// - If translation or Wasm validation of `func` failed.
297-
/// - If `ctx` ran out of fuel in case fuel consumption is enabled.
298-
#[cold]
299-
#[inline]
300-
fn compile_or_wait<'a>(
301-
&'a self,
302-
fuel: Option<&mut Fuel>,
303-
func: EngineFunc,
304-
) -> Result<CompiledFuncRef<'a>, Error> {
305-
match self.get_uncompiled(func) {
306-
Some(entity) => self.compile(fuel, func, entity),
307-
None => self.wait_for_compilation(func),
274+
#[cfg(not(feature = "parser"))]
275+
None => Err(Error::new(
276+
"Function not compiled - parser feature required",
277+
)),
308278
}
309279
}
310280

@@ -327,6 +297,7 @@ impl CodeMap {
327297
/// Returns the [`UncompiledFuncEntity`] of `func` if possible, otherwise returns `None`.
328298
///
329299
/// After this operation `func` will be in [`FuncEntity::Compiling`] state.
300+
#[cfg(feature = "parser")]
330301
#[inline]
331302
fn get_uncompiled(&self, func: EngineFunc) -> Option<UncompiledFuncEntity> {
332303
let mut funcs = self.funcs.lock();
@@ -353,6 +324,54 @@ impl CodeMap {
353324
// returned `CompiledFuncRef` only references `Pin`ned data.
354325
unsafe { mem::transmute::<CompiledFuncRef<'_>, CompiledFuncRef<'a>>(cref) }
355326
}
327+
}
328+
329+
#[cfg(feature = "parser")]
330+
impl CodeMap {
331+
/// Compile `func` or wait for result if another process already started compilation.
332+
///
333+
/// # Errors
334+
///
335+
/// - If translation or Wasm validation of `func` failed.
336+
/// - If `ctx` ran out of fuel in case fuel consumption is enabled.
337+
#[cold]
338+
#[inline]
339+
fn compile_or_wait<'a>(
340+
&'a self,
341+
fuel: Option<&mut Fuel>,
342+
func: EngineFunc,
343+
) -> Result<CompiledFuncRef<'a>, Error> {
344+
match self.get_uncompiled(func) {
345+
Some(entity) => self.compile(fuel, func, entity),
346+
None => self.wait_for_compilation(func),
347+
}
348+
}
349+
350+
/// Initializes the [`EngineFunc`] for lazy translation.
351+
///
352+
/// # Panics
353+
///
354+
/// - If `func` is an invalid [`EngineFunc`] reference for this [`CodeMap`].
355+
/// - If `func` refers to an already initialized [`EngineFunc`].
356+
pub fn init_func_as_uncompiled(
357+
&self,
358+
func: EngineFunc,
359+
func_idx: FuncIdx,
360+
bytes: &[u8],
361+
module: &ModuleHeader,
362+
func_to_validate: Option<FuncToValidate<ValidatorResources>>,
363+
) {
364+
let mut funcs = self.funcs.lock();
365+
let Some(func) = funcs.get_mut(func) else {
366+
panic!("encountered invalid internal function: {func:?}")
367+
};
368+
func.init_uncompiled(UncompiledFuncEntity::new(
369+
func_idx,
370+
bytes,
371+
module.clone(),
372+
func_to_validate,
373+
));
374+
}
356375

357376
/// Compile and validate the [`UncompiledFuncEntity`] identified by `func`.
358377
///
@@ -426,6 +445,7 @@ impl CodeMap {
426445
enum FuncEntity {
427446
/// The function entity has not yet been initialized.
428447
Uninit,
448+
#[cfg(feature = "parser")]
429449
/// An internal function that has not yet been compiled.
430450
Uncompiled(UncompiledFuncEntity),
431451
/// The function entity is currently compiling.
@@ -461,6 +481,7 @@ impl FuncEntity {
461481
///
462482
/// If `func` has already been initialized.
463483
#[inline]
484+
#[cfg(feature = "parser")]
464485
pub fn init_uncompiled(&mut self, entity: UncompiledFuncEntity) {
465486
assert!(matches!(self, Self::Uninit));
466487
*self = Self::Uncompiled(entity);
@@ -483,6 +504,7 @@ impl FuncEntity {
483504
///
484505
/// Returns a proper error if the [`FuncEntity`] is not uncompiled.
485506
#[inline]
507+
#[cfg(feature = "parser")]
486508
pub fn get_uncompiled(&mut self) -> Option<UncompiledFuncEntity> {
487509
match self {
488510
Self::Uncompiled(_) => {}
@@ -535,6 +557,7 @@ impl FuncEntity {
535557
#[repr(transparent)]
536558
pub struct TypeIndex(u32);
537559

560+
#[cfg(feature = "parser")]
538561
/// An internal uncompiled function entity.
539562
pub struct UncompiledFuncEntity {
540563
/// The index of the function within the Wasm module.
@@ -552,6 +575,7 @@ pub struct UncompiledFuncEntity {
552575
validation: Option<(TypeIndex, ValidatorResources)>,
553576
}
554577

578+
#[cfg(feature = "parser")]
555579
impl UncompiledFuncEntity {
556580
/// Creates a new [`UncompiledFuncEntity`].
557581
pub fn new(
@@ -676,6 +700,7 @@ impl UncompiledFuncEntity {
676700
}
677701
}
678702

703+
#[cfg(feature = "parser")]
679704
impl fmt::Debug for UncompiledFuncEntity {
680705
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
681706
f.debug_struct("UncompiledFuncEntity")

0 commit comments

Comments
 (0)