fn snapshot_memories(
    ctx: &mut impl AsContextMut,
    instance: &wasmtime::Instance,
) -> (Vec<u64>, Vec<DataSegment>) {
    log::debug!("Snapshotting memories");

    // Find and record non-zero regions of memory (in parallel).
    let mut memory_mins = vec![];
    let mut data_segments = vec![];
    let mut memory_index = 0;
    loop {
        let name = format!("__wizer_memory_{}", memory_index);
        let memory = match instance.get_memory(&mut *ctx, &name) {
            None => break,
            Some(memory) => memory,
        };
        memory_mins.push(memory.size(&*ctx));

        let num_wasm_pages = memory.size(&*ctx);

        let memory_data = memory.data(&*ctx);

        // Consider each Wasm page in parallel. Create data segments for each
        // region of non-zero memory.
        data_segments.par_extend((0..num_wasm_pages).into_par_iter().flat_map(|i| {
            let page_end = ((i + 1) * WASM_PAGE_SIZE) as usize;
            let mut start = (i * WASM_PAGE_SIZE) as usize;
            let mut segments = vec![];
            while start < page_end {
                let nonzero = match memory_data[start..page_end]
                    .iter()
                    .position(|byte| *byte != 0)
                {
                    None => break,
                    Some(i) => i,
                };
                start += nonzero;
                let end = memory_data[start..page_end]
                    .iter()
                    .position(|byte| *byte == 0)
                    .map_or(page_end, |zero| start + zero);
                segments.push(DataSegment {
                    memory_index,
                    memory,
                    offset: u32::try_from(start).unwrap(),
                    len: u32::try_from(end - start).unwrap(),
                });
                start = end;
            }
            segments
        }));

        memory_index += 1;
    }

    if data_segments.is_empty() {
        return (memory_mins, data_segments);
    }

    // Sort data segments to enforce determinism in the face of the
    // parallelism above.
    data_segments.sort_by_key(|s| (s.memory_index, s.offset));

    // Merge any contiguous segments (caused by spanning a Wasm page boundary,
    // and therefore created in separate logical threads above) or pages that
    // are within four bytes of each other. Four because this is the minimum
    // overhead of defining a new active data segment: one for the memory index
    // LEB, two for the memory offset init expression (one for the `i32.const`
    // opcode and another for the constant immediate LEB), and finally one for
    // the data length LEB).
    const MIN_ACTIVE_SEGMENT_OVERHEAD: u32 = 4;
    let mut merged_data_segments = Vec::with_capacity(data_segments.len());
    merged_data_segments.push(data_segments[0]);
    for b in &data_segments[1..] {
        let a = merged_data_segments.last_mut().unwrap();

        // Only merge segments for the same memory.
        if a.memory_index != b.memory_index {
            merged_data_segments.push(*b);
            continue;
        }

        // Only merge segments if they are contiguous or if it is definitely
        // more size efficient than leaving them apart.
        let gap = a.gap(b);
        if gap > MIN_ACTIVE_SEGMENT_OVERHEAD {
            merged_data_segments.push(*b);
            continue;
        }

        // Okay, merge them together into `a` (so that the next iteration can
        // merge it with its predecessor) and then omit `b`!
        let merged = a.merge(b);
        *a = merged;
    }

    remove_excess_segments(&mut merged_data_segments);

    (memory_mins, merged_data_segments)
}
/// Find the initialized minimum page size of each memory, as well as all
/// regions of non-zero memory.
Find the initialized minimum page size of each memory, as well as all
regions of non-zero memory.
Find the initialized minimum page size of each memory as well as all regions of non - zero memory .
fn snapshot_memories(
    ctx: &mut impl AsContextMut,
    instance: &wasmtime::Instance,
) -> (Vec<u64>, Vec<DataSegment>) {
    log::debug!("Snapshotting memories");
    // Find and record non-zero regions of memory (in parallel).
    let mut memory_mins = vec![];
    let mut data_segments = vec![];
    let mut memory_index = 0;
    loop {
        let name = format!("__wizer_memory_{}", memory_index);
        let memory = match instance.get_memory(&mut *ctx, &name) {
            None => break,
            Some(memory) => memory,
        };
        memory_mins.push(memory.size(&*ctx));
        let num_wasm_pages = memory.size(&*ctx);
        let memory_data = memory.data(&*ctx);
        // Consider each Wasm page in parallel. Create data segments for each
        // region of non-zero memory.
        data_segments.par_extend((0..num_wasm_pages).into_par_iter().flat_map(|i| {
            let page_end = ((i + 1) * WASM_PAGE_SIZE) as usize;
            let mut start = (i * WASM_PAGE_SIZE) as usize;
            let mut segments = vec![];
            while start < page_end {
                let nonzero = match memory_data[start..page_end]
                    .iter()
                    .position(|byte| *byte != 0)
                {
                    None => break,
                    Some(i) => i,
                };
                start += nonzero;
                let end = memory_data[start..page_end]
                    .iter()
                    .position(|byte| *byte == 0)
                    .map_or(page_end, |zero| start + zero);
                segments.push(DataSegment {
                    memory_index,
                    memory,
                    offset: u32::try_from(start).unwrap(),
                    len: u32::try_from(end - start).unwrap(),
                });
                start = end;
            }
            segments
        }));
        memory_index += 1;
    }
    if data_segments.is_empty() {
        return (memory_mins, data_segments);
    }
    // Sort data segments to enforce determinism in the face of the
    // parallelism above.
    data_segments.sort_by_key(|s| (s.memory_index, s.offset));
    // Merge any contiguous segments (caused by spanning a Wasm page boundary,
    // and therefore created in separate logical threads above) or pages that
    // are within four bytes of each other. Four because this is the minimum
    // overhead of defining a new active data segment: one for the memory index
    // LEB, two for the memory offset init expression (one for the `i32.const`
    // opcode and another for the constant immediate LEB), and finally one for
    // the data length LEB).
    const MIN_ACTIVE_SEGMENT_OVERHEAD: u32 = 4;
    let mut merged_data_segments = Vec::with_capacity(data_segments.len());
    merged_data_segments.push(data_segments[0]);
    for b in &data_segments[1..] {
        let a = merged_data_segments.last_mut().unwrap();
        // Only merge segments for the same memory.
        if a.memory_index != b.memory_index {
            merged_data_segments.push(*b);
            continue;
        }
        // Only merge segments if they are contiguous or if it is definitely
        // more size efficient than leaving them apart.
        let gap = a.gap(b);
        if gap > MIN_ACTIVE_SEGMENT_OVERHEAD {
            merged_data_segments.push(*b);
            continue;
        }
        // Okay, merge them together into `a` (so that the next iteration can
        // merge it with its predecessor) and then omit `b`!
        let merged = a.merge(b);
        *a = merged;
    }
    remove_excess_segments(&mut merged_data_segments);
    (memory_mins, merged_data_segments)
}
fn snapshot_memories ( ctx : & mut impl AsContextMut , instance : & wasmtime :: Instance , ) -> ( Vec < u64 > , Vec < DataSegment > ) { log :: debug ! ( " " ) ; // Find and record non-zero regions of memory (in parallel). let mut memory_mins = vec ! [ ] ; let mut data_segments = vec ! [ ] ; let mut memory_index = 0 ; loop { let name = format ! ( " " memory_index ) ; let memory = match instance . get_memory ( & mut * ctx , & name ) { None => break , Some ( memory ) => memory , } ; memory_mins . push ( memory . size ( & * ctx ) ) ; let num_wasm_pages = memory . size ( & * ctx ) ; let memory_data = memory . data ( & * ctx ) ; // Consider each Wasm page in parallel. Create data segments for each // region of non-zero memory. data_segments . par_extend ( ( 0 .. num_wasm_pages ) . into_par_iter ( ) . flat_map ( | i | { let page_end = ( ( i + 1 ) * WASM_PAGE_SIZE ) as usize ; let mut start = ( i * WASM_PAGE_SIZE ) as usize ; let mut segments = vec ! [ ] ; while start < page_end { let nonzero = match memory_data [ start .. page_end ] . iter ( ) . position ( | byte | * byte != 0 ) { None => break , Some ( i ) => i , } ; start += nonzero ; let end = memory_data [ start .. page_end ] . iter ( ) . position ( | byte | * byte == 0 ) . map_or ( page_end , | zero | start + zero ) ; segments . push ( DataSegment { memory_index , memory , offset : u32 :: try_from ( start ) . unwrap ( ) , len : u32 :: try_from ( end - start ) . unwrap ( ) , } ) ; start = end ; } segments } ) ) ; memory_index += 1 ; } if data_segments . is_empty ( ) { return ( memory_mins , data_segments ) ; } // Sort data segments to enforce determinism in the face of the // parallelism above. data_segments . sort_by_key ( | s | ( s . memory_index , s . offset ) ) ; // Merge any contiguous segments (caused by spanning a Wasm page boundary, // and therefore created in separate logical threads above) or pages that // are within four bytes of each other. Four because this is the minimum // overhead of defining a new active data segment: one for the memory index // LEB, two for the memory offset init expression (one for the `i32.const` // opcode and another for the constant immediate LEB), and finally one for // the data length LEB). const MIN_ACTIVE_SEGMENT_OVERHEAD : u32 = 4 ; let mut merged_data_segments = Vec :: with_capacity ( data_segments . len ( ) ) ; merged_data_segments . push ( data_segments [ 0 ] ) ; for b in & data_segments [ 1 .. ] { let a = merged_data_segments . last_mut ( ) . unwrap ( ) ; // Only merge segments for the same memory. if a . memory_index != b . memory_index { merged_data_segments . push ( * b ) ; continue ; } // Only merge segments if they are contiguous or if it is definitely // more size efficient than leaving them apart. let gap = a . gap ( b ) ; if gap > MIN_ACTIVE_SEGMENT_OVERHEAD { merged_data_segments . push ( * b ) ; continue ; } // Okay, merge them together into `a` (so that the next iteration can // merge it with its predecessor) and then omit `b`! let merged = a . merge ( b ) ; * a = merged ; } remove_excess_segments ( & mut merged_data_segments ) ; ( memory_mins , merged_data_segments ) }
Find the initialized minimum page size of each memory, as well as all
regions of non-zero memory.
Find the initialized minimum page size of each memory as well as all regions of non - zero memory .
ctx
&mut impl AsContextMut
instance
&wasmtime::Instance
ctx
&mut impl AsContextMut
instance
&wasmtime::Instance