Skip to content

Commit 6111401

Browse files
authored
Remove smallvec usage from ConstExpr::new method (#1626)
* simplify ConstExpr::new * add ConstExprStack type * use new ConstExprStack type * redo some panic messages * remove no longer used smallvec dependency * fix ConstExprStack::pop2 method * add #Note comment to top field * apply rustfmt
1 parent c09b97d commit 6111401

File tree

3 files changed

+69
-46
lines changed

3 files changed

+69
-46
lines changed

Cargo.lock

Lines changed: 0 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

crates/wasmi/Cargo.toml

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,6 @@ spin = { version = "0.9", default-features = false, features = [
2929
"spin_mutex",
3030
"rwlock",
3131
] }
32-
smallvec = { version = "1.13.1", features = ["union"] }
3332

3433
[dev-dependencies]
3534
assert_matches = "1.5"

crates/wasmi/src/module/init_expr.rs

Lines changed: 69 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -16,9 +16,8 @@ use crate::{
1616
F32,
1717
F64,
1818
};
19-
use alloc::boxed::Box;
20-
use core::fmt;
21-
use smallvec::SmallVec;
19+
use alloc::{boxed::Box, vec::Vec};
20+
use core::{fmt, mem};
2221
use wasmparser::AbstractHeapType;
2322

2423
#[cfg(feature = "simd")]
@@ -213,6 +212,48 @@ macro_rules! def_expr {
213212
}};
214213
}
215214

