11use alloc:: format;
22use alloc:: string:: ToString ;
33use core:: ops:: { BitAnd , BitOr , BitXor , Neg } ;
4- use tinywasm_types:: { BlockArgs , ElementKind , ValType } ;
4+ use tinywasm_types:: { BlockArgs , ElementKind , Instruction , ValType } ;
55
66use super :: { InterpreterRuntime , RawWasmValue , Stack } ;
77use crate :: runtime:: { BlockFrame , BlockType , CallFrame } ;
@@ -48,84 +48,43 @@ impl<'store, 'stack> Executor<'store, 'stack> {
4848
4949 pub ( crate ) fn run_to_completion ( & mut self ) -> Result < ( ) > {
5050 loop {
51- match self . exec_one ( ) ? {
52- ExecResult :: Return => return Ok ( ( ) ) ,
53- ExecResult :: Continue => continue ,
51+ match self . next ( ) {
52+ Ok ( ExecResult :: Return ) => return Ok ( ( ) ) ,
53+ Ok ( ExecResult :: Continue ) => continue ,
54+ Err ( e) => {
55+ cold ( ) ;
56+ return Err ( e) ;
57+ }
5458 } ;
5559 }
5660 }
5761
58- pub ( crate ) fn process_call ( & mut self ) -> Result < ExecResult > {
59- let old = self . cf . block_ptr ;
60- self . cf = self . stack . call_stack . pop ( ) ?;
61-
62- if old > self . cf . block_ptr {
63- self . stack . blocks . truncate ( old) ;
64- }
65-
66- if self . cf . module_addr != self . module . id ( ) {
67- self . module . swap_with ( self . cf . module_addr , self . store ) ;
68- }
69-
70- Ok ( ExecResult :: Continue )
71- }
72-
73- pub ( crate ) fn exec_one ( & mut self ) -> Result < ExecResult > {
62+ #[ inline( always) ]
63+ pub ( crate ) fn next ( & mut self ) -> Result < ExecResult > {
7464 use tinywasm_types:: Instruction :: * ;
7565 match self . cf . fetch_instr ( ) {
7666 Nop => cold ( ) ,
7767 Unreachable => self . exec_unreachable ( ) ?,
68+
7869 Drop => self . stack . values . pop ( ) . map ( |_| ( ) ) ?,
7970 Select ( _valtype) => self . exec_select ( ) ?,
8071
81- Call ( v) => skip ! ( self . exec_call( * v) ) ,
82- CallIndirect ( ty, table) => {
83- skip ! ( self . exec_call_indirect ( * ty , * table ) )
84- }
85- If ( args , el , end ) => skip ! ( self . exec_if ( ( * args ) . into ( ) , * el , * end ) ) ,
72+ Call ( v) => return self . exec_call ( * v) ,
73+ CallIndirect ( ty, table) => return self . exec_call_indirect ( * ty , * table ) ,
74+
75+ If ( args , el , end ) => return self . exec_if ( ( * args ) . into ( ) , * el , * end ) ,
76+ Else ( end_offset ) => self . exec_else ( * end_offset ) ? ,
8677 Loop ( args, end) => self . enter_block ( self . cf . instr_ptr , * end, BlockType :: Loop , * args) ,
8778 Block ( args, end) => self . enter_block ( self . cf . instr_ptr , * end, BlockType :: Block , * args) ,
88-
8979 Br ( v) => break_to ! ( * v, self ) ,
90- BrIf ( v) => {
91- if i32:: from ( self . stack . values . pop ( ) ?) != 0 {
92- break_to ! ( * v, self ) ;
93- }
94- }
95- BrTable ( default, len) => {
96- let start = self . cf . instr_ptr + 1 ;
97- let end = start + * len as usize ;
98- if end > self . cf . instructions ( ) . len ( ) {
99- return Err ( Error :: Other ( format ! (
100- "br_table out of bounds: {} >= {}" ,
101- end,
102- self . cf. instructions( ) . len( )
103- ) ) ) ;
104- }
105-
106- let idx: i32 = self . stack . values . pop ( ) ?. into ( ) ;
107- match self . cf . instructions ( ) [ start..end] . get ( idx as usize ) {
108- None => break_to ! ( * default , self ) ,
109- Some ( BrLabel ( to) ) => break_to ! ( * to, self ) ,
110- _ => return Err ( Error :: Other ( "br_table with invalid label" . to_string ( ) ) ) ,
111- }
112- }
113-
114- Return => match self . stack . call_stack . is_empty ( ) {
115- true => return Ok ( ExecResult :: Return ) ,
116- false => return self . process_call ( ) ,
117- } ,
118-
119- // We're essentially using else as a EndBlockFrame instruction for if blocks
120- Else ( end_offset) => self . exec_else ( * end_offset) ?,
121-
122- // remove the label from the label stack
80+ BrIf ( v) => return self . exec_br_if ( * v) ,
81+ BrTable ( default, len) => return self . exec_brtable ( * default, * len) ,
82+ Return => return self . exec_return ( ) ,
12383 EndBlockFrame => self . exec_end_block ( ) ?,
12484
12585 LocalGet ( local_index) => self . exec_local_get ( * local_index) ,
12686 LocalSet ( local_index) => self . exec_local_set ( * local_index) ?,
12787 LocalTee ( local_index) => self . exec_local_tee ( * local_index) ?,
128-
12988 GlobalGet ( global_index) => self . exec_global_get ( * global_index) ?,
13089 GlobalSet ( global_index) => self . exec_global_set ( * global_index) ?,
13190
@@ -337,9 +296,10 @@ impl<'store, 'stack> Executor<'store, 'stack> {
337296 LocalGetSet ( a, b) => self . exec_local_get_set ( * a, * b) ,
338297 I64XorConstRotl ( rotate_by) => self . exec_i64_xor_const_rotl ( * rotate_by) ?,
339298 I32LocalGetConstAdd ( local, val) => self . exec_i32_local_get_const_add ( * local, * val) ,
340- I32StoreLocal { local, const_i32 : consti32 , offset, mem_addr } => {
341- self . exec_i32_store_local ( * local, * consti32 , * offset, * mem_addr) ?
299+ I32StoreLocal { local, const_i32, offset, mem_addr } => {
300+ self . exec_i32_store_local ( * local, * const_i32 , * offset, * mem_addr) ?
342301 }
302+
343303 i => {
344304 cold ( ) ;
345305 return Err ( Error :: UnsupportedFeature ( format ! ( "unimplemented instruction: {:?}" , i) ) ) ;
@@ -365,6 +325,57 @@ impl<'store, 'stack> Executor<'store, 'stack> {
365325 Ok ( ( ) )
366326 }
367327
328+ #[ inline( always) ]
329+ fn exec_br_if ( & mut self , to : u32 ) -> Result < ExecResult > {
330+ let val: i32 = self . stack . values . pop ( ) ?. into ( ) ;
331+ if val != 0 {
332+ break_to ! ( to, self ) ;
333+ }
334+
335+ self . cf . instr_ptr += 1 ;
336+ Ok ( ExecResult :: Continue )
337+ }
338+
339+ #[ inline( always) ]
340+ fn exec_brtable ( & mut self , default : u32 , len : u32 ) -> Result < ExecResult > {
341+ let start = self . cf . instr_ptr + 1 ;
342+ let end = start + len as usize ;
343+ if end > self . cf . instructions ( ) . len ( ) {
344+ return Err ( Error :: Other ( format ! ( "br_table out of bounds: {} >= {}" , end, self . cf. instructions( ) . len( ) ) ) ) ;
345+ }
346+
347+ let idx: i32 = self . stack . values . pop ( ) ?. into ( ) ;
348+
349+ match self . cf . instructions ( ) [ start..end] . get ( idx as usize ) {
350+ None => break_to ! ( default , self ) ,
351+ Some ( Instruction :: BrLabel ( to) ) => break_to ! ( * to, self ) ,
352+ _ => return Err ( Error :: Other ( "br_table with invalid label" . to_string ( ) ) ) ,
353+ }
354+
355+ self . cf . instr_ptr += 1 ;
356+ Ok ( ExecResult :: Continue )
357+ }
358+
359+ #[ inline( always) ]
360+ fn exec_return ( & mut self ) -> Result < ExecResult > {
361+ if self . stack . call_stack . is_empty ( ) {
362+ return Ok ( ExecResult :: Return ) ;
363+ }
364+
365+ let old = self . cf . block_ptr ;
366+ self . cf = self . stack . call_stack . pop ( ) ?;
367+
368+ if old > self . cf . block_ptr {
369+ self . stack . blocks . truncate ( old) ;
370+ }
371+
372+ if self . cf . module_addr != self . module . id ( ) {
373+ self . module . swap_with ( self . cf . module_addr , self . store ) ;
374+ }
375+
376+ Ok ( ExecResult :: Continue )
377+ }
378+
368379 #[ inline( always) ]
369380 #[ cold]
370381 fn exec_unreachable ( & self ) -> Result < ( ) > {
@@ -598,7 +609,7 @@ impl<'store, 'stack> Executor<'store, 'stack> {
598609 }
599610
600611 #[ inline( always) ]
601- fn exec_call ( & mut self , v : u32 ) -> Result < ( ) > {
612+ fn exec_call ( & mut self , v : u32 ) -> Result < ExecResult > {
602613 let func_inst = self . store . get_func ( self . module . resolve_func_addr ( v) ) ?;
603614 let wasm_func = match & func_inst. func {
604615 crate :: Function :: Wasm ( wasm_func) => wasm_func,
@@ -608,7 +619,7 @@ impl<'store, 'stack> Executor<'store, 'stack> {
608619 let res = ( func. func ) ( FuncContext { store : self . store , module_addr : self . module . id ( ) } , & params) ?;
609620 self . stack . values . extend_from_typed ( & res) ;
610621 self . cf . instr_ptr += 1 ;
611- return Ok ( ( ) ) ;
622+ return Ok ( ExecResult :: Continue ) ;
612623 }
613624 } ;
614625
@@ -620,11 +631,11 @@ impl<'store, 'stack> Executor<'store, 'stack> {
620631 if self . cf . module_addr != self . module . id ( ) {
621632 self . module . swap_with ( self . cf . module_addr , self . store ) ;
622633 }
623- Ok ( ( ) )
634+ Ok ( ExecResult :: Continue )
624635 }
625636
626637 #[ inline( always) ]
627- fn exec_call_indirect ( & mut self , type_addr : u32 , table_addr : u32 ) -> Result < ( ) > {
638+ fn exec_call_indirect ( & mut self , type_addr : u32 , table_addr : u32 ) -> Result < ExecResult > {
628639 let table = self . store . get_table ( self . module . resolve_table_addr ( table_addr) ) ?;
629640 let table_idx: u32 = self . stack . values . pop ( ) ?. into ( ) ;
630641
@@ -654,7 +665,7 @@ impl<'store, 'stack> Executor<'store, 'stack> {
654665 let res = ( host_func. func ) ( FuncContext { store : self . store , module_addr : self . module . id ( ) } , & params) ?;
655666 self . stack . values . extend_from_typed ( & res) ;
656667 self . cf . instr_ptr += 1 ;
657- return Ok ( ( ) ) ;
668+ return Ok ( ExecResult :: Continue ) ;
658669 }
659670 } ;
660671
@@ -672,29 +683,30 @@ impl<'store, 'stack> Executor<'store, 'stack> {
672683 if self . cf . module_addr != self . module . id ( ) {
673684 self . module . swap_with ( self . cf . module_addr , self . store ) ;
674685 }
675- Ok ( ( ) )
686+
687+ Ok ( ExecResult :: Continue )
676688 }
677689
678690 #[ inline( always) ]
679- fn exec_if ( & mut self , args : BlockArgs , else_offset : u32 , end_offset : u32 ) -> Result < ( ) > {
691+ fn exec_if ( & mut self , args : BlockArgs , else_offset : u32 , end_offset : u32 ) -> Result < ExecResult > {
680692 // truthy value is on the top of the stack, so enter the then block
681693 if i32:: from ( self . stack . values . pop ( ) ?) != 0 {
682694 self . enter_block ( self . cf . instr_ptr , end_offset, BlockType :: If , args) ;
683695 self . cf . instr_ptr += 1 ;
684- return Ok ( ( ) ) ;
696+ return Ok ( ExecResult :: Continue ) ;
685697 }
686698
687699 // falsy value is on the top of the stack
688700 if else_offset == 0 {
689701 self . cf . instr_ptr += end_offset as usize + 1 ;
690- return Ok ( ( ) ) ;
702+ return Ok ( ExecResult :: Continue ) ;
691703 }
692704
693705 let old = self . cf . instr_ptr ;
694706 self . cf . instr_ptr += else_offset as usize ;
695707 self . enter_block ( old + else_offset as usize , end_offset - else_offset, BlockType :: Else , args) ;
696708 self . cf . instr_ptr += 1 ;
697- Ok ( ( ) )
709+ Ok ( ExecResult :: Continue )
698710 }
699711
700712 #[ inline( always) ]
0 commit comments