Skip to content

Commit dfcde24

Browse files
authored
Reduce codemap memory usage (#990)
* bump wasmparser-nostd to v0.100.2 * rename func_idx -> func_index * rename func_to_validate field to just "validation" * add WasmFeatures field to CodeMap This is going to be needed later. * propagate WasmFeatures and make CodeMap work again * shrink SmallByteSlice inline buffer
1 parent 023d06a commit dfcde24

File tree

3 files changed

+54
-22
lines changed

3 files changed

+54
-22
lines changed

crates/wasmi/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ exclude = [
1919
]
2020

2121
[dependencies]
22-
wasmparser = { version = "0.100.1", package = "wasmparser-nostd", default-features = false }
22+
wasmparser = { version = "0.100.2", package = "wasmparser-nostd", default-features = false }
2323
wasmi_core = { workspace = true }
2424
wasmi_arena = { workspace = true }
2525
spin = { version = "0.9", default-features = false, features = [

crates/wasmi/src/engine/code_map.rs

Lines changed: 50 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ use crate::{
1717
engine::bytecode::Instruction,
1818
module::{FuncIdx, ModuleHeader},
1919
store::{Fuel, FuelError},
20+
Config,
2021
Error,
2122
};
2223
use core::{
@@ -31,7 +32,7 @@ use core::{
3132
use std::boxed::Box;
3233
use wasmi_arena::{Arena, ArenaIndex};
3334
use wasmi_core::TrapCode;
34-
use wasmparser::{FuncToValidate, ValidatorResources};
35+
use wasmparser::{FuncToValidate, ValidatorResources, WasmFeatures};
3536

3637
/// A reference to a compiled function stored in the [`CodeMap`] of an [`Engine`](crate::Engine).
3738
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
@@ -102,16 +103,16 @@ impl InternalFuncEntity {
102103
///
103104
/// - If function translation failed.
104105
/// - If `ctx` ran out of fuel in case fuel consumption is enabled.
105-
fn compile(&mut self, fuel: Option<&mut Fuel>) -> Result<(), Error> {
106+
fn compile(&mut self, fuel: Option<&mut Fuel>, features: &WasmFeatures) -> Result<(), Error> {
106107
let uncompiled = match self {
107108
InternalFuncEntity::Uncompiled(func) => func,
108109
InternalFuncEntity::Compiled(func) => {
109110
unreachable!("expected func to be uncompiled: {func:?}")
110111
}
111112
};
112-
let func_idx = uncompiled.func_idx;
113+
let func_idx = uncompiled.func_index;
113114
let bytes = mem::take(&mut uncompiled.bytes);
114-
let needs_validation = uncompiled.func_to_validate.is_some();
115+
let needs_validation = uncompiled.validation.is_some();
115116
let compilation_fuel = |_costs: &FuelCosts| {
116117
let len_bytes = bytes.as_slice().len() as u64;
117118
let compile_factor = match needs_validation {
@@ -133,10 +134,16 @@ impl InternalFuncEntity {
133134
module.engine()
134135
)
135136
};
136-
match uncompiled.func_to_validate.take() {
137-
Some(func_to_validate) => {
137+
match uncompiled.validation.take() {
138+
Some((type_index, resources)) => {
138139
let allocs = engine.get_allocs();
139140
let translator = FuncTranslator::new(func_idx, module, allocs.0)?;
141+
let func_to_validate = FuncToValidate {
142+
resources,
143+
index: func_idx.into_u32(),
144+
ty: type_index.0,
145+
features: *features,
146+
};
140147
let validator = func_to_validate.into_validator(allocs.1);
141148
let translator = ValidatingFuncTranslator::new(validator, translator)?;
142149
let allocs = FuncTranslationDriver::new(0, &bytes[..], translator)?.translate(
@@ -163,8 +170,8 @@ impl InternalFuncEntity {
163170

164171
/// An internal uncompiled function entity.
165172
pub struct UncompiledFuncEntity {
166-
/// The index of the function within the `module`.
167-
func_idx: FuncIdx,
173+
/// The index of the function within the Wasm module.
174+
func_index: FuncIdx,
168175
/// The Wasm binary bytes.
169176
bytes: SmallByteSlice,
170177
/// The Wasm module of the Wasm function.
@@ -175,33 +182,48 @@ pub struct UncompiledFuncEntity {
175182
/// Optional Wasm validation information.
176183
///
177184
/// This is `Some` if the [`UncompiledFuncEntity`] is to be validated upon compilation.
178-
func_to_validate: Option<FuncToValidate<ValidatorResources>>,
185+
validation: Option<(TypeIndex, ValidatorResources)>,
179186
}
180187

188+
/// A function type index into the Wasm module.
189+
#[derive(Debug, Copy, Clone)]
190+
#[repr(transparent)]
191+
pub struct TypeIndex(u32);
192+
181193
impl UncompiledFuncEntity {
182194
/// Creates a new [`UncompiledFuncEntity`].
183195
pub fn new(
184-
func_idx: FuncIdx,
196+
func_index: FuncIdx,
185197
bytes: impl Into<SmallByteSlice>,
186198
module: ModuleHeader,
187199
func_to_validate: impl Into<Option<FuncToValidate<ValidatorResources>>>,
188200
) -> Self {
201+
let validation = func_to_validate.into().map(|func_to_validate| {
202+
assert_eq!(
203+
func_to_validate.index,
204+
func_index.into_u32(),
205+
"Wasmi function index ({}) does not match with Wasm validation function index ({})",
206+
func_to_validate.index,
207+
func_index.into_u32(),
208+
);
209+
(TypeIndex(func_to_validate.ty), func_to_validate.resources)
210+
});
189211
Self {
190-
func_idx,
212+
func_index,
191213
bytes: bytes.into(),
192214
module,
193-
func_to_validate: func_to_validate.into(),
215+
validation,
194216
}
195217
}
196218
}
197219

198220
impl fmt::Debug for UncompiledFuncEntity {
199221
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
200222
f.debug_struct("UncompiledFuncEntity")
201-
.field("func_idx", &self.func_idx)
223+
.field("func_idx", &self.func_index)
202224
.field("bytes", &self.bytes)
203225
.field("module", &self.module)
204-
.field("validate", &self.func_to_validate.is_some())
226+
.field("validate", &self.validation.is_some())
205227
.finish()
206228
}
207229
}
@@ -233,7 +255,7 @@ impl Default for SmallByteSlice {
233255

234256
impl SmallByteSlice {
235257
/// The maximum amount of bytes that can be stored inline.
236-
const MAX_INLINE_SIZE: usize = 30;
258+
const MAX_INLINE_SIZE: usize = 22;
237259

238260
/// Returns the underlying slice of bytes.
239261
#[inline]
@@ -353,9 +375,10 @@ impl CompiledFuncEntity {
353375
}
354376

355377
/// Datastructure to efficiently store information about compiled functions.
356-
#[derive(Debug, Default)]
378+
#[derive(Debug)]
357379
pub struct CodeMap {
358380
funcs: Arena<CompiledFunc, FuncEntity>,
381+
features: WasmFeatures,
359382
}
360383

361384
/// Atomicly accessible [`CompilationPhase`].
@@ -639,6 +662,7 @@ impl FuncEntity {
639662
pub fn compile_and_get(
640663
&self,
641664
mut fuel: Option<&mut Fuel>,
665+
features: &WasmFeatures,
642666
) -> Result<&CompiledFuncEntity, Error> {
643667
loop {
644668
if let Some(func) = self.get_compiled() {
@@ -661,7 +685,7 @@ impl FuncEntity {
661685
// Note: We need to use `take` because Rust doesn't know that this part of
662686
// the loop is only executed once.
663687
let fuel = fuel.take();
664-
match func.compile(fuel) {
688+
match func.compile(fuel, features) {
665689
Ok(()) => {
666690
self.phase
667691
.set_compiled()
@@ -679,6 +703,14 @@ impl FuncEntity {
679703
}
680704

681705
impl CodeMap {
706+
/// Creates a new [`CodeMap`].
707+
pub fn new(config: &Config) -> Self {
708+
Self {
709+
funcs: Arena::default(),
710+
features: config.wasm_features(),
711+
}
712+
}
713+
682714
/// Allocates a new uninitialized [`CompiledFunc`] to the [`CodeMap`].
683715
///
684716
/// # Note
@@ -739,7 +771,7 @@ impl CodeMap {
739771
};
740772
match func.get_compiled() {
741773
Some(func) => Ok(func),
742-
None => func.compile_and_get(fuel),
774+
None => func.compile_and_get(fuel, &self.features),
743775
}
744776
}
745777
}

crates/wasmi/src/engine/mod.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -594,7 +594,7 @@ impl EngineInner {
594594
fn new(config: &Config) -> Self {
595595
Self {
596596
config: *config,
597-
res: RwLock::new(EngineResources::new()),
597+
res: RwLock::new(EngineResources::new(config)),
598598
allocs: Mutex::new(ReusableAllocationStack::default()),
599599
stacks: Mutex::new(EngineStacks::new(config)),
600600
}
@@ -804,10 +804,10 @@ pub struct EngineResources {
804804

805805
impl EngineResources {
806806
/// Creates a new [`EngineResources`].
807-
fn new() -> Self {
807+
fn new(config: &Config) -> Self {
808808
let engine_idx = EngineIdx::new();
809809
Self {
810-
code_map: CodeMap::default(),
810+
code_map: CodeMap::new(config),
811811
func_types: FuncTypeRegistry::new(engine_idx),
812812
}
813813
}

0 commit comments

Comments
 (0)