// Scans through a function and adds instrumentation after each `memory.grow`
// instruction to make sure that there's enough available memory left to support
// the requested extra memory. If no `memory.grow` instructions are present then
// the function's code remains unchanged.
Scans through a function and adds instrumentation after each `memory.grow`
instruction to make sure that there's enough available memory left to support
the requested extra memory. If no `memory.grow` instructions are present then
the function's code remains unchanged.
Scans through a function and adds instrumentation after each ` memory . grow ` instruction to make sure that there ' s enough available memory left to support the requested extra memory . If no ` memory . grow ` instructions are present then the function ' s code remains unchanged .
fn inject_update_available_memory(func_body: &mut FuncBody, func_type: &FunctionType) {
    let mut injection_points: Vec<usize> = Vec::new();
    {
        let code = func_body.code();
        for (idx, instr) in code.elements().iter().enumerate() {
            // TODO(EXC-222): Once `table.grow` is supported we should extend the list of
            // injections here.
            if let Instruction::GrowMemory(_) = instr {
                injection_points.push(idx);
            }
        }
    }
    // If we found any injection points, we need to instrument the code.
    if !injection_points.is_empty() {
        // We inject a local to cache the argument to `memory.grow`.
        let n_locals: u32 = func_body.locals().iter().map(Local::count).sum();
        let memory_local_ix = func_type.params().len() as u32 + n_locals;
        func_body.locals_mut().push(Local::new(1, ValueType::I32));
        let code = func_body.code_mut();
        let orig_elems = code.elements_mut();
        let mut elems: Vec<Instruction> = Vec::new();
        let mut last_injection_position = 0;
        for point in injection_points {
            let update_available_memory_instr = orig_elems[point].clone();
            elems.extend_from_slice(&orig_elems[last_injection_position..point]);
            // At this point we have a memory.grow so the argument to it will be on top of
            // the stack, which we just assign to `memory_local_ix` with a local.tee
            // instruction.
            elems.extend_from_slice(&[
                Instruction::TeeLocal(memory_local_ix),
                update_available_memory_instr,
                Instruction::GetLocal(memory_local_ix),
                Instruction::Call(UPDATE_AVAILABLE_MEMORY_FN),
            ]);
            last_injection_position = point + 1;
        }
        elems.extend_from_slice(&orig_elems[last_injection_position..]);
        *orig_elems = elems;
    }
}
fn inject_update_available_memory ( func_body : & mut FuncBody , func_type : & FunctionType ) { let mut injection_points : Vec < usize > = Vec :: new ( ) ; { let code = func_body . code ( ) ; for ( idx , instr ) in code . elements ( ) . iter ( ) . enumerate ( ) { // TODO(EXC-222): Once `table.grow` is supported we should extend the list of // injections here. if let Instruction :: GrowMemory ( _ ) = instr { injection_points . push ( idx ) ; } } } // If we found any injection points, we need to instrument the code. if ! injection_points . is_empty ( ) { // We inject a local to cache the argument to `memory.grow`. let n_locals : u32 = func_body . locals ( ) . iter ( ) . map ( Local :: count ) . sum ( ) ; let memory_local_ix = func_type . params ( ) . len ( ) as u32 + n_locals ; func_body . locals_mut ( ) . push ( Local :: new ( 1 , ValueType :: I32 ) ) ; let code = func_body . code_mut ( ) ; let orig_elems = code . elements_mut ( ) ; let mut elems : Vec < Instruction > = Vec :: new ( ) ; let mut last_injection_position = 0 ; for point in injection_points { let update_available_memory_instr = orig_elems [ point ] . clone ( ) ; elems . extend_from_slice ( & orig_elems [ last_injection_position .. point ] ) ; // At this point we have a memory.grow so the argument to it will be on top of // the stack, which we just assign to `memory_local_ix` with a local.tee // instruction. elems . extend_from_slice ( & [ Instruction :: TeeLocal ( memory_local_ix ) , update_available_memory_instr , Instruction :: GetLocal ( memory_local_ix ) , Instruction :: Call ( UPDATE_AVAILABLE_MEMORY_FN ) , ] ) ; last_injection_position = point + 1 ; } elems . extend_from_slice ( & orig_elems [ last_injection_position .. ] ) ; * orig_elems = elems ; } }
Scans through a function and adds instrumentation after each `memory.grow`
instruction to make sure that there's enough available memory left to support
the requested extra memory.
Scans through a function and adds instrumentation after each ` memory . grow ` instruction to make sure that there ' s enough available memory left to support the requested extra memory .
func_body
&mut FuncBody
func_type
&FunctionType