@@ -4,7 +4,11 @@ macro_rules! define_stable_dispatch {
44 ( $executor: ident, $instr_ptr: ident, $dispatch_next: ident, $dispatch_flow: ident;
55 $( $variant: ident $( ( $( $arg: pat) ,* ) ) ? $( { $( $field: ident) ,* } ) ? => $body: expr) ,* $( , ) ?) => {
66 #[ inline( always) ]
7- fn exec_step( $executor: & mut Self , $instr_ptr: usize ) -> ExecResult <ExecFlow > {
7+ fn exec_step(
8+ $executor: & mut Self ,
9+ instructions: & [ tinywasm_types:: Instruction ] ,
10+ $instr_ptr: usize ,
11+ ) -> ExecResult <ExecFlow > {
812 macro_rules! $dispatch_next {
913 ( $next_instr_ptr: expr) => { {
1014 return Ok ( ExecFlow :: Next ( $next_instr_ptr) ) ;
@@ -16,23 +20,49 @@ macro_rules! define_stable_dispatch {
1620 } } ;
1721 }
1822 use tinywasm_types:: Instruction :: * ;
19- match & $executor . func . instructions[ $instr_ptr] {
23+ match & instructions[ $instr_ptr] {
2024 $( $variant $( ( $( $arg) ,* ) ) ? $( { $( $field) ,* } ) ? => $body, ) *
2125 }
2226 Ok ( ExecFlow :: Next ( $instr_ptr + 1 ) )
2327 }
2428 } ;
2529}
2630
27- impl Executor < ' _ , ' _ > {
31+ impl < ' module > Executor < ' _ , ' module > {
2832 instruction_handlers ! ( define_stable_dispatch) ;
2933
34+ /// The executing function's instructions. They are borrowed from the module instance, not from
35+ /// the executor, so the dispatch loop keeps them in a local across steps.
36+ #[ inline( always) ]
37+ fn instructions ( & self ) -> & ' module [ tinywasm_types:: Instruction ] {
38+ let func: & ' module WasmFunction = self . func ;
39+ & func. instructions
40+ }
41+
42+ /// One step from `instr_ptr`. A step that switches functions reloads `instructions`.
43+ #[ inline( always) ]
44+ fn step (
45+ & mut self ,
46+ instructions : & mut & ' module [ tinywasm_types:: Instruction ] ,
47+ instr_ptr : usize ,
48+ ) -> ExecResult < Option < usize > > {
49+ Ok ( match Self :: exec_step ( self , instructions, instr_ptr) ? {
50+ ExecFlow :: Next ( next_instr_ptr) => Some ( next_instr_ptr) ,
51+ ExecFlow :: Switch ( next_instr_ptr) => {
52+ * instructions = self . instructions ( ) ;
53+ Some ( next_instr_ptr)
54+ }
55+ ExecFlow :: Complete => None ,
56+ } )
57+ }
58+
3059 /// Runs until the call completes (`None`) or continues in another module instance's frame.
3160 #[ inline( always) ]
3261 pub ( crate ) fn run_to_completion ( mut self ) -> Result < Option < CallFrame > > {
3362 let mut instr_ptr = self . cf . instr_ptr ;
63+ let mut instructions = self . instructions ( ) ;
3464 loop {
35- match Self :: exec_step ( & mut self , instr_ptr) ?. next_instr_ptr ( ) {
65+ match self . step ( & mut instructions , instr_ptr) ? {
3666 Some ( next_instr_ptr) => instr_ptr = next_instr_ptr,
3767 None => return cold ! ( Ok ( self . left( ) ) ) ,
3868 }
@@ -50,10 +80,11 @@ impl Executor<'_, '_> {
5080 mut chunk_left : u32 ,
5181 ) -> Result < RunEnd > {
5282 let mut instr_ptr = self . cf . instr_ptr ;
83+ let mut instructions = self . instructions ( ) ;
5384 loop {
5485 while chunk_left != 0 {
5586 chunk_left -= 1 ;
56- match Self :: exec_step ( & mut self , instr_ptr) ?. next_instr_ptr ( ) {
87+ match self . step ( & mut instructions , instr_ptr) ? {
5788 Some ( next_instr_ptr) => instr_ptr = next_instr_ptr,
5889 None => return Ok ( self . run_end ( chunk_left) ) ,
5990 }
@@ -72,10 +103,11 @@ impl Executor<'_, '_> {
72103 pub ( crate ) fn run_with_fuel ( mut self , mut chunk_left : u32 ) -> Result < RunEnd > {
73104 self . fuel_metered = true ;
74105 let mut instr_ptr = self . cf . instr_ptr ;
106+ let mut instructions = self . instructions ( ) ;
75107 loop {
76108 while chunk_left != 0 {
77109 chunk_left -= 1 ;
78- match Self :: exec_step ( & mut self , instr_ptr) ?. next_instr_ptr ( ) {
110+ match self . step ( & mut instructions , instr_ptr) ? {
79111 Some ( next_instr_ptr) => instr_ptr = next_instr_ptr,
80112 None => return Ok ( self . run_end ( chunk_left) ) ,
81113 }
0 commit comments