diff --git a/utils/wasm-gen/src/config.rs b/utils/wasm-gen/src/config.rs index 60c96cd2d71..9cfdd5dbdc6 100644 --- a/utils/wasm-gen/src/config.rs +++ b/utils/wasm-gen/src/config.rs @@ -22,6 +22,7 @@ //! 1. From scratch by settings fields to corresponding values sometimes using //! related to these fields builders. For example, wasm module configs: //! ```rust +//! # use std::num::NonZeroUsize; //! use gear_wasm_gen::*; //! use arbitrary::{Arbitrary, Result, Unstructured}; //! @@ -38,8 +39,8 @@ //! InstructionKind::Control, //! ], //! max_instructions: 100_000, -//! min_funcs: 15, -//! max_funcs: 30, +//! min_funcs: NonZeroUsize::new(15).unwrap(), +//! max_funcs: NonZeroUsize::new(30).unwrap(), //! unreachable_enabled: true, //! }; //! let arbitrary = ArbitraryParams::arbitrary(u)?; diff --git a/utils/wasm-gen/src/config/module.rs b/utils/wasm-gen/src/config/module.rs index 4690382a667..709c35a2678 100644 --- a/utils/wasm-gen/src/config/module.rs +++ b/utils/wasm-gen/src/config/module.rs @@ -23,6 +23,8 @@ //! can be arbitrary, but some must be constantly set. That's implemented with [`ArbitraryParams`] //! and [`ConstantParams`]. +use std::num::NonZeroUsize; + use arbitrary::{Arbitrary, Result, Unstructured}; pub use wasm_smith::InstructionKind; use wasm_smith::{InstructionKind::*, InstructionKinds, SwarmConfig}; @@ -88,6 +90,9 @@ impl From<(SelectableParams, ArbitraryParams)> for WasmModuleConfig { unreachable_enabled, } = selectable_params; + let min_funcs = min_funcs.get(); + let max_funcs = max_funcs.get(); + let ArbitraryParams { available_imports, canonicalize_nans, @@ -352,10 +357,10 @@ pub struct SelectableParams { pub max_instructions: usize, /// Minimum amount of functions `wasm-gen` will insert /// into generated wasm. - pub min_funcs: usize, + pub min_funcs: NonZeroUsize, /// Maximum amount of functions `wasm-gen` will insert /// into generated wasm. - pub max_funcs: usize, + pub max_funcs: NonZeroUsize, /// Flag signalizing whether `unreachable` instruction /// must be used or not. pub unreachable_enabled: bool, @@ -369,8 +374,8 @@ impl Default for SelectableParams { Numeric, Reference, Parametric, Variable, Table, Memory, Control, ], max_instructions: 500, - min_funcs: 3, - max_funcs: 5, + min_funcs: NonZeroUsize::new(3).expect("from non zero value; qed."), + max_funcs: NonZeroUsize::new(5).expect("from non zero value; qed."), unreachable_enabled: true, } } diff --git a/utils/wasm-gen/src/generator.rs b/utils/wasm-gen/src/generator.rs index 5d9e662d68a..f188c0da787 100644 --- a/utils/wasm-gen/src/generator.rs +++ b/utils/wasm-gen/src/generator.rs @@ -56,7 +56,7 @@ use crate::{utils, GearWasmGeneratorConfig, WasmModule}; use arbitrary::{Result, Unstructured}; use gear_wasm_instrument::parity_wasm::elements::Module; -use std::collections::HashSet; +use std::{collections::HashSet, ops::RangeInclusive}; mod entry_points; mod memory; @@ -216,15 +216,17 @@ struct CallIndexes { /// /// These are indexes of functions which aren't generated from /// `wasm-smith` but from the current crate generators. All gear - /// entry points ([`EntryPointsGenerator`]) and custom reservation send - /// function (generated in [`SysCallsImportsGenerator`]) are considered - /// to be "custom" functions. + /// entry points ([`EntryPointsGenerator`]) and custom precuse syscalls + /// (generated in [`SysCallsImportsGenerator`]) are considered to be + /// "custom" functions. /// /// Separating "pre-defined" functions from newly generated ones is important /// when syscalls invocator inserts calls of generated syscalls. For example, /// calls must not be inserted in the custom function, which perofrms `gr_reservation_send`, /// not to pollute it's internal instructions structure which is defined such that /// semantically correct `gr_reservation_send` call is performed. + /// + /// Same immutability is actual for gear exports to keep them as simple as possible. custom_funcs: HashSet, } @@ -250,8 +252,24 @@ impl CallIndexes { self.inner.get(handle_idx).copied() } - fn is_custom_func(&self, idx: usize) -> bool { - self.custom_funcs.contains(&idx) + fn predefined_funcs_indexes(&self) -> RangeInclusive { + let last = if let Some(first_custom_func_idx) = self.custom_funcs.iter().min() { + // Take last predefined func idx + // + // Subtraction is safe, because by config it's guaranteed + // that there's at least one internal function from `wasm-smith`. + // So, if there's only one predefined function, then first idx + // of a custom function is 1. + first_custom_func_idx - 1 + } else { + self.inner + .iter() + .filter_map(FunctionIndex::internal_func_idx) + .max() + .expect("at least 1 func is generated by config definition") as usize + }; + + 0..=last } fn len(&self) -> usize { @@ -282,6 +300,15 @@ enum FunctionIndex { Func(u32), } +impl FunctionIndex { + fn internal_func_idx(&self) -> Option { + match self { + FunctionIndex::Func(idx) => Some(*idx), + _ => None, + } + } +} + /// Frozen gear wasm generator. /// /// Instantce of this generator signals, that some gear wasm generator diff --git a/utils/wasm-gen/src/generator/syscalls/imports.rs b/utils/wasm-gen/src/generator/syscalls/imports.rs index 36a2fe1faf5..d941e617865 100644 --- a/utils/wasm-gen/src/generator/syscalls/imports.rs +++ b/utils/wasm-gen/src/generator/syscalls/imports.rs @@ -292,11 +292,11 @@ impl<'a, 'b> SysCallsImportsGenerator<'a, 'b> { syscall: SysCallName, is_loose: bool, ) -> Result { - use InvocableSysCall::*; - - let invocable_syscall = is_loose - .then_some(Loose(syscall)) - .unwrap_or(Precise(syscall)); + let invocable_syscall = if is_loose { + InvocableSysCall::Loose(syscall) + } else { + InvocableSysCall::Precise(syscall) + }; let syscall_amount_range = self.config.injection_amounts(invocable_syscall); self.unstructured.int_in_range(syscall_amount_range) diff --git a/utils/wasm-gen/src/generator/syscalls/invocator.rs b/utils/wasm-gen/src/generator/syscalls/invocator.rs index 18cd7bdf43b..a71cfec2553 100644 --- a/utils/wasm-gen/src/generator/syscalls/invocator.rs +++ b/utils/wasm-gen/src/generator/syscalls/invocator.rs @@ -201,24 +201,7 @@ impl<'a, 'b> SysCallsInvocator<'a, 'b> { self.unstructured.len() ); - let code_funcs = self.module.count_code_funcs(); - let insert_into_funcs: Vec<_> = (0..code_funcs) - .filter(|idx| !self.call_indexes.is_custom_func(*idx)) - .collect(); - - let syscalls_to_insert = - self.syscalls_imports - .clone() - .into_iter() - .flat_map(|(syscall, (amount, _))| { - iter::repeat(syscall) - .take(amount as usize) - .collect::>() - }); - - let insertion_mapping = - self.build_syscalls_insertion_mapping(syscalls_to_insert, &insert_into_funcs)?; - + let insertion_mapping = self.build_syscalls_insertion_mapping()?; for (insert_into_fn, syscalls) in insertion_mapping { self.insert_syscalls_into_fn(insert_into_fn, syscalls)?; } @@ -234,24 +217,28 @@ impl<'a, 'b> SysCallsInvocator<'a, 'b> { /// Distributes provided syscalls among provided function ids. /// /// Returns mapping `func_id` <-> `syscalls which should be inserted into func_id`. - fn build_syscalls_insertion_mapping( + fn build_syscalls_insertion_mapping( &mut self, - syscalls: I, - insert_into_funcs: &[usize], - ) -> Result>> - where - I: Iterator, - { + ) -> Result>> { + let insert_into_funcs = self.call_indexes.predefined_funcs_indexes(); + let syscalls = self + .syscalls_imports + .clone() + .into_iter() + .map(|(syscall, (amount, _))| (syscall, amount)); + let mut insertion_mapping: BTreeMap<_, Vec<_>> = BTreeMap::new(); - for syscall in syscalls { - let insert_into = *self.unstructured.choose(insert_into_funcs)?; + for (syscall, amount) in syscalls { + for _ in 0..amount { + let insert_into = self.unstructured.int_in_range(insert_into_funcs.clone())?; - match insertion_mapping.entry(insert_into) { - Entry::Occupied(mut entry) => { - entry.get_mut().push(syscall); - } - Entry::Vacant(entry) => { - entry.insert(vec![syscall]); + match insertion_mapping.entry(insert_into) { + Entry::Occupied(mut entry) => { + entry.get_mut().push(syscall); + } + Entry::Vacant(entry) => { + entry.insert(vec![syscall]); + } } } } diff --git a/utils/wasm-gen/src/lib.rs b/utils/wasm-gen/src/lib.rs index 8f51d0f8f3b..3252549bf62 100644 --- a/utils/wasm-gen/src/lib.rs +++ b/utils/wasm-gen/src/lib.rs @@ -75,7 +75,5 @@ pub fn generate_gear_program_module( } // TODO -// 2. clean-up in SysCallsImportsGenerator -// 3. clean-up after 3242, 3196 -// 4. Check all other code -// 5. Check logs after merging @mertwole's changes. Make it more clear. +// 3. clean-up invocator +// 4. Check logs. diff --git a/utils/wasm-gen/src/tests.rs b/utils/wasm-gen/src/tests.rs index 0835dc4473d..137b3ff6e63 100644 --- a/utils/wasm-gen/src/tests.rs +++ b/utils/wasm-gen/src/tests.rs @@ -43,7 +43,7 @@ use gear_wasm_instrument::{ }; use proptest::prelude::*; use rand::{rngs::SmallRng, RngCore, SeedableRng}; -use std::mem; +use std::{mem, num::NonZeroUsize}; const UNSTRUCTURED_SIZE: usize = 1_000_000; @@ -347,8 +347,8 @@ fn execute_wasm_with_custom_configs( call_indirect_enabled: false, allowed_instructions: vec![], max_instructions: 0, - min_funcs: 1, - max_funcs: 1, + min_funcs: NonZeroUsize::new(1).unwrap(), + max_funcs: NonZeroUsize::new(1).unwrap(), unreachable_enabled: true, }, );