@@ -23,6 +23,7 @@ use crate::{
23
23
} ,
24
24
func:: FuncEntity ,
25
25
table:: TableEntity ,
26
+ FuelConsumptionMode ,
26
27
Func ,
27
28
FuncRef ,
28
29
Instance ,
@@ -164,6 +165,21 @@ struct Executor<'ctx, 'engine> {
164
165
code_map : & ' engine CodeMap ,
165
166
}
166
167
168
+ macro_rules! forward_call {
169
+ ( $expr: expr) => { {
170
+ if let CallOutcome :: Call {
171
+ host_func,
172
+ instance,
173
+ } = $expr?
174
+ {
175
+ return Ok ( WasmOutcome :: Call {
176
+ host_func,
177
+ instance,
178
+ } ) ;
179
+ }
180
+ } } ;
181
+ }
182
+
167
183
impl < ' ctx , ' engine > Executor < ' ctx , ' engine > {
168
184
/// Creates a new [`Executor`] for executing a `wasmi` function frame.
169
185
#[ inline( always) ]
@@ -214,56 +230,18 @@ impl<'ctx, 'engine> Executor<'ctx, 'engine> {
214
230
}
215
231
}
216
232
Instr :: ReturnCall { drop_keep, func } => {
217
- if let CallOutcome :: Call {
218
- host_func,
219
- instance,
220
- } = self . visit_return_call ( drop_keep, func) ?
221
- {
222
- return Ok ( WasmOutcome :: Call {
223
- host_func,
224
- instance,
225
- } ) ;
226
- }
233
+ forward_call ! ( self . visit_return_call( drop_keep, func) )
227
234
}
228
235
Instr :: ReturnCallIndirect {
229
236
drop_keep,
230
237
table,
231
238
func_type,
232
239
} => {
233
- if let CallOutcome :: Call {
234
- host_func,
235
- instance,
236
- } = self . visit_return_call_indirect ( drop_keep, table, func_type) ?
237
- {
238
- return Ok ( WasmOutcome :: Call {
239
- host_func,
240
- instance,
241
- } ) ;
242
- }
243
- }
244
- Instr :: Call ( func) => {
245
- if let CallOutcome :: Call {
246
- host_func,
247
- instance,
248
- } = self . visit_call ( func) ?
249
- {
250
- return Ok ( WasmOutcome :: Call {
251
- host_func,
252
- instance,
253
- } ) ;
254
- }
240
+ forward_call ! ( self . visit_return_call_indirect( drop_keep, table, func_type) )
255
241
}
242
+ Instr :: Call ( func) => forward_call ! ( self . visit_call( func) ) ,
256
243
Instr :: CallIndirect { table, func_type } => {
257
- if let CallOutcome :: Call {
258
- host_func,
259
- instance,
260
- } = self . visit_call_indirect ( table, func_type) ?
261
- {
262
- return Ok ( WasmOutcome :: Call {
263
- host_func,
264
- instance,
265
- } ) ;
266
- }
244
+ forward_call ! ( self . visit_call_indirect( table, func_type) )
267
245
}
268
246
Instr :: Drop => self . visit_drop ( ) ,
269
247
Instr :: Select => self . visit_select ( ) ,
@@ -599,7 +577,7 @@ impl<'ctx, 'engine> Executor<'ctx, 'engine> {
599
577
///
600
578
/// This also modifies the stack as the caller would expect it
601
579
/// and synchronizes the execution state with the outer structures.
602
- #[ inline]
580
+ #[ inline( always ) ]
603
581
fn ret ( & mut self , drop_keep : DropKeep ) -> ReturnOutcome {
604
582
self . sp . drop_keep ( drop_keep) ;
605
583
self . sync_stack_ptr ( ) ;
@@ -622,49 +600,113 @@ impl<'ctx, 'engine> Executor<'ctx, 'engine> {
622
600
/// for amount of required fuel determined by `delta` or if
623
601
/// fuel metering is disabled.
624
602
///
625
- /// Only if `exec` runs successfully and fuel metering
626
- /// is enabled the fuel determined by `delta` is charged.
627
- ///
628
603
/// # Errors
629
604
///
630
605
/// - If the [`StoreInner`] ran out of fuel.
631
606
/// - If the `exec` closure traps.
632
- fn consume_fuel_on_success < T , E > (
607
+ #[ inline( always) ]
608
+ fn consume_fuel_with < T , E > (
633
609
& mut self ,
634
610
delta : impl FnOnce ( & FuelCosts ) -> u64 ,
635
611
exec : impl FnOnce ( & mut Self ) -> Result < T , E > ,
636
612
) -> Result < T , E >
637
613
where
638
614
E : From < TrapCode > ,
639
615
{
640
- if !self . is_fuel_metering_enabled ( ) {
641
- return exec ( self ) ;
616
+ match self . get_fuel_consumption_mode ( ) {
617
+ None => exec ( self ) ,
618
+ Some ( mode) => self . consume_fuel_with_mode ( mode, delta, exec) ,
642
619
}
643
- // At this point we know that fuel metering is enabled.
620
+ }
621
+
622
+ /// Consume an amount of fuel specified by `delta` and executes `exec`.
623
+ ///
624
+ /// The `mode` determines when and if the fuel determined by `delta` is charged.
625
+ ///
626
+ /// # Errors
627
+ ///
628
+ /// - If the [`StoreInner`] ran out of fuel.
629
+ /// - If the `exec` closure traps.
630
+ #[ inline( always) ]
631
+ fn consume_fuel_with_mode < T , E > (
632
+ & mut self ,
633
+ mode : FuelConsumptionMode ,
634
+ delta : impl FnOnce ( & FuelCosts ) -> u64 ,
635
+ exec : impl FnOnce ( & mut Self ) -> Result < T , E > ,
636
+ ) -> Result < T , E >
637
+ where
638
+ E : From < TrapCode > ,
639
+ {
644
640
let delta = delta ( self . fuel_costs ( ) ) ;
641
+ match mode {
642
+ FuelConsumptionMode :: Lazy => self . consume_fuel_with_lazy ( delta, exec) ,
643
+ FuelConsumptionMode :: Eager => self . consume_fuel_with_eager ( delta, exec) ,
644
+ }
645
+ }
646
+
647
+ /// Consume an amount of fuel specified by `delta` if `exec` succeeds.
648
+ ///
649
+ /// Prior to executing `exec` it is checked if enough fuel is remaining
650
+ /// determined by `delta`. The fuel is charged only after `exec` has been
651
+ /// finished successfully.
652
+ ///
653
+ /// # Errors
654
+ ///
655
+ /// - If the [`StoreInner`] ran out of fuel.
656
+ /// - If the `exec` closure traps.
657
+ #[ inline( always) ]
658
+ fn consume_fuel_with_lazy < T , E > (
659
+ & mut self ,
660
+ delta : u64 ,
661
+ exec : impl FnOnce ( & mut Self ) -> Result < T , E > ,
662
+ ) -> Result < T , E >
663
+ where
664
+ E : From < TrapCode > ,
665
+ {
645
666
self . ctx . fuel ( ) . sufficient_fuel ( delta) ?;
646
667
let result = exec ( self ) ?;
647
668
self . ctx
648
669
. fuel_mut ( )
649
670
. consume_fuel ( delta)
650
- . unwrap_or_else ( |error| {
651
- panic ! ( "remaining fuel has already been approved prior but encountered: {error}" )
652
- } ) ;
671
+ . expect ( "remaining fuel has already been approved prior" ) ;
653
672
Ok ( result)
654
673
}
655
674
656
- /// Returns `true` if fuel metering is enabled.
657
- fn is_fuel_metering_enabled ( & self ) -> bool {
658
- self . ctx . engine ( ) . config ( ) . get_consume_fuel ( )
675
+ /// Consume an amount of fuel specified by `delta` and executes `exec`.
676
+ ///
677
+ /// # Errors
678
+ ///
679
+ /// - If the [`StoreInner`] ran out of fuel.
680
+ /// - If the `exec` closure traps.
681
+ #[ inline( always) ]
682
+ fn consume_fuel_with_eager < T , E > (
683
+ & mut self ,
684
+ delta : u64 ,
685
+ exec : impl FnOnce ( & mut Self ) -> Result < T , E > ,
686
+ ) -> Result < T , E >
687
+ where
688
+ E : From < TrapCode > ,
689
+ {
690
+ self . ctx . fuel_mut ( ) . consume_fuel ( delta) ?;
691
+ exec ( self )
659
692
}
660
693
661
694
/// Returns a shared reference to the [`FuelCosts`] of the [`Engine`].
662
695
///
663
696
/// [`Engine`]: crate::Engine
697
+ #[ inline]
664
698
fn fuel_costs ( & self ) -> & FuelCosts {
665
699
self . ctx . engine ( ) . config ( ) . fuel_costs ( )
666
700
}
667
701
702
+ /// Returns the [`FuelConsumptionMode`] of the [`Engine`].
703
+ ///
704
+ /// [`Engine`]: crate::Engine
705
+ #[ inline]
706
+ fn get_fuel_consumption_mode ( & self ) -> Option < FuelConsumptionMode > {
707
+ self . ctx . engine ( ) . config ( ) . get_fuel_consumption_mode ( )
708
+ }
709
+
668
710
/// Executes a `call` or `return_call` instruction.
669
711
#[ inline( always) ]
670
712
fn execute_call (
@@ -892,7 +934,7 @@ impl<'ctx, 'engine> Executor<'ctx, 'engine> {
892
934
return self . try_next_instr ( ) ;
893
935
}
894
936
} ;
895
- let result = self . consume_fuel_on_success (
937
+ let result = self . consume_fuel_with (
896
938
|costs| {
897
939
let delta_in_bytes = delta. to_bytes ( ) . unwrap_or ( 0 ) as u64 ;
898
940
costs. fuel_for_bytes ( delta_in_bytes)
@@ -928,7 +970,7 @@ impl<'ctx, 'engine> Executor<'ctx, 'engine> {
928
970
let n = i32:: from ( n) as usize ;
929
971
let offset = i32:: from ( d) as usize ;
930
972
let byte = u8:: from ( val) ;
931
- self . consume_fuel_on_success (
973
+ self . consume_fuel_with (
932
974
|costs| costs. fuel_for_bytes ( n as u64 ) ,
933
975
|this| {
934
976
let memory = this
@@ -951,7 +993,7 @@ impl<'ctx, 'engine> Executor<'ctx, 'engine> {
951
993
let n = i32:: from ( n) as usize ;
952
994
let src_offset = i32:: from ( s) as usize ;
953
995
let dst_offset = i32:: from ( d) as usize ;
954
- self . consume_fuel_on_success (
996
+ self . consume_fuel_with (
955
997
|costs| costs. fuel_for_bytes ( n as u64 ) ,
956
998
|this| {
957
999
let data = this. cache . default_memory_bytes ( this. ctx ) ;
@@ -976,7 +1018,7 @@ impl<'ctx, 'engine> Executor<'ctx, 'engine> {
976
1018
let n = i32:: from ( n) as usize ;
977
1019
let src_offset = i32:: from ( s) as usize ;
978
1020
let dst_offset = i32:: from ( d) as usize ;
979
- self . consume_fuel_on_success (
1021
+ self . consume_fuel_with (
980
1022
|costs| costs. fuel_for_bytes ( n as u64 ) ,
981
1023
|this| {
982
1024
let ( memory, data) = this
@@ -1018,7 +1060,7 @@ impl<'ctx, 'engine> Executor<'ctx, 'engine> {
1018
1060
fn visit_table_grow ( & mut self , table_index : TableIdx ) -> Result < ( ) , TrapCode > {
1019
1061
let ( init, delta) = self . sp . pop2 ( ) ;
1020
1062
let delta: u32 = delta. into ( ) ;
1021
- let result = self . consume_fuel_on_success (
1063
+ let result = self . consume_fuel_with (
1022
1064
|costs| costs. fuel_for_elements ( u64:: from ( delta) ) ,
1023
1065
|this| {
1024
1066
let table = this. cache . get_table ( this. ctx , table_index) ;
@@ -1043,7 +1085,7 @@ impl<'ctx, 'engine> Executor<'ctx, 'engine> {
1043
1085
let ( i, val, n) = self . sp . pop3 ( ) ;
1044
1086
let dst: u32 = i. into ( ) ;
1045
1087
let len: u32 = n. into ( ) ;
1046
- self . consume_fuel_on_success (
1088
+ self . consume_fuel_with (
1047
1089
|costs| costs. fuel_for_elements ( u64:: from ( len) ) ,
1048
1090
|this| {
1049
1091
let table = this. cache . get_table ( this. ctx , table_index) ;
@@ -1088,7 +1130,7 @@ impl<'ctx, 'engine> Executor<'ctx, 'engine> {
1088
1130
let len = u32:: from ( n) ;
1089
1131
let src_index = u32:: from ( s) ;
1090
1132
let dst_index = u32:: from ( d) ;
1091
- self . consume_fuel_on_success (
1133
+ self . consume_fuel_with (
1092
1134
|costs| costs. fuel_for_elements ( u64:: from ( len) ) ,
1093
1135
|this| {
1094
1136
// Query both tables and check if they are the same:
@@ -1120,7 +1162,7 @@ impl<'ctx, 'engine> Executor<'ctx, 'engine> {
1120
1162
let len = u32:: from ( n) ;
1121
1163
let src_index = u32:: from ( s) ;
1122
1164
let dst_index = u32:: from ( d) ;
1123
- self . consume_fuel_on_success (
1165
+ self . consume_fuel_with (
1124
1166
|costs| costs. fuel_for_elements ( u64:: from ( len) ) ,
1125
1167
|this| {
1126
1168
let ( instance, table, element) = this
0 commit comments