From 50ac94bca3cb2eafc48664f5cef84fc38eb22fa1 Mon Sep 17 00:00:00 2001 From: Vineeth Kashyap Date: Mon, 10 Feb 2025 20:27:12 -0500 Subject: [PATCH] [cleanup] Remove module generation --- Cargo.lock | 13 - Cargo.toml | 1 - .../module-generation/Cargo.toml | 24 -- .../module-generation/src/generator.rs | 354 ------------------ .../module-generation/src/lib.rs | 14 - .../module-generation/src/options.rs | 61 --- .../module-generation/src/padding.rs | 75 ---- .../module-generation/src/utils.rs | 15 - 8 files changed, 557 deletions(-) delete mode 100644 third_party/move/testing-infra/module-generation/Cargo.toml delete mode 100644 third_party/move/testing-infra/module-generation/src/generator.rs delete mode 100644 third_party/move/testing-infra/module-generation/src/lib.rs delete mode 100644 third_party/move/testing-infra/module-generation/src/options.rs delete mode 100644 third_party/move/testing-infra/module-generation/src/padding.rs delete mode 100644 third_party/move/testing-infra/module-generation/src/utils.rs diff --git a/Cargo.lock b/Cargo.lock index 6953fc32dbc6e..8beb33cdb7423 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -11018,19 +11018,6 @@ dependencies = [ "syn 1.0.109", ] -[[package]] -name = "module-generation" -version = "0.1.0" -dependencies = [ - "move-binary-format", - "move-bytecode-verifier", - "move-core-types", - "move-ir-to-bytecode", - "move-ir-types", - "move-symbol-pool", - "rand 0.8.5", -] - [[package]] name = "module-publish" version = "0.1.0" diff --git a/Cargo.toml b/Cargo.toml index 2465dfb3adac3..03ba3d9c91bd5 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -242,7 +242,6 @@ members = [ "third_party/move/move-vm/test-utils", "third_party/move/move-vm/transactional-tests", "third_party/move/move-vm/types", - "third_party/move/testing-infra/module-generation", "third_party/move/testing-infra/transactional-test-runner", "third_party/move/tools/move-bytecode-utils", "third_party/move/tools/move-bytecode-viewer", diff --git a/third_party/move/testing-infra/module-generation/Cargo.toml b/third_party/move/testing-infra/module-generation/Cargo.toml deleted file mode 100644 index 3179dab7209c3..0000000000000 --- a/third_party/move/testing-infra/module-generation/Cargo.toml +++ /dev/null @@ -1,24 +0,0 @@ -[package] -name = "module-generation" -version = "0.1.0" -authors = ["Diem Association "] -description = "Diem binary module generation" -repository = "https://github.com/diem/diem" -homepage = "https://diem.com" -license = "Apache-2.0" -publish = false -edition = "2021" - -[dependencies] -move-binary-format = { workspace = true } -move-bytecode-verifier = { workspace = true } -move-core-types = { workspace = true } -move-ir-to-bytecode = { workspace = true } -move-ir-types = { workspace = true } -move-symbol-pool = { workspace = true } -# Cannot use workspace version as aptos-core currently cannot be upgraded -# to newer rand. See https://github.com/aptos-labs/aptos-core/issues/13031 -rand = { version = "0.8.5" } - -[features] -default = [] diff --git a/third_party/move/testing-infra/module-generation/src/generator.rs b/third_party/move/testing-infra/module-generation/src/generator.rs deleted file mode 100644 index d12c1dcefe17d..0000000000000 --- a/third_party/move/testing-infra/module-generation/src/generator.rs +++ /dev/null @@ -1,354 +0,0 @@ -// Copyright (c) The Diem Core Contributors -// Copyright (c) The Move Contributors -// SPDX-License-Identifier: Apache-2.0 - -use crate::{options::ModuleGeneratorOptions, padding::Pad, utils::random_string}; -use move_binary_format::file_format::CompiledModule; -use move_bytecode_verifier::verify_module; -use move_core_types::account_address::AccountAddress; -use move_ir_to_bytecode::compiler::compile_module; -use move_ir_types::{ast::*, location::*}; -use move_symbol_pool::Symbol; -use rand::{rngs::StdRng, Rng}; -use std::{ - collections::{BTreeSet, VecDeque}, - iter::FromIterator, -}; - -type Set = BTreeSet; - -macro_rules! init { - ($len:expr, $e:expr) => { - (0..$len).map(|_| $e).collect() - }; -} - -pub fn generate_module(rng: &mut StdRng, options: ModuleGeneratorOptions) -> CompiledModule { - generate_modules(rng, 1, options).0 -} - -/// Generate a `number - 1` modules. Then generate a root module that imports all of these modules. -pub fn generate_modules( - rng: &mut StdRng, - number: usize, - options: ModuleGeneratorOptions, -) -> (CompiledModule, Vec) { - assert!(number > 0, "We cannot generate zero modules"); - - let table_size = options.min_table_size; - let (callee_names, callees): (Set, Vec) = (0..(number - 1)) - .map(|_| { - let module = ModuleGenerator::create(rng, options.clone(), &Set::new()); - let module_name = module.identifier.name.0; - (module_name, module) - }) - .unzip(); - - let root_module = ModuleGenerator::create(rng, options.clone(), &callee_names); - let empty_deps: Vec = Vec::new(); - let compiled_callees = callees - .into_iter() - .map(|module| { - let mut module = compile_module(module, &empty_deps).unwrap().0; - Pad::pad(table_size, &mut module, options.clone()); - module - }) - .collect(); - - // TODO: for friend visibility, maybe we could generate a module that friend all other modules... - - let mut compiled_root = compile_module(root_module, &compiled_callees).unwrap().0; - Pad::pad(table_size, &mut compiled_root, options); - (compiled_root, compiled_callees) -} - -pub fn generate_verified_modules( - rng: &mut StdRng, - number: usize, - options: ModuleGeneratorOptions, -) -> (CompiledModule, Vec) { - let (root, callees) = generate_modules(rng, number, options); - for callee in &callees { - verify_module(callee).unwrap() - } - verify_module(&root).unwrap(); - (root, callees) -} - -/////////////////////////////////////////////////////////////////////////// -// Generation of IR-level modules -/////////////////////////////////////////////////////////////////////////// - -pub struct ModuleGenerator<'a> { - options: ModuleGeneratorOptions, - current_module: ModuleDefinition, - gen: &'a mut StdRng, -} - -impl<'a> ModuleGenerator<'a> { - fn index(&mut self, bound: usize) -> usize { - self.gen.gen_range(0..bound) - } - - fn identifier(&mut self) -> String { - let len = self.gen.gen_range(10..self.options.max_string_size); - random_string(self.gen, len) - } - - fn base_type(&mut self, ty_param_context: &[&TypeVar]) -> Type { - // TODO: Don't generate nested resources for now. Once we allow functions to take resources - // (and have type parameters of kind Resource or All) then we should revisit this here. - let structs: Vec<_> = self - .current_module - .structs - .iter() - .filter(|s| !s.value.abilities.contains(&Ability::Key)) - .cloned() - .collect(); - - let mut end = 5; - if !ty_param_context.is_empty() { - end += 1; - }; - if !structs.is_empty() { - end += 1; - }; - - match self.index(end) { - 0 => Type::Address, - 1 => Type::U8, - 2 => Type::U64, - 3 => Type::U128, - 4 => Type::Bool, - 5 if !structs.is_empty() => { - let index = self.index(structs.len()); - let struct_def = structs[index].value.clone(); - let ty_instants = { - let num_typ_params = struct_def.type_formals.len(); - // NB: Relying on randomness for termination here - init!(num_typ_params, self.base_type(ty_param_context)) - }; - let struct_ident = { - let struct_name = struct_def.name; - let module_name = ModuleName::module_self(); - QualifiedStructIdent::new(module_name, struct_name) - }; - Type::Struct(struct_ident, ty_instants) - }, - 6 => Type::U16, - 7 => Type::U32, - 8 => Type::U256, - _ => { - let index = self.index(ty_param_context.len()); - let ty_var = ty_param_context[index].value.clone(); - Type::TypeParameter(ty_var) - }, - } - } - - fn typ(&mut self, ty_param_context: &[(TypeVar, BTreeSet)]) -> Type { - let typ = self.base_type( - &ty_param_context - .iter() - .map(|(tv, _)| tv) - .collect::>(), - ); - // TODO: Always change the base type to a reference if it's resource type. Then we can - // allow functions to take resources. - // if typ.is_nominal_resource { .... } - if self.options.references_allowed && self.gen.gen_bool(0.25) { - let is_mutable = self.gen.gen_bool(0.25); - Type::Reference(is_mutable, Box::new(typ)) - } else { - typ - } - } - - fn fun_type_parameters(&mut self) -> Vec<(TypeVar, BTreeSet)> { - // Don't generate type parameters if we're generating simple types only - if self.options.simple_types_only { - vec![] - } else { - let num_ty_params = self.index(self.options.max_ty_params); - let abilities = BTreeSet::from_iter(vec![Ability::Copy, Ability::Drop]); - init!(num_ty_params, { - let name = Spanned::unsafe_no_loc(TypeVar_(self.identifier().into())); - (name, abilities.clone()) - }) - } - } - - fn struct_type_parameters(&mut self) -> Vec { - // Don't generate type parameters if we're generating simple types only - if self.options.simple_types_only { - vec![] - } else { - let is_phantom = self.index(1) != 0; - let num_ty_params = self.index(self.options.max_ty_params); - let abilities = BTreeSet::from_iter(vec![Ability::Copy, Ability::Drop]); - init!(num_ty_params, { - let name = Spanned::unsafe_no_loc(TypeVar_(self.identifier().into())); - (is_phantom, name, abilities.clone()) - }) - } - } - - // All functions will have unit return type, and an empty body with the exception of a return. - // We'll scoop this out and replace it later on in the compiled module that we generate. - fn function_signature(&mut self) -> FunctionSignature { - let ty_params = self.fun_type_parameters(); - let number_of_args = self.index(self.options.max_function_call_size); - let mut formals: Vec<(Var, Type)> = init!(number_of_args, { - let param_name = Spanned::unsafe_no_loc(Var_(self.identifier().into())); - let ty = self.typ(&ty_params); - (param_name, ty) - }); - - if self.options.args_for_ty_params { - let mut ty_formals = ty_params - .iter() - .map(|(ty_var_, _)| { - let param_name = Spanned::unsafe_no_loc(Var_(self.identifier().into())); - let ty = Type::TypeParameter(ty_var_.value.clone()); - (param_name, ty) - }) - .collect(); - - formals.append(&mut ty_formals); - } - - FunctionSignature::new(formals, vec![], ty_params) - } - - fn struct_fields(&mut self, ty_params: &[StructTypeParameter]) -> StructDefinitionFields { - let num_fields = self - .gen - .gen_range(self.options.min_fields..self.options.max_fields); - let fields: Fields = init!(num_fields, { - ( - Spanned::unsafe_no_loc(Field_(self.identifier().into())), - self.base_type(&ty_params.iter().map(|(_, tv, _)| tv).collect::>()), - ) - }); - - StructDefinitionFields::Move { fields } - } - - fn function_def(&mut self) { - let signature = self.function_signature(); - let num_locals = self.index(self.options.max_locals); - let locals = init!(num_locals, { - ( - Spanned::unsafe_no_loc(Var_(self.identifier().into())), - self.typ(&signature.type_formals), - ) - }); - let fun = Function_ { - visibility: FunctionVisibility::Public, - is_entry: false, - acquires: Vec::new(), - specifications: Vec::new(), - signature, - body: FunctionBody::Move { - locals, - code: vec![Spanned::unsafe_no_loc(Block_ { - label: Spanned::unsafe_no_loc(BlockLabel_(Symbol::from("b0"))), - statements: VecDeque::from(vec![Spanned::unsafe_no_loc( - Statement_::return_empty(), - )]), - })], - }, - }; - let fun_name = FunctionName(self.identifier().into()); - self.current_module - .functions - .push((fun_name, Spanned::unsafe_no_loc(fun))); - } - - fn struct_def(&mut self, abilities: BTreeSet) { - let name = StructName(self.identifier().into()); - let type_parameters = self.struct_type_parameters(); - let fields = self.struct_fields(&type_parameters); - let strct = StructDefinition_ { - abilities, - name, - type_formals: type_parameters, - fields, - invariants: vec![], - }; - self.current_module - .structs - .push(Spanned::unsafe_no_loc(strct)) - } - - fn imports(callees: &Set) -> Vec { - callees - .iter() - .map(|ident| { - let module_name = ModuleName(*ident); - let qualified_mod_ident = ModuleIdent::new(module_name, AccountAddress::ZERO); - ImportDefinition::new(qualified_mod_ident, None) - }) - .collect() - } - - fn gen(mut self) -> ModuleDefinition { - let num_structs = self.index(self.options.max_structs) + 1; - let num_functions = self.index(self.options.max_functions) + 1; - // TODO: the order of generation here means that functions can't take resources as arguments. - // We will need to generate (valid) bytecode bodies for these functions before we allow - // resources. - { - // We generate a function at this point as an "entry point" into the module: since we - // haven't generated any structs yet, this function will only take base types as its input - // parameters. Likewise we can't take references since there isn't any value stack. - let simple_types = self.options.simple_types_only; - self.options.simple_types_only = true; - self.function_def(); - self.options.simple_types_only = simple_types; - } - // TODO generate abilities - let abilities = BTreeSet::from_iter(vec![Ability::Copy, Ability::Drop, Ability::Store]); - (0..num_structs).for_each(|_| self.struct_def(abilities.clone())); - // TODO/XXX: We can allow references to resources here - (0..num_functions).for_each(|_| self.function_def()); - if self.options.add_resources { - // TODO generate abilities - let abilities = BTreeSet::from_iter(vec![Ability::Key, Ability::Store]); - (0..num_structs).for_each(|_| self.struct_def(abilities.clone())); - } - self.current_module - } - - pub fn create( - gen: &'a mut StdRng, - options: ModuleGeneratorOptions, - callable_modules: &Set, - ) -> ModuleDefinition { - // TODO: Generation of struct and function handles to the `callable_modules` - let module_name = { - let len = gen.gen_range(10..options.max_string_size); - random_string(gen, len) - }; - let current_module = ModuleDefinition { - loc: Spanned::unsafe_no_loc(0).loc, - identifier: ModuleIdent { - name: ModuleName(module_name.into()), - address: AccountAddress::random(), - }, - friends: Vec::new(), - imports: Self::imports(callable_modules), - explicit_dependency_declarations: Vec::new(), - structs: Vec::new(), - functions: Vec::new(), - constants: Vec::new(), - synthetics: Vec::new(), - }; - Self { - options, - current_module, - gen, - } - .gen() - } -} diff --git a/third_party/move/testing-infra/module-generation/src/lib.rs b/third_party/move/testing-infra/module-generation/src/lib.rs deleted file mode 100644 index e6783cf00fa89..0000000000000 --- a/third_party/move/testing-infra/module-generation/src/lib.rs +++ /dev/null @@ -1,14 +0,0 @@ -// Copyright (c) The Diem Core Contributors -// Copyright (c) The Move Contributors -// SPDX-License-Identifier: Apache-2.0 - -mod generator; -mod options; -mod padding; -mod utils; - -pub use generator::{ - generate_module, generate_modules, generate_verified_modules, ModuleGenerator, -}; -pub use options::ModuleGeneratorOptions; -pub use padding::Pad; diff --git a/third_party/move/testing-infra/module-generation/src/options.rs b/third_party/move/testing-infra/module-generation/src/options.rs deleted file mode 100644 index eaedc6061b991..0000000000000 --- a/third_party/move/testing-infra/module-generation/src/options.rs +++ /dev/null @@ -1,61 +0,0 @@ -// Copyright (c) The Diem Core Contributors -// Copyright (c) The Move Contributors -// SPDX-License-Identifier: Apache-2.0 - -//! Defines constants and options that are used for module generation - -#[derive(Clone, Debug)] -pub struct ModuleGeneratorOptions { - /// The maximum number of locals that can be defined within a generated function definition. - pub max_locals: usize, - /// The maximum number of fields that will be generated for any struct. - pub max_fields: usize, - pub min_fields: usize, - /// The maximum number of structs that can be generated for a module - pub max_structs: usize, - /// The maximum number of functions that can be generated for a module. - pub max_functions: usize, - /// The maximum number of type parameters functions and structs. - pub max_ty_params: usize, - /// The maximum size that generated byte arrays can be. - pub byte_array_max_size: usize, - /// The maximum size that a generated string can be. - pub max_string_size: usize, - /// The maximum number of arguments to generated function definitions. - pub max_function_call_size: usize, - /// The maximum number of return types of generated function definitions. - pub max_ret_types_size: usize, - /// Whether or not generate modules should only contain simple (non-reference, or nested - /// struct) types. - pub simple_types_only: bool, - /// Whether references are allowed to be generated for e.g. function parameters, locals. - pub references_allowed: bool, - /// Whether the generated modules should have any resources declared. - pub add_resources: bool, - /// The minimum number of entries in any table - pub min_table_size: usize, - /// If set, all functions with type parameters will have arguments of those types as well. - pub args_for_ty_params: bool, -} - -impl Default for ModuleGeneratorOptions { - fn default() -> Self { - Self { - min_fields: 1, - max_locals: 10, - max_fields: 20, - max_structs: 100, - max_functions: 100, - max_ty_params: 5, - byte_array_max_size: 64, - max_string_size: 32, - max_function_call_size: 23, - max_ret_types_size: 4, - simple_types_only: false, - references_allowed: true, - add_resources: true, - min_table_size: 1, - args_for_ty_params: false, - } - } -} diff --git a/third_party/move/testing-infra/module-generation/src/padding.rs b/third_party/move/testing-infra/module-generation/src/padding.rs deleted file mode 100644 index 10d0defe9eb10..0000000000000 --- a/third_party/move/testing-infra/module-generation/src/padding.rs +++ /dev/null @@ -1,75 +0,0 @@ -// Copyright (c) The Diem Core Contributors -// Copyright (c) The Move Contributors -// SPDX-License-Identifier: Apache-2.0 - -use crate::{options::ModuleGeneratorOptions, utils::random_string}; -use move_binary_format::file_format::{Bytecode, CompiledModule, Signature}; -use move_core_types::{account_address::AccountAddress, identifier::Identifier}; -use rand::{rngs::StdRng, Rng, SeedableRng}; - -/////////////////////////////////////////////////////////////////////////// -// Padding of tables in compiled modules -/////////////////////////////////////////////////////////////////////////// - -pub struct Pad { - gen: StdRng, - table_size: usize, - options: ModuleGeneratorOptions, -} - -impl Pad { - pub fn pad(table_size: usize, module: &mut CompiledModule, options: ModuleGeneratorOptions) { - let seed: [u8; 32] = [1; 32]; - let mut slf = Self { - gen: StdRng::from_seed(seed), - table_size, - options, - }; - slf.pad_cosntant_table(module); - slf.pad_identifier_table(module); - slf.pad_address_identifier_table(module); - slf.pad_signatures(module); - slf.pad_function_bodies(module); - } - - fn pad_cosntant_table(&mut self, module: &mut CompiledModule) { - // TODO actual constant generation - module.constant_pool = vec![] - } - - fn pad_identifier_table(&mut self, module: &mut CompiledModule) { - module.identifiers = (0..(self.table_size + module.identifiers.len())) - .map(|_| { - let len = self.gen.gen_range(10..self.options.max_string_size); - Identifier::new(random_string(&mut self.gen, len)).unwrap() - }) - .collect() - } - - fn pad_address_identifier_table(&mut self, module: &mut CompiledModule) { - module.address_identifiers = (0..(self.table_size + module.address_identifiers.len())) - .map(|_| AccountAddress::random()) - .collect() - } - - fn pad_function_bodies(&mut self, module: &mut CompiledModule) { - for fdef in module.function_defs.iter_mut() { - if let Some(code) = &mut fdef.code { - code.code = vec![ - Bytecode::LdTrue, - Bytecode::LdTrue, - Bytecode::Pop, - Bytecode::Pop, - Bytecode::Ret, - ] - } - } - } - - // Ensure that locals signatures always contain an empty signature - fn pad_signatures(&mut self, module: &mut CompiledModule) { - if module.signatures.iter().all(|v| !v.is_empty()) { - module.signatures.push(Signature(Vec::new())); - } - } -} diff --git a/third_party/move/testing-infra/module-generation/src/utils.rs b/third_party/move/testing-infra/module-generation/src/utils.rs deleted file mode 100644 index 07a03ee6e2c53..0000000000000 --- a/third_party/move/testing-infra/module-generation/src/utils.rs +++ /dev/null @@ -1,15 +0,0 @@ -// Copyright (c) The Diem Core Contributors -// Copyright (c) The Move Contributors -// SPDX-License-Identifier: Apache-2.0 - -use rand::{distributions::Alphanumeric, rngs::StdRng, Rng}; - -pub fn random_string(rng: &mut StdRng, len: usize) -> String { - if len == 0 { - "".to_string() - } else { - let mut string = "a".to_string(); - (1..len).for_each(|_| string.push(char::from(rng.sample(Alphanumeric)))); - string - } -}