215+
/// Stack to translate [`ConstExpr`].
216+
#[derive(Debug, Default)]
217+
pub struct ConstExprStack {
218+
/// The top-most [`Op`] on the stack.
219+
///
220+
/// # Note
221+
/// This is an optimization so that the [`ConstExprStack`] does not
222+
/// require heap allocations for the common case where only a single
223+
/// stack slot is needed.
224+
top: Option<Op>,
225+
/// The remaining ops on the stack.
226+
ops: Vec<Op>,
227+
}
228+
229+
impl ConstExprStack {
230+
/// Returns `true` if [`ConstExprStack`] is empty.
231+
pub fn is_empty(&self) -> bool {
232+
self.ops.is_empty()
233+
}
234+
235+
/// Pushes an [`Op`] to the [`ConstExprStack`].
236+
pub fn push(&mut self, op: Op) {
237+
let old_top = self.top.replace(op);
238+
if let Some(old_top) = old_top {
239+
self.ops.push(old_top);
240+
}
241+
}
242+
243+
/// Pops the top-most [`Op`] from the [`ConstExprStack`] if any.
244+
pub fn pop(&mut self) -> Option<Op> {
245+
let new_top = self.ops.pop();
246+
mem::replace(&mut self.top, new_top)
247+
}
248+
249+
/// Pops the 2 top-most [`Op`]s from the [`ConstExprStack`] if any.
250+
pub fn pop2(&mut self) -> Option<(Op, Op)> {
251+
let rhs = self.pop()?;
252+
let lhs = self.pop()?;
253+
Some((lhs, rhs))
254+
}
255+
}
256+
216257
impl ConstExpr {
217258
/// Creates a new [`ConstExpr`] from the given Wasm [`ConstExpr`].
218259
///
@@ -221,23 +262,18 @@ impl ConstExpr {
221262
/// The constructor assumes that Wasm validation already succeeded
222263
/// on the input Wasm [`ConstExpr`].
223264
pub fn new(expr: wasmparser::ConstExpr<'_>) -> Self {
224-
/// A buffer required for translation of Wasm const expressions.
225-
type TranslationBuffer = SmallVec<[Op; 3]>;
226265
/// Convenience function to create the various expression operators.
227-
fn expr_op<Lhs, Rhs, T>(stack: &mut TranslationBuffer, expr: fn(Lhs, Rhs) -> T)
266+
fn expr_op<Lhs, Rhs, T>(stack: &mut ConstExprStack, expr: fn(Lhs, Rhs) -> T) -> Op
228267
where
229268
Lhs: From<UntypedVal> + 'static,
230269
Rhs: From<UntypedVal> + 'static,
231270
T: 'static,
232271
UntypedVal: From<T>,
233272
{
234-
let rhs = stack
235-
.pop()
236-
.expect("must have rhs operator on the stack due to Wasm validation");
237-
let lhs = stack
238-
.pop()
239-
.expect("must have lhs operator on the stack due to Wasm validation");
240-
let op = match (lhs, rhs) {
273+
let (lhs, rhs) = stack
274+
.pop2()
275+
.expect("must have 2 operators on the stack due to Wasm validation");
276+
match (lhs, rhs) {
241277
(Op::Const(lhs), Op::Const(rhs)) => def_expr!(lhs, rhs, expr),
242278
(Op::Const(lhs), Op::Global(rhs)) => def_expr!(lhs, rhs, expr),
243279
(Op::Const(lhs), Op::FuncRef(rhs)) => def_expr!(lhs, rhs, expr),
@@ -254,36 +290,29 @@ impl ConstExpr {
254290
(Op::Expr(lhs), Op::Global(rhs)) => def_expr!(lhs, rhs, expr),
255291
(Op::Expr(lhs), Op::FuncRef(rhs)) => def_expr!(lhs, rhs, expr),
256292
(Op::Expr(lhs), Op::Expr(rhs)) => def_expr!(lhs, rhs, expr),
257-
};
258-
stack.push(op);
293+
}
259294
}
260295

261296
let mut reader = expr.get_operators_reader();
262-
let mut stack = TranslationBuffer::new();
297+
let mut stack = ConstExprStack::default();
263298
loop {
264-
let op = reader.read().unwrap_or_else(|error| {
265-
panic!("unexpectedly encountered invalid const expression operator: {error}")
266-
});
267-
match op {
268-
wasmparser::Operator::I32Const { value } => {
269-
stack.push(Op::constant(value));
270-
}
271-
wasmparser::Operator::I64Const { value } => {
272-
stack.push(Op::constant(value));
273-
}
299+
let wasm_op = reader
300+
.read()
301+
.unwrap_or_else(|error| panic!("invalid const expression operator: {error}"));
302+
let op = match wasm_op {
303+
wasmparser::Operator::I32Const { value } => Op::constant(value),
304+
wasmparser::Operator::I64Const { value } => Op::constant(value),
274305
wasmparser::Operator::F32Const { value } => {
275-
stack.push(Op::constant(F32::from_bits(value.bits())));
306+
Op::constant(F32::from_bits(value.bits()))
276307
}
277308
wasmparser::Operator::F64Const { value } => {
278-
stack.push(Op::constant(F64::from_bits(value.bits())));
309+
Op::constant(F64::from_bits(value.bits()))
279310
}
280311
#[cfg(feature = "simd")]
281312
wasmparser::Operator::V128Const { value } => {
282-
stack.push(Op::constant(V128::from(value.i128() as u128)));
283-
}
284-
wasmparser::Operator::GlobalGet { global_index } => {
285-
stack.push(Op::global(global_index));
313+
Op::constant(V128::from(value.i128() as u128))
286314
}
315+
wasmparser::Operator::GlobalGet { global_index } => Op::global(global_index),
287316
wasmparser::Operator::RefNull { hty } => {
288317
let value = match hty {
289318
wasmparser::HeapType::Abstract {
@@ -295,34 +324,30 @@ impl ConstExpr {
295324
ty: AbstractHeapType::Extern,
296325
} => Val::from(<Ref<ExternRef>>::Null),
297326
invalid => {
298-
panic!("encountered invalid heap type for `ref.null`: {invalid:?}")
327+
panic!("invalid heap type for `ref.null`: {invalid:?}")
299328
}
300329
};
301-
stack.push(Op::constant(value));
302-
}
303-
wasmparser::Operator::RefFunc { function_index } => {
304-
stack.push(Op::funcref(function_index));
330+
Op::constant(value)
305331
}
332+
wasmparser::Operator::RefFunc { function_index } => Op::funcref(function_index),
306333
wasmparser::Operator::I32Add => expr_op(&mut stack, wasm::i32_add),
307334
wasmparser::Operator::I32Sub => expr_op(&mut stack, wasm::i32_sub),
308335
wasmparser::Operator::I32Mul => expr_op(&mut stack, wasm::i32_mul),
309336
wasmparser::Operator::I64Add => expr_op(&mut stack, wasm::i64_add),
310337
wasmparser::Operator::I64Sub => expr_op(&mut stack, wasm::i64_sub),
311338
wasmparser::Operator::I64Mul => expr_op(&mut stack, wasm::i64_mul),
312339
wasmparser::Operator::End => break,
313-
op => panic!("encountered invalid Wasm const expression operator: {op:?}"),
340+
op => panic!("unexpected Wasm const expression operator: {op:?}"),
314341
};
342+
stack.push(op);
315343
}
316344
reader
317345
.ensure_end()
318-
.expect("due to Wasm validation this is guaranteed to succeed");
346+
.expect("Wasm validation requires const expressions to have an `end`");
319347
let op = stack
320348
.pop()
321-
.expect("due to Wasm validation must have one operator on the stack");
322-
assert!(
323-
stack.is_empty(),
324-
"due to Wasm validation operator stack must be empty now"
325-
);
349+
.expect("must contain the root const expression at this point");
350+
debug_assert!(stack.is_empty());
326351
Self { op }
327352
}
328353

0 commit comments

Comments
 (0)