@@ -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} ;
2221use 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+
216257impl 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