/// Takes a Wasm binary and inserts the instructions metering and memory grow
/// instrumentation.
///
/// Returns an [`InstrumentationOutput`] or an error if the input binary could
/// not be instrumented.
Takes a Wasm binary and inserts the instructions metering and memory grow
instrumentation.

Returns an [`InstrumentationOutput`] or an error if the input binary could
not be instrumented.
Takes a Wasm binary and inserts the instructions metering and memory grow instrumentation . Returns an [ ` InstrumentationOutput ` ] or an error if the input binary could not be instrumented .
pub fn instrument(
    wasm: &BinaryEncodedWasm,
    instruction_cost_table: &InstructionCostTable,
) -> Result<InstrumentationOutput, WasmInstrumentationError> {
    let module = parity_wasm::deserialize_buffer::<Module>(wasm.as_slice()).map_err(|err| {
        WasmInstrumentationError::ParityDeserializeError(into_parity_wasm_error(err))
    })?;
    let mut module = inject_helper_functions(module);
    module = export_table(module);
    module = export_memory(module);
    module = export_mutable_globals(module);
    let num_functions = module.functions_space() as u32;
    let num_globals = module.globals_space() as u32;
    let export_module_data = ExportModuleData {
        out_of_instructions_fn: 0, // because it's the first import
        instructions_counter_ix: num_globals,
        set_counter_fn: num_functions,
        get_counter_fn: num_functions + 1,
        decr_instruction_counter_fn: num_functions + 2,
        start_fn_ix: module.start_section(),
    };
    if export_module_data.start_fn_ix.is_some() {
        module.clear_start_section();
    }
    // inject instructions counter decrementation
    {
        if let Some(code_section) = module.code_section_mut() {
            for func_body in code_section.bodies_mut().iter_mut() {
                let code = func_body.code_mut();
                inject_metering(code, instruction_cost_table, &export_module_data);
            }
        }
    }
    {
        // Collect all the function types of the locally defined functions inside the
        // module.
        //
        // The main reason to create this vector of function types is because we can't
        // mix a mutable (to inject instructions) and immutable (to look up the function
        // type) reference to the `code_section`.
        let mut func_types = Vec::new();
        if let Some(code_section) = module.code_section() {
            let functions = module.function_section().unwrap().entries();
            let types = module.type_section().unwrap().types();
            for i in 0..code_section.bodies().len() {
                let Type::Function(t) = &types[functions[i].type_ref() as usize];
                func_types.push(t.clone());
            }
        }
        // Inject `update_available_memory` to functions with `memory.grow`
        // instructions.
        if !func_types.is_empty() {
            let func_bodies = module.code_section_mut().unwrap().bodies_mut();
            for (func_ix, func_type) in func_types.into_iter().enumerate() {
                inject_update_available_memory(&mut func_bodies[func_ix], &func_type);
            }
        }
    }
    let mut module = export_additional_symbols(module, &export_module_data)?;
    let exported_functions = module
        .export_section()
        .unwrap() // because we definitely push exports above
        .entries()
        .iter()
        .filter_map(|export| WasmMethod::try_from(export.field().to_string()).ok())
        .collect();
    let limits = match module.memory_section() {
        // if Wasm does not declare any memory section (mostly tests), use this default
        None => (0, None),
        Some(section) => {
            let entries = section.entries();
            if entries.len() != 1 {
                return Err(WasmInstrumentationError::IncorrectNumberMemorySections {
                    expected: 1,
                    got: entries.len(),
                });
            }
            let limits = entries[0].limits();
            (limits.initial(), limits.maximum())
        }
    };
    // pull out the data from the data section
    let data = Segments::from(get_data(module.sections_mut()));
    data.validate(NumWasmPages::from(limits.0 as usize))?;
    let result = parity_wasm::serialize(module).map_err(|err| {
        WasmInstrumentationError::ParitySerializeError(into_parity_wasm_error(err))
    })?;
    Ok(InstrumentationOutput {
        exported_functions,
        limits,
        data,
        binary: BinaryEncodedWasm::new(result),
    })
}
pub fn instrument ( wasm : & BinaryEncodedWasm , instruction_cost_table : & InstructionCostTable , ) -> Result < InstrumentationOutput , WasmInstrumentationError > { let module = parity_wasm :: deserialize_buffer :: < Module > ( wasm . as_slice ( ) ) . map_err ( | err | { WasmInstrumentationError :: ParityDeserializeError ( into_parity_wasm_error ( err ) ) } ) ? ; let mut module = inject_helper_functions ( module ) ; module = export_table ( module ) ; module = export_memory ( module ) ; module = export_mutable_globals ( module ) ; let num_functions = module . functions_space ( ) as u32 ; let num_globals = module . globals_space ( ) as u32 ; let export_module_data = ExportModuleData { out_of_instructions_fn : 0 , // because it's the first import instructions_counter_ix : num_globals , set_counter_fn : num_functions , get_counter_fn : num_functions + 1 , decr_instruction_counter_fn : num_functions + 2 , start_fn_ix : module . start_section ( ) , } ; if export_module_data . start_fn_ix . is_some ( ) { module . clear_start_section ( ) ; } // inject instructions counter decrementation { if let Some ( code_section ) = module . code_section_mut ( ) { for func_body in code_section . bodies_mut ( ) . iter_mut ( ) { let code = func_body . code_mut ( ) ; inject_metering ( code , instruction_cost_table , & export_module_data ) ; } } } { // Collect all the function types of the locally defined functions inside the // module. // // The main reason to create this vector of function types is because we can't // mix a mutable (to inject instructions) and immutable (to look up the function // type) reference to the `code_section`. let mut func_types = Vec :: new ( ) ; if let Some ( code_section ) = module . code_section ( ) { let functions = module . function_section ( ) . unwrap ( ) . entries ( ) ; let types = module . type_section ( ) . unwrap ( ) . types ( ) ; for i in 0 .. code_section . bodies ( ) . len ( ) { let Type :: Function ( t ) = & types [ functions [ i ] . type_ref ( ) as usize ] ; func_types . push ( t . clone ( ) ) ; } } // Inject `update_available_memory` to functions with `memory.grow` // instructions. if ! func_types . is_empty ( ) { let func_bodies = module . code_section_mut ( ) . unwrap ( ) . bodies_mut ( ) ; for ( func_ix , func_type ) in func_types . into_iter ( ) . enumerate ( ) { inject_update_available_memory ( & mut func_bodies [ func_ix ] , & func_type ) ; } } } let mut module = export_additional_symbols ( module , & export_module_data ) ? ; let exported_functions = module . export_section ( ) . unwrap ( ) // because we definitely push exports above . entries ( ) . iter ( ) . filter_map ( | export | WasmMethod :: try_from ( export . field ( ) . to_string ( ) ) . ok ( ) ) . collect ( ) ; let limits = match module . memory_section ( ) { // if Wasm does not declare any memory section (mostly tests), use this default None => ( 0 , None ) , Some ( section ) => { let entries = section . entries ( ) ; if entries . len ( ) != 1 { return Err ( WasmInstrumentationError :: IncorrectNumberMemorySections { expected : 1 , got : entries . len ( ) , } ) ; } let limits = entries [ 0 ] . limits ( ) ; ( limits . initial ( ) , limits . maximum ( ) ) } } ; // pull out the data from the data section let data = Segments :: from ( get_data ( module . sections_mut ( ) ) ) ; data . validate ( NumWasmPages :: from ( limits . 0 as usize ) ) ? ; let result = parity_wasm :: serialize ( module ) . map_err ( | err | { WasmInstrumentationError :: ParitySerializeError ( into_parity_wasm_error ( err ) ) } ) ? ; Ok ( InstrumentationOutput { exported_functions , limits , data , binary : BinaryEncodedWasm :: new ( result ) , } ) }
Takes a Wasm binary and inserts the instructions metering and memory grow
instrumentation.
Takes a Wasm binary and inserts the instructions metering and memory grow instrumentation .
wasm
&BinaryEncodedWasm
instruction_cost_table
&InstructionCostTable