Skip to content

Reduce codemap memory usage #990

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 6 commits into from
Apr 21, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion crates/wasmi/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ exclude = [
]

[dependencies]
wasmparser = { version = "0.100.1", package = "wasmparser-nostd", default-features = false }
wasmparser = { version = "0.100.2", package = "wasmparser-nostd", default-features = false }
wasmi_core = { workspace = true }
wasmi_arena = { workspace = true }
spin = { version = "0.9", default-features = false, features = [
Expand Down
68 changes: 50 additions & 18 deletions crates/wasmi/src/engine/code_map.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
engine::bytecode::Instruction,
module::{FuncIdx, ModuleHeader},
store::{Fuel, FuelError},
Config,
Error,
};
use core::{
Expand All @@ -31,7 +32,7 @@
use std::boxed::Box;
use wasmi_arena::{Arena, ArenaIndex};
use wasmi_core::TrapCode;
use wasmparser::{FuncToValidate, ValidatorResources};
use wasmparser::{FuncToValidate, ValidatorResources, WasmFeatures};

/// A reference to a compiled function stored in the [`CodeMap`] of an [`Engine`](crate::Engine).
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
Expand Down Expand Up @@ -102,16 +103,16 @@
///
/// - If function translation failed.
/// - If `ctx` ran out of fuel in case fuel consumption is enabled.
fn compile(&mut self, fuel: Option<&mut Fuel>) -> Result<(), Error> {
fn compile(&mut self, fuel: Option<&mut Fuel>, features: &WasmFeatures) -> Result<(), Error> {

Check warning on line 106 in crates/wasmi/src/engine/code_map.rs

View check run for this annotation

Codecov / codecov/patch

crates/wasmi/src/engine/code_map.rs#L106

Added line #L106 was not covered by tests
let uncompiled = match self {
InternalFuncEntity::Uncompiled(func) => func,
InternalFuncEntity::Compiled(func) => {
unreachable!("expected func to be uncompiled: {func:?}")
}
};
let func_idx = uncompiled.func_idx;
let func_idx = uncompiled.func_index;

Check warning on line 113 in crates/wasmi/src/engine/code_map.rs

View check run for this annotation

Codecov / codecov/patch

crates/wasmi/src/engine/code_map.rs#L113

Added line #L113 was not covered by tests
let bytes = mem::take(&mut uncompiled.bytes);
let needs_validation = uncompiled.func_to_validate.is_some();
let needs_validation = uncompiled.validation.is_some();

Check warning on line 115 in crates/wasmi/src/engine/code_map.rs

View check run for this annotation

Codecov / codecov/patch

crates/wasmi/src/engine/code_map.rs#L115

Added line #L115 was not covered by tests
let compilation_fuel = |_costs: &FuelCosts| {
let len_bytes = bytes.as_slice().len() as u64;
let compile_factor = match needs_validation {
Expand All @@ -133,10 +134,16 @@
module.engine()
)
};
match uncompiled.func_to_validate.take() {
Some(func_to_validate) => {
match uncompiled.validation.take() {
Some((type_index, resources)) => {

Check warning on line 138 in crates/wasmi/src/engine/code_map.rs

View check run for this annotation

Codecov / codecov/patch

crates/wasmi/src/engine/code_map.rs#L137-L138

Added lines #L137 - L138 were not covered by tests
let allocs = engine.get_allocs();
let translator = FuncTranslator::new(func_idx, module, allocs.0)?;
let func_to_validate = FuncToValidate {
resources,
index: func_idx.into_u32(),

Check warning on line 143 in crates/wasmi/src/engine/code_map.rs

View check run for this annotation

Codecov / codecov/patch

crates/wasmi/src/engine/code_map.rs#L141-L143

Added lines #L141 - L143 were not covered by tests
ty: type_index.0,
features: *features,
};

Check warning on line 146 in crates/wasmi/src/engine/code_map.rs

View check run for this annotation

Codecov / codecov/patch

crates/wasmi/src/engine/code_map.rs#L145-L146

Added lines #L145 - L146 were not covered by tests
let validator = func_to_validate.into_validator(allocs.1);
let translator = ValidatingFuncTranslator::new(validator, translator)?;
let allocs = FuncTranslationDriver::new(0, &bytes[..], translator)?.translate(
Expand All @@ -163,8 +170,8 @@

/// An internal uncompiled function entity.
pub struct UncompiledFuncEntity {
/// The index of the function within the `module`.
func_idx: FuncIdx,
/// The index of the function within the Wasm module.
func_index: FuncIdx,
/// The Wasm binary bytes.
bytes: SmallByteSlice,
/// The Wasm module of the Wasm function.
Expand All @@ -175,33 +182,48 @@
/// Optional Wasm validation information.
///
/// This is `Some` if the [`UncompiledFuncEntity`] is to be validated upon compilation.
func_to_validate: Option<FuncToValidate<ValidatorResources>>,
validation: Option<(TypeIndex, ValidatorResources)>,
}

/// A function type index into the Wasm module.
#[derive(Debug, Copy, Clone)]

Check warning on line 189 in crates/wasmi/src/engine/code_map.rs

View check run for this annotation

Codecov / codecov/patch

crates/wasmi/src/engine/code_map.rs#L189

Added line #L189 was not covered by tests
#[repr(transparent)]
pub struct TypeIndex(u32);

Check warning on line 191 in crates/wasmi/src/engine/code_map.rs

View check run for this annotation

Codecov / codecov/patch

crates/wasmi/src/engine/code_map.rs#L191

Added line #L191 was not covered by tests

impl UncompiledFuncEntity {
/// Creates a new [`UncompiledFuncEntity`].
pub fn new(
func_idx: FuncIdx,
func_index: FuncIdx,
bytes: impl Into<SmallByteSlice>,
module: ModuleHeader,
func_to_validate: impl Into<Option<FuncToValidate<ValidatorResources>>>,
) -> Self {
let validation = func_to_validate.into().map(|func_to_validate| {
assert_eq!(

Check warning on line 202 in crates/wasmi/src/engine/code_map.rs

View check run for this annotation

Codecov / codecov/patch

crates/wasmi/src/engine/code_map.rs#L201-L202

Added lines #L201 - L202 were not covered by tests
func_to_validate.index,
func_index.into_u32(),

Check warning on line 204 in crates/wasmi/src/engine/code_map.rs

View check run for this annotation

Codecov / codecov/patch

crates/wasmi/src/engine/code_map.rs#L204

Added line #L204 was not covered by tests
"Wasmi function index ({}) does not match with Wasm validation function index ({})",
func_to_validate.index,
func_index.into_u32(),

Check warning on line 207 in crates/wasmi/src/engine/code_map.rs

View check run for this annotation

Codecov / codecov/patch

crates/wasmi/src/engine/code_map.rs#L207

Added line #L207 was not covered by tests
);
(TypeIndex(func_to_validate.ty), func_to_validate.resources)
});

Check warning on line 210 in crates/wasmi/src/engine/code_map.rs

View check run for this annotation

Codecov / codecov/patch

crates/wasmi/src/engine/code_map.rs#L209-L210

Added lines #L209 - L210 were not covered by tests
Self {
func_idx,
func_index,

Check warning on line 212 in crates/wasmi/src/engine/code_map.rs

View check run for this annotation

Codecov / codecov/patch

crates/wasmi/src/engine/code_map.rs#L212

Added line #L212 was not covered by tests
bytes: bytes.into(),
module,
func_to_validate: func_to_validate.into(),
validation,

Check warning on line 215 in crates/wasmi/src/engine/code_map.rs

View check run for this annotation

Codecov / codecov/patch

crates/wasmi/src/engine/code_map.rs#L215

Added line #L215 was not covered by tests
}
}
}

impl fmt::Debug for UncompiledFuncEntity {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.debug_struct("UncompiledFuncEntity")
.field("func_idx", &self.func_idx)
.field("func_idx", &self.func_index)

Check warning on line 223 in crates/wasmi/src/engine/code_map.rs

View check run for this annotation

Codecov / codecov/patch

crates/wasmi/src/engine/code_map.rs#L223

Added line #L223 was not covered by tests
.field("bytes", &self.bytes)
.field("module", &self.module)
.field("validate", &self.func_to_validate.is_some())
.field("validate", &self.validation.is_some())

Check warning on line 226 in crates/wasmi/src/engine/code_map.rs

View check run for this annotation

Codecov / codecov/patch

crates/wasmi/src/engine/code_map.rs#L226

Added line #L226 was not covered by tests
.finish()
}
}
Expand Down Expand Up @@ -233,7 +255,7 @@

impl SmallByteSlice {
/// The maximum amount of bytes that can be stored inline.
const MAX_INLINE_SIZE: usize = 30;
const MAX_INLINE_SIZE: usize = 22;

/// Returns the underlying slice of bytes.
#[inline]
Expand Down Expand Up @@ -353,9 +375,10 @@
}

/// Datastructure to efficiently store information about compiled functions.
#[derive(Debug, Default)]
#[derive(Debug)]

Check warning on line 378 in crates/wasmi/src/engine/code_map.rs

View check run for this annotation

Codecov / codecov/patch

crates/wasmi/src/engine/code_map.rs#L378

Added line #L378 was not covered by tests
pub struct CodeMap {
funcs: Arena<CompiledFunc, FuncEntity>,
features: WasmFeatures,

Check warning on line 381 in crates/wasmi/src/engine/code_map.rs

View check run for this annotation

Codecov / codecov/patch

crates/wasmi/src/engine/code_map.rs#L381

Added line #L381 was not covered by tests
}

/// Atomicly accessible [`CompilationPhase`].
Expand Down Expand Up @@ -639,6 +662,7 @@
pub fn compile_and_get(
&self,
mut fuel: Option<&mut Fuel>,
features: &WasmFeatures,
) -> Result<&CompiledFuncEntity, Error> {
loop {
if let Some(func) = self.get_compiled() {
Expand All @@ -661,7 +685,7 @@
// Note: We need to use `take` because Rust doesn't know that this part of
// the loop is only executed once.
let fuel = fuel.take();
match func.compile(fuel) {
match func.compile(fuel, features) {

Check warning on line 688 in crates/wasmi/src/engine/code_map.rs

View check run for this annotation

Codecov / codecov/patch

crates/wasmi/src/engine/code_map.rs#L688

Added line #L688 was not covered by tests
Ok(()) => {
self.phase
.set_compiled()
Expand All @@ -679,6 +703,14 @@
}

impl CodeMap {
/// Creates a new [`CodeMap`].
pub fn new(config: &Config) -> Self {
Self {
funcs: Arena::default(),
features: config.wasm_features(),
}

Check warning on line 711 in crates/wasmi/src/engine/code_map.rs

View check run for this annotation

Codecov / codecov/patch

crates/wasmi/src/engine/code_map.rs#L711

Added line #L711 was not covered by tests
}

/// Allocates a new uninitialized [`CompiledFunc`] to the [`CodeMap`].
///
/// # Note
Expand Down Expand Up @@ -739,7 +771,7 @@
};
match func.get_compiled() {
Some(func) => Ok(func),
None => func.compile_and_get(fuel),
None => func.compile_and_get(fuel, &self.features),

Check warning on line 774 in crates/wasmi/src/engine/code_map.rs

View check run for this annotation

Codecov / codecov/patch

crates/wasmi/src/engine/code_map.rs#L774

Added line #L774 was not covered by tests
}
}
}
Expand Down
6 changes: 3 additions & 3 deletions crates/wasmi/src/engine/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -594,7 +594,7 @@ impl EngineInner {
fn new(config: &Config) -> Self {
Self {
config: *config,
res: RwLock::new(EngineResources::new()),
res: RwLock::new(EngineResources::new(config)),
allocs: Mutex::new(ReusableAllocationStack::default()),
stacks: Mutex::new(EngineStacks::new(config)),
}
Expand Down Expand Up @@ -804,10 +804,10 @@ pub struct EngineResources {

impl EngineResources {
/// Creates a new [`EngineResources`].
fn new() -> Self {
fn new(config: &Config) -> Self {
let engine_idx = EngineIdx::new();
Self {
code_map: CodeMap::default(),
code_map: CodeMap::new(config),
func_types: FuncTypeRegistry::new(engine_idx),
}
}
Expand Down
Loading