@@ -136,6 +136,51 @@ impl Counter {
136136 }
137137}
138138
139+ fn inject_inline_gas ( module : elements:: Module ) -> elements:: Module {
140+ use parity_wasm:: elements:: Instruction :: * ;
141+
142+ static DEFAULT_START_GAS : i32 = 2000000000 ; // 4 billion is too big for signed integer
143+
144+ let global_gas_index = module. globals_space ( ) as u32 ;
145+ println ! ( "total globals before injecting gas global: {:?}" , global_gas_index) ;
146+
147+ let b = builder:: from_module ( module) ;
148+
149+ let mut b2 = b. global ( ) . mutable ( )
150+ . value_type ( ) . i32 ( ) . init_expr ( elements:: Instruction :: I32Const ( DEFAULT_START_GAS ) )
151+ . build ( )
152+ . export ( )
153+ . field ( "gas_global" )
154+ . internal ( ) . global ( global_gas_index)
155+ . build ( ) ;
156+
157+ b2. push_function (
158+ builder:: function ( )
159+ . signature ( ) . param ( ) . i32 ( ) . build ( )
160+ . body ( )
161+ . with_locals ( vec ! [ elements:: Local :: new( 1 , elements:: ValueType :: I32 ) ] )
162+ . with_instructions ( elements:: Instructions :: new ( vec ! [
163+ GetGlobal ( global_gas_index) ,
164+ GetLocal ( 0 ) , // local 0 is the input param
165+ I32Sub ,
166+ TeeLocal ( 1 ) , // save deducted gas to local, because stack item will be consumed by i32.lte_s
167+ I32Const ( 0 as i32 ) ,
168+ I32LtS ,
169+ If ( elements:: BlockType :: NoResult ) ,
170+ Unreachable ,
171+ End ,
172+ GetLocal ( 1 ) , // put deducted gas back on stack
173+ SetGlobal ( global_gas_index) , // save to global
174+ End ,
175+ ] ) )
176+ . build ( )
177+ . build ( )
178+ ) ;
179+
180+ b2. build ( )
181+
182+ }
183+
139184fn inject_grow_counter ( instructions : & mut elements:: Instructions , grow_counter_func : u32 ) -> usize {
140185 use parity_wasm:: elements:: Instruction :: * ;
141186 let mut counter = 0 ;
@@ -312,8 +357,12 @@ pub fn inject_counter(
312357pub fn inject_gas_counter ( module : elements:: Module , rules : & rules:: Set )
313358 -> Result < elements:: Module , elements:: Module >
314359{
360+ let mbuilder = builder:: from_module ( module) ;
361+ let mut module = mbuilder. build ( ) ;
362+
363+ /*
364+ // we are doing inline gas metering, so disable the external metering
315365 // Injecting gas counting external
316- let mut mbuilder = builder:: from_module ( module) ;
317366 let import_sig = mbuilder.push_signature(
318367 builder::signature()
319368 .param().i32()
@@ -335,7 +384,16 @@ pub fn inject_gas_counter(module: elements::Module, rules: &rules::Set)
335384 // (substract all imports that are NOT functions)
336385
337386 let gas_func = module.import_count(elements::ImportCountType::Function) as u32 - 1;
338- let total_func = module. functions_space ( ) as u32 ;
387+ */
388+
389+
390+ // for inline gas function
391+ let gas_func = module. functions_space ( ) as u32 ;
392+
393+ // need to inject inline gas function after the metering statements,
394+ // or the gas function itself with be metered and recursively call itself
395+
396+ let total_func = gas_func + 1 ;
339397 let mut need_grow_counter = false ;
340398 let mut error = false ;
341399
@@ -378,6 +436,9 @@ pub fn inject_gas_counter(module: elements::Module, rules: &rules::Set)
378436
379437 if error { return Err ( module) ; }
380438
439+ // metering calls have been injected, now inject inline gas func
440+ module = inject_inline_gas ( module) ;
441+
381442 if need_grow_counter { Ok ( add_grow_counter ( module, rules, gas_func) ) } else { Ok ( module) }
382443}
383444
0 commit comments