From b1a5887125c2826ec487b5712ac6ca072dcaa25f Mon Sep 17 00:00:00 2001 From: George Mitenkov Date: Tue, 21 Oct 2025 23:37:16 +0100 Subject: [PATCH] [vm][WIP] Type IDs --- Cargo.lock | 1 + .../aptos-native-interface/src/builder.rs | 14 +- .../aptos-native-interface/src/errors.rs | 4 +- .../aptos-native-interface/src/native.rs | 4 +- .../aptos-vm-profiling/src/bins/run_move.rs | 6 +- .../verifier/transaction_arg_validation.rs | 291 ++-- .../aptos-vm/src/verifier/view_function.rs | 82 +- aptos-move/block-executor/src/code_cache.rs | 16 +- .../block-executor/src/code_cache_global.rs | 17 +- .../tests/resource_groups.txt | 8 + .../tests/transaction_context.txt | 7 + .../framework/move-stdlib/src/natives/bcs.rs | 23 +- .../framework/move-stdlib/src/natives/cmp.rs | 4 +- .../framework/move-stdlib/src/natives/hash.rs | 6 +- .../framework/move-stdlib/src/natives/mem.rs | 4 +- .../move-stdlib/src/natives/signer.rs | 4 +- .../move-stdlib/src/natives/string.rs | 10 +- .../move-stdlib/src/natives/unit_test.rs | 4 +- .../move-stdlib/src/natives/vector.rs | 6 +- aptos-move/framework/src/natives/account.rs | 4 +- .../src/natives/account_abstraction.rs | 6 +- .../natives/aggregator_natives/aggregator.rs | 10 +- .../aggregator_natives/aggregator_factory.rs | 4 +- .../aggregator_natives/aggregator_v2.rs | 75 +- .../natives/aggregator_natives/helpers_v2.rs | 18 +- aptos-move/framework/src/natives/code.rs | 4 +- .../framework/src/natives/consensus_config.rs | 4 +- .../framework/src/natives/create_signer.rs | 4 +- .../cryptography/algebra/arithmetics/add.rs | 6 +- .../cryptography/algebra/arithmetics/div.rs | 6 +- .../algebra/arithmetics/double.rs | 6 +- .../cryptography/algebra/arithmetics/inv.rs | 6 +- .../cryptography/algebra/arithmetics/mul.rs | 6 +- .../cryptography/algebra/arithmetics/neg.rs | 6 +- .../algebra/arithmetics/scalar_mul.rs | 14 +- .../cryptography/algebra/arithmetics/sqr.rs | 6 +- .../cryptography/algebra/arithmetics/sub.rs | 6 +- .../natives/cryptography/algebra/casting.rs | 14 +- .../natives/cryptography/algebra/constants.rs | 16 +- .../src/natives/cryptography/algebra/eq.rs | 6 +- .../cryptography/algebra/hash_to_structure.rs | 8 +- .../src/natives/cryptography/algebra/new.rs | 6 +- .../natives/cryptography/algebra/pairing.rs | 18 +- .../src/natives/cryptography/algebra/rand.rs | 6 +- .../cryptography/algebra/serialization.rs | 14 +- .../src/natives/cryptography/bls12381.rs | 28 +- .../src/natives/cryptography/bulletproofs.rs | 10 +- .../src/natives/cryptography/ed25519.rs | 10 +- .../src/natives/cryptography/multi_ed25519.rs | 12 +- .../cryptography/ristretto255_point.rs | 34 +- .../cryptography/ristretto255_scalar.rs | 26 +- .../src/natives/cryptography/secp256k1.rs | 4 +- aptos-move/framework/src/natives/debug.rs | 15 +- .../natives/dispatchable_fungible_asset.rs | 6 +- aptos-move/framework/src/natives/event.rs | 36 +- .../framework/src/natives/function_info.rs | 8 +- aptos-move/framework/src/natives/hash.rs | 14 +- aptos-move/framework/src/natives/object.rs | 16 +- .../src/natives/permissioned_signer.rs | 10 +- .../framework/src/natives/randomness.rs | 6 +- .../framework/src/natives/state_storage.rs | 4 +- .../framework/src/natives/string_utils.rs | 21 +- .../src/natives/transaction_context.rs | 28 +- aptos-move/framework/src/natives/type_info.rs | 12 +- aptos-move/framework/src/natives/util.rs | 8 +- aptos-move/framework/table-natives/src/lib.rs | 39 +- .../move-table-extension/src/lib.rs | 34 +- .../move-binary-format/src/file_format.rs | 6 + .../move/move-stdlib/src/natives/bcs.rs | 7 +- .../move/move-stdlib/src/natives/debug.rs | 41 +- .../move/move-stdlib/src/natives/event.rs | 5 +- .../move/move-stdlib/src/natives/hash.rs | 8 +- .../move/move-stdlib/src/natives/signer.rs | 4 +- .../move/move-stdlib/src/natives/string.rs | 10 +- .../move/move-stdlib/src/natives/type_name.rs | 6 +- .../move/move-stdlib/src/natives/unit_test.rs | 6 +- .../move-vm/runtime/src/access_control.rs | 1 + .../move/move-vm/runtime/src/data_cache.rs | 30 +- third_party/move/move-vm/runtime/src/frame.rs | 131 +- .../move-vm/runtime/src/frame_type_cache.rs | 62 +- .../move/move-vm/runtime/src/interpreter.rs | 298 ++-- .../move-vm/runtime/src/loader/function.rs | 124 +- .../move-vm/runtime/src/loader/modules.rs | 1 + .../move/move-vm/runtime/src/loader/script.rs | 21 + .../move/move-vm/runtime/src/move_vm.rs | 84 +- .../move-vm/runtime/src/native_functions.rs | 25 +- .../move-vm/runtime/src/runtime_ref_checks.rs | 36 +- .../runtime/src/runtime_type_checks.rs | 472 +++--- .../runtime/src/storage/environment.rs | 8 +- .../runtime/src/storage/layout_cache.rs | 17 +- .../runtime/src/storage/loader/lazy.rs | 11 +- .../runtime/src/storage/loader/test_utils.rs | 1 + .../runtime/src/storage/loader/traits.rs | 26 +- .../runtime/src/storage/ty_depth_checker.rs | 1 + .../src/storage/ty_layout_converter.rs | 985 ++++++----- .../runtime/src/storage/ty_tag_converter.rs | 559 ++----- third_party/move/move-vm/types/Cargo.toml | 1 + .../types/src/loaded_data/runtime_types.rs | 119 +- .../src/loaded_data/struct_name_indexing.rs | 2 +- .../move-vm/types/src/natives/function.rs | 4 +- .../move/move-vm/types/src/ty_interner.rs | 1461 +++++++++++++---- .../move-vm/types/src/values/values_impl.rs | 292 ++-- 102 files changed, 3295 insertions(+), 2741 deletions(-) create mode 100644 aptos-move/e2e-move-tests/proptest-regressions/tests/resource_groups.txt create mode 100644 aptos-move/e2e-move-tests/proptest-regressions/tests/transaction_context.txt diff --git a/Cargo.lock b/Cargo.lock index b12448b1baac9..535aae65bd061 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -13119,6 +13119,7 @@ name = "move-vm-types" version = "0.1.0" dependencies = [ "ambassador", + "arc-swap", "bcs 0.1.4", "better_any", "bytes", diff --git a/aptos-move/aptos-native-interface/src/builder.rs b/aptos-move/aptos-native-interface/src/builder.rs index b65e6fcb397a9..edef889e75c52 100644 --- a/aptos-move/aptos-native-interface/src/builder.rs +++ b/aptos-move/aptos-native-interface/src/builder.rs @@ -9,9 +9,7 @@ use aptos_gas_algebra::DynamicExpression; use aptos_gas_schedule::{MiscGasParameters, NativeGasParameters}; use aptos_types::on_chain_config::{Features, TimedFeatures}; use move_vm_runtime::native_functions::{NativeContext, NativeFunction}; -use move_vm_types::{ - loaded_data::runtime_types::Type, natives::function::NativeResult, values::Value, -}; +use move_vm_types::{natives::function::NativeResult, ty_interner::TypeId, values::Value}; use smallvec::SmallVec; use std::{collections::VecDeque, sync::Arc}; @@ -81,9 +79,9 @@ impl SafeNativeBuilder { /// allowing the client to use [`SafeNativeContext`] instead of Move VM's [`NativeContext`]. pub fn make_native(&self, native: F) -> NativeFunction where - F: Fn( + F: for<'a> Fn( &mut SafeNativeContext, - Vec, + &'a [TypeId], VecDeque, ) -> SafeNativeResult> + Send @@ -95,7 +93,7 @@ impl SafeNativeBuilder { let enable_incremental_gas_charging = self.enable_incremental_gas_charging; - let closure = move |context: &mut NativeContext, ty_args, args| { + let closure = move |context: &mut NativeContext, ty_args: &[TypeId], args| { use SafeNativeError::*; let mut context = SafeNativeContext { @@ -175,9 +173,9 @@ impl SafeNativeBuilder { ) -> impl Iterator + 'a where 'b: 'a, - F: Fn( + F: for<'c> Fn( &mut SafeNativeContext, - Vec, + &'c [TypeId], VecDeque, ) -> SafeNativeResult> + Send diff --git a/aptos-move/aptos-native-interface/src/errors.rs b/aptos-move/aptos-native-interface/src/errors.rs index 5c269a50a9dc7..d5c7488081e83 100644 --- a/aptos-move/aptos-native-interface/src/errors.rs +++ b/aptos-move/aptos-native-interface/src/errors.rs @@ -3,7 +3,7 @@ use move_binary_format::errors::PartialVMError; use move_core_types::{identifier::Identifier, language_storage::ModuleId, vm_status::StatusCode}; -use move_vm_types::{loaded_data::runtime_types::Type, values::Value}; +use move_vm_types::{ty_interner::TypeId, values::Value}; use smallvec::SmallVec; /// Wraps [PartialVMError] to ensure it cannot be constructed via public constructor when we create @@ -81,7 +81,7 @@ pub enum SafeNativeError { FunctionDispatch { module_name: ModuleId, func_name: Identifier, - ty_args: Vec, + ty_args: Vec, args: SmallVec<[Value; 1]>, }, diff --git a/aptos-move/aptos-native-interface/src/native.rs b/aptos-move/aptos-native-interface/src/native.rs index e917307b85c81..e685bafb35bd1 100644 --- a/aptos-move/aptos-native-interface/src/native.rs +++ b/aptos-move/aptos-native-interface/src/native.rs @@ -2,7 +2,7 @@ // SPDX-License-Identifier: Apache-2.0 use crate::{context::SafeNativeContext, errors::SafeNativeResult}; -use move_vm_types::{loaded_data::runtime_types::Type, values::Value}; +use move_vm_types::{ty_interner::TypeId, values::Value}; use smallvec::SmallVec; use std::collections::VecDeque; @@ -12,6 +12,6 @@ use std::collections::VecDeque; /// it can be used in the VM. pub type RawSafeNative = fn( &mut SafeNativeContext, - Vec, + &[TypeId], VecDeque, ) -> SafeNativeResult>; diff --git a/aptos-move/aptos-vm-profiling/src/bins/run_move.rs b/aptos-move/aptos-vm-profiling/src/bins/run_move.rs index c2969f48f3734..7c0fbe0279fdd 100644 --- a/aptos-move/aptos-vm-profiling/src/bins/run_move.rs +++ b/aptos-move/aptos-vm-profiling/src/bins/run_move.rs @@ -24,8 +24,8 @@ use move_vm_runtime::{ }; use move_vm_test_utils::InMemoryStorage; use move_vm_types::{ - gas::UnmeteredGasMeter, loaded_data::runtime_types::Type, natives::function::NativeResult, - pop_arg, values::Value, + gas::UnmeteredGasMeter, natives::function::NativeResult, pop_arg, ty_interner::TypeId, + values::Value, }; use smallvec::smallvec; use std::{collections::VecDeque, env, fs, sync::Arc}; @@ -37,7 +37,7 @@ enum Entrypoint { } fn make_native_create_signer() -> NativeFunction { - Arc::new(|_context, ty_args: Vec, mut args: VecDeque| { + Arc::new(|_context, ty_args: &[TypeId], mut args: VecDeque| { assert!(ty_args.is_empty()); assert_eq!(args.len(), 1); diff --git a/aptos-move/aptos-vm/src/verifier/transaction_arg_validation.rs b/aptos-move/aptos-vm/src/verifier/transaction_arg_validation.rs index c0f94ae0d70ba..71ee5594f81af 100644 --- a/aptos-move/aptos-vm/src/verifier/transaction_arg_validation.rs +++ b/aptos-move/aptos-vm/src/verifier/transaction_arg_validation.rs @@ -31,6 +31,7 @@ use move_vm_runtime::{ use move_vm_types::{ gas::GasMeter, loaded_data::runtime_types::{Type, TypeParamMap}, + ty_interner::{TypeId, TypeRepr}, }; use once_cell::sync::Lazy; use std::{ @@ -133,13 +134,12 @@ pub(crate) fn validate_combine_signer_and_txn_args( } let allowed_structs = get_allowed_structs(are_struct_constructors_enabled); - let ty_builder = &loader.runtime_environment().vm_config().ty_builder; + let pool = loader.runtime_environment().ty_pool(); // Need to keep this here to ensure we return the historic correct error code for replay for ty in func.param_tys()[signer_param_cnt..].iter() { - let subst_res = ty_builder.create_ty_with_subst(ty, func.ty_args()); - let ty = subst_res.map_err(|e| e.finish(Location::Undefined).into_vm_status())?; - let valid = is_valid_txn_arg(loader.runtime_environment(), &ty, allowed_structs); + let ty = pool.instantiate_and_intern(ty, func.ty_args()); + let valid = is_valid_txn_arg(loader.runtime_environment(), ty, allowed_structs); if !valid { return Err(VMStatus::error( StatusCode::INVALID_MAIN_FUNCTION_SIGNATURE, @@ -170,17 +170,35 @@ pub(crate) fn validate_combine_signer_and_txn_args( // This also validates that the args are valid. If they are structs, they have to be allowed // and must be constructed successfully. If construction fails, this would fail with a // FAILED_TO_DESERIALIZE_ARGUMENT error. - let args = construct_args( - session, - loader, - gas_meter, - traversal_context, - &func.param_tys()[signer_param_cnt..], - args, - func.ty_args(), - allowed_structs, - false, - )?; + let args = if func.ty_args().is_empty() { + construct_args( + session, + loader, + gas_meter, + traversal_context, + &func.param_ty_ids()[signer_param_cnt..], + args, + allowed_structs, + false, + )? + } else { + let param_tys = func + .param_tys() + .iter() + .skip(signer_param_cnt) + .map(|ty| pool.instantiate_and_intern(ty, func.ty_args())) + .collect::>(); + construct_args( + session, + loader, + gas_meter, + traversal_context, + ¶m_tys, + args, + allowed_structs, + false, + )? + }; // Combine signer and non-signer arguments. let combined_args = if signer_param_cnt == 0 { @@ -197,31 +215,50 @@ pub(crate) fn validate_combine_signer_and_txn_args( /// its name cannot be queried for some reason. pub(crate) fn is_valid_txn_arg( runtime_environment: &RuntimeEnvironment, - ty: &Type, + ty: TypeId, allowed_structs: &ConstructorMap, ) -> bool { - use move_vm_types::loaded_data::runtime_types::Type::*; - match ty { - Bool | U8 | U16 | U32 | U64 | U128 | U256 | I8 | I16 | I32 | I64 | I128 | I256 - | Address => true, - Vector(inner) => is_valid_txn_arg(runtime_environment, inner, allowed_structs), - Struct { .. } | StructInstantiation { .. } => { - // Note: Original behavior was to return false even if the module loading fails (e.g., - // if struct does not exist. This preserves it. - runtime_environment - .get_struct_name(ty) - .ok() - .flatten() - .is_some_and(|(module_id, identifier)| { - allowed_structs.contains_key(&format!( - "{}::{}", - module_id.short_str_lossless(), - identifier - )) - }) + TypeId::BOOL + | TypeId::U8 + | TypeId::U16 + | TypeId::U32 + | TypeId::U64 + | TypeId::U128 + | TypeId::U256 + | TypeId::I8 + | TypeId::I16 + | TypeId::I32 + | TypeId::I64 + | TypeId::I128 + | TypeId::I256 + | TypeId::ADDRESS => true, + TypeId::SIGNER => false, + ty => { + if ty.is_any_ref() { + return false; + } + + let pool = runtime_environment.ty_pool(); + match pool.type_repr(ty) { + TypeRepr::Vector(elem) => { + is_valid_txn_arg(runtime_environment, elem, allowed_structs) + }, + TypeRepr::Struct { idx, .. } => runtime_environment + .struct_name_index_map() + .idx_to_struct_name(idx) + .ok() + .is_some_and(|id| { + allowed_structs.contains_key(&format!( + "{}::{}", + id.module.short_str_lossless(), + id.name + )) + }), + TypeRepr::Function { .. } => false, + _ => unreachable!(), + } }, - Signer | Reference(_) | MutableReference(_) | TyParam(_) | Function { .. } => false, } } @@ -233,9 +270,8 @@ pub(crate) fn construct_args( loader: &impl Loader, gas_meter: &mut impl GasMeter, traversal_context: &mut TraversalContext, - types: &[Type], + types: &[TypeId], args: Vec>, - ty_args: &[Type], allowed_structs: &ConstructorMap, is_view: bool, ) -> Result>, VMStatus> { @@ -245,16 +281,13 @@ pub(crate) fn construct_args( return Err(invalid_signature()); } - let ty_builder = &loader.runtime_environment().vm_config().ty_builder; for (ty, arg) in types.iter().zip(args) { - let subst_res = ty_builder.create_ty_with_subst(ty, ty_args); - let ty = subst_res.map_err(|e| e.finish(Location::Undefined).into_vm_status())?; let arg = construct_arg( session, loader, gas_meter, traversal_context, - &ty, + *ty, allowed_structs, arg, is_view, @@ -273,32 +306,66 @@ fn construct_arg( loader: &impl Loader, gas_meter: &mut impl GasMeter, traversal_context: &mut TraversalContext, - ty: &Type, + ty: TypeId, allowed_structs: &ConstructorMap, arg: Vec, is_view: bool, ) -> Result, VMStatus> { - use move_vm_types::loaded_data::runtime_types::Type::*; match ty { - Bool | U8 | U16 | U32 | U64 | U128 | U256 | I8 | I16 | I32 | I64 | I128 | I256 - | Address => Ok(arg), - Vector(_) | Struct { .. } | StructInstantiation { .. } => { + TypeId::BOOL + | TypeId::U8 + | TypeId::U16 + | TypeId::U32 + | TypeId::U64 + | TypeId::U128 + | TypeId::U256 + | TypeId::I8 + | TypeId::I16 + | TypeId::I32 + | TypeId::I64 + | TypeId::I128 + | TypeId::I256 + | TypeId::ADDRESS => Ok(arg), + TypeId::SIGNER => { + if is_view { + Ok(arg) + } else { + Err(invalid_signature()) + } + }, + ty => { + if ty.is_any_ref() { + return Err(invalid_signature()); + } + let initial_cursor_len = arg.len(); let mut cursor = Cursor::new(&arg[..]); let mut new_arg = vec![]; let mut max_invocations = 10; // Read from config in the future - recursively_construct_arg( - session, - loader, - gas_meter, - traversal_context, - ty, - allowed_structs, - &mut cursor, - initial_cursor_len, - &mut max_invocations, - &mut new_arg, - )?; + + let pool = loader.runtime_environment().ty_pool(); + let repr = pool.type_repr(ty); + match repr { + TypeRepr::Function { .. } => { + return Err(invalid_signature()); + }, + TypeRepr::Vector(_) | TypeRepr::Struct { .. } => { + recursively_construct_arg( + session, + loader, + gas_meter, + traversal_context, + &repr, + allowed_structs, + &mut cursor, + initial_cursor_len, + &mut max_invocations, + &mut new_arg, + )?; + }, + _ => unreachable!(), + } + // Check cursor has parsed everything // Unfortunately, is_empty is only enabled in nightly, so we check this way. if cursor.position() != initial_cursor_len as u64 { @@ -311,16 +378,6 @@ fn construct_arg( } Ok(new_arg) }, - Signer => { - if is_view { - Ok(arg) - } else { - Err(invalid_signature()) - } - }, - Reference(_) | MutableReference(_) | TyParam(_) | Function { .. } => { - Err(invalid_signature()) - }, } } @@ -332,17 +389,16 @@ pub(crate) fn recursively_construct_arg( loader: &impl Loader, gas_meter: &mut impl GasMeter, traversal_context: &mut TraversalContext, - ty: &Type, + ty: &TypeRepr, allowed_structs: &ConstructorMap, cursor: &mut Cursor<&[u8]>, initial_cursor_len: usize, max_invocations: &mut u64, arg: &mut Vec, ) -> Result<(), VMStatus> { - use move_vm_types::loaded_data::runtime_types::Type::*; - + let pool = loader.runtime_environment().ty_pool(); match ty { - Vector(inner) => { + TypeRepr::Vector(inner) => { // get the vector length and iterate over each element let mut len = get_len(cursor)?; serialize_uleb128(len, arg); @@ -352,7 +408,7 @@ pub(crate) fn recursively_construct_arg( loader, gas_meter, traversal_context, - inner, + &pool.type_repr(*inner), allowed_structs, cursor, initial_cursor_len, @@ -362,16 +418,17 @@ pub(crate) fn recursively_construct_arg( len -= 1; } }, - Struct { .. } | StructInstantiation { .. } => { + TypeRepr::Struct { idx, .. } => { let (module_id, identifier) = loader .runtime_environment() - .get_struct_name(ty) + .struct_name_index_map() + .idx_to_struct_name(*idx) + .map(|id| (id.module, id.name)) .map_err(|_| { // Note: The original behaviour was to map all errors to an invalid signature // error, here we want to preserve it for now. invalid_signature() - })? - .ok_or_else(invalid_signature)?; + })?; let full_name = format!("{}::{}", module_id.short_str_lossless(), identifier); let constructor = allowed_structs .get(&full_name) @@ -391,15 +448,16 @@ pub(crate) fn recursively_construct_arg( max_invocations, )?); }, - Bool | U8 | I8 => read_n_bytes(1, cursor, arg)?, - U16 | I16 => read_n_bytes(2, cursor, arg)?, - U32 | I32 => read_n_bytes(4, cursor, arg)?, - U64 | I64 => read_n_bytes(8, cursor, arg)?, - U128 | I128 => read_n_bytes(16, cursor, arg)?, - U256 | I256 | Address => read_n_bytes(32, cursor, arg)?, - Signer | Reference(_) | MutableReference(_) | TyParam(_) | Function { .. } => { - return Err(invalid_signature()) - }, + TypeRepr::Bool | TypeRepr::U8 | TypeRepr::I8 => read_n_bytes(1, cursor, arg)?, + TypeRepr::U16 | TypeRepr::I16 => read_n_bytes(2, cursor, arg)?, + TypeRepr::U32 | TypeRepr::I32 => read_n_bytes(4, cursor, arg)?, + TypeRepr::U64 | TypeRepr::I64 => read_n_bytes(8, cursor, arg)?, + TypeRepr::U128 | TypeRepr::I128 => read_n_bytes(16, cursor, arg)?, + TypeRepr::U256 | TypeRepr::I256 | TypeRepr::Address => read_n_bytes(32, cursor, arg)?, + TypeRepr::Signer + | TypeRepr::Reference(_) + | TypeRepr::MutableReference(_) + | TypeRepr::Function { .. } => return Err(invalid_signature()), }; Ok(()) } @@ -413,7 +471,7 @@ fn validate_and_construct( loader: &impl Loader, gas_meter: &mut impl GasMeter, traversal_context: &mut TraversalContext, - expected_type: &Type, + expected_type: &TypeRepr, // note: seems like this must be a struct constructor: &FunctionId, allowed_structs: &ConstructorMap, cursor: &mut Cursor<&[u8]>, @@ -479,19 +537,16 @@ fn validate_and_construct( expected_type, )?; let mut args = vec![]; - let ty_builder = &loader.runtime_environment().vm_config().ty_builder; + let pool = loader.runtime_environment().ty_pool(); for param_ty in function.param_tys() { let mut arg = vec![]; - let arg_ty = ty_builder - .create_ty_with_subst(param_ty, function.ty_args()) - .unwrap(); - + let arg_ty = pool.instantiate_and_intern(param_ty, function.ty_args()); recursively_construct_arg( session, loader, gas_meter, traversal_context, - &arg_ty, + &pool.type_repr(arg_ty), allowed_structs, cursor, initial_cursor_len, @@ -569,7 +624,7 @@ fn load_constructor_function( traversal_context: &mut TraversalContext, module_id: &ModuleId, function_name: &IdentStr, - expected_return_ty: &Type, + expected_return_ty: &TypeRepr, ) -> VMResult { if !module_id.address().is_special() { let msg = format!( @@ -592,13 +647,28 @@ fn load_constructor_function( return Err(PartialVMError::new(StatusCode::ABORTED).finish(Location::Undefined)); } + let pool = loader.runtime_environment().ty_pool(); let mut map = TypeParamMap::default(); - if !map.match_ty(&function.return_tys()[0], expected_return_ty) { - // For functions that are marked constructor this should not happen. - return Err( - PartialVMError::new(StatusCode::INVALID_MAIN_FUNCTION_SIGNATURE) - .finish(Location::Undefined), - ); + match (&function.return_tys()[0], expected_return_ty) { + (Type::Struct { .. }, TypeRepr::Struct { .. }) => { + // todo: assert == + }, + (Type::StructInstantiation { ty_args, .. }, TypeRepr::Struct { ty_args: ids, .. }) => { + // need to infer type arguments. + let ids = pool.get_type_vec(*ids); + if !ty_args + .iter() + .zip(ids.iter()) + .all(|(t, e)| map.match_ty(pool, t, *e)) + { + // For functions that are marked constructor this should not happen. + return Err( + PartialVMError::new(StatusCode::INVALID_MAIN_FUNCTION_SIGNATURE) + .finish(Location::Undefined), + ); + } + }, + _ => unreachable!(), } // Construct the type arguments from the match. @@ -611,13 +681,20 @@ fn load_constructor_function( })?); } - Type::verify_ty_arg_abilities(function.ty_param_abilities(), &ty_args) - .map_err(|e| e.finish(Location::Module(module_id.clone())))?; - let ty_args_id = loader - .runtime_environment() - .ty_pool() - .intern_ty_args(&ty_args); + if function.ty_param_abilities().len() != ty_args.len() { + return Err( + PartialVMError::new(StatusCode::NUMBER_OF_TYPE_ARGUMENTS_MISMATCH) + .finish(Location::Module(module_id.clone())), + ); + } + for (ty, expected_ability_set) in ty_args.iter().zip(function.ty_param_abilities()) { + if !expected_ability_set.is_subset(pool.abilities(*ty)) { + return Err(PartialVMError::new(StatusCode::CONSTRAINT_NOT_SATISFIED) + .finish(Location::Module(module_id.clone()))); + } + } + let ty_args_id = pool.intern_ty_slice(&ty_args); Ok(LoadedFunction { owner: LoadedFunctionOwner::Module(module), ty_args, diff --git a/aptos-move/aptos-vm/src/verifier/view_function.rs b/aptos-move/aptos-vm/src/verifier/view_function.rs index 95bb90ee9855a..77750bfb41828 100644 --- a/aptos-move/aptos-vm/src/verifier/view_function.rs +++ b/aptos-move/aptos-vm/src/verifier/view_function.rs @@ -60,33 +60,69 @@ pub(crate) fn validate_view_function( ); } + let pool = loader.runtime_environment().ty_pool(); let allowed_structs = get_allowed_structs(struct_constructors_feature); let result = if loader.is_lazy_loading_enabled() { - transaction_arg_validation::construct_args( - session, - loader, - gas_meter, - traversal_context, - func.param_tys(), - args, - func.ty_args(), - allowed_structs, - true, - ) + if func.ty_args().is_empty() { + transaction_arg_validation::construct_args( + session, + loader, + gas_meter, + traversal_context, + func.param_ty_ids(), + args, + allowed_structs, + true, + ) + } else { + let param_tys = func + .param_tys() + .iter() + .map(|ty| pool.instantiate_and_intern(ty, func.ty_args())) + .collect::>(); + transaction_arg_validation::construct_args( + session, + loader, + gas_meter, + traversal_context, + ¶m_tys, + args, + allowed_structs, + true, + ) + } } else { let traversal_storage = TraversalStorage::new(); - transaction_arg_validation::construct_args( - session, - loader, - // No metering with eager loading. - &mut UnmeteredGasMeter, - &mut TraversalContext::new(&traversal_storage), - func.param_tys(), - args, - func.ty_args(), - allowed_structs, - true, - ) + if func.ty_args().is_empty() { + transaction_arg_validation::construct_args( + session, + loader, + // No metering with eager loading. + &mut UnmeteredGasMeter, + &mut TraversalContext::new(&traversal_storage), + func.param_ty_ids(), + args, + allowed_structs, + true, + ) + } else { + let param_tys = func + .param_tys() + .iter() + .map(|ty| pool.instantiate_and_intern(ty, func.ty_args())) + .collect::>(); + transaction_arg_validation::construct_args( + session, + loader, + // No metering with eager loading. + &mut UnmeteredGasMeter, + &mut TraversalContext::new(&traversal_storage), + ¶m_tys, + args, + allowed_structs, + true, + ) + } }; result.map_err(|e| PartialVMError::new(e.status_code())) } diff --git a/aptos-move/block-executor/src/code_cache.rs b/aptos-move/block-executor/src/code_cache.rs index 7803df342e844..d971957e51a10 100644 --- a/aptos-move/block-executor/src/code_cache.rs +++ b/aptos-move/block-executor/src/code_cache.rs @@ -28,12 +28,14 @@ use move_core_types::{ account_address::AccountAddress, identifier::IdentStr, language_storage::ModuleId, }; use move_vm_runtime::{ - LayoutCache, LayoutCacheEntry, Module, RuntimeEnvironment, Script, StructKey, - WithRuntimeEnvironment, + LayoutCache, LayoutCacheEntry, Module, RuntimeEnvironment, Script, WithRuntimeEnvironment, }; -use move_vm_types::code::{ - ambassador_impl_ScriptCache, Code, ModuleCache, ModuleCode, ModuleCodeBuilder, ScriptCache, - WithBytes, +use move_vm_types::{ + code::{ + ambassador_impl_ScriptCache, Code, ModuleCache, ModuleCode, ModuleCodeBuilder, ScriptCache, + WithBytes, + }, + ty_interner::TypeId, }; use std::sync::Arc; @@ -252,11 +254,11 @@ impl> LatestView<'_, T, S> { } impl> LayoutCache for LatestView<'_, T, S> { - fn get_struct_layout(&self, key: &StructKey) -> Option { + fn get_struct_layout(&self, key: TypeId) -> Option { self.global_module_cache.get_struct_layout_entry(key) } - fn store_struct_layout(&self, key: &StructKey, entry: LayoutCacheEntry) -> PartialVMResult<()> { + fn store_struct_layout(&self, key: TypeId, entry: LayoutCacheEntry) -> PartialVMResult<()> { self.global_module_cache .store_struct_layout_entry(key, entry)?; Ok(()) diff --git a/aptos-move/block-executor/src/code_cache_global.rs b/aptos-move/block-executor/src/code_cache_global.rs index 98ca601d0e095..c5a03eed1ae3b 100644 --- a/aptos-move/block-executor/src/code_cache_global.rs +++ b/aptos-move/block-executor/src/code_cache_global.rs @@ -12,8 +12,11 @@ use dashmap::DashMap; use hashbrown::HashMap; use move_binary_format::{errors::PartialVMResult, CompiledModule}; use move_core_types::language_storage::ModuleId; -use move_vm_runtime::{LayoutCacheEntry, Module, RuntimeEnvironment, StructKey}; -use move_vm_types::code::{ModuleCache, ModuleCode, WithSize}; +use move_vm_runtime::{LayoutCacheEntry, Module, RuntimeEnvironment}; +use move_vm_types::{ + code::{ModuleCache, ModuleCode, WithSize}, + ty_interner::TypeId, +}; use std::{ hash::Hash, ops::Deref, @@ -77,7 +80,7 @@ pub struct GlobalModuleCache { size: usize, /// Cached layouts of structs or enums. This cache stores roots only and is invalidated when /// modules are published. - struct_layouts: DashMap, + struct_layouts: DashMap, } impl GlobalModuleCache @@ -152,8 +155,8 @@ where } /// Returns layout entry if it exists in global cache. - pub(crate) fn get_struct_layout_entry(&self, key: &StructKey) -> Option { - match self.struct_layouts.get(key) { + pub(crate) fn get_struct_layout_entry(&self, key: TypeId) -> Option { + match self.struct_layouts.get(&key) { None => { GLOBAL_LAYOUT_CACHE_MISSES.inc(); None @@ -164,10 +167,10 @@ where pub(crate) fn store_struct_layout_entry( &self, - key: &StructKey, + key: TypeId, entry: LayoutCacheEntry, ) -> PartialVMResult<()> { - if let dashmap::Entry::Vacant(e) = self.struct_layouts.entry(*key) { + if let dashmap::Entry::Vacant(e) = self.struct_layouts.entry(key) { e.insert(entry); } Ok(()) diff --git a/aptos-move/e2e-move-tests/proptest-regressions/tests/resource_groups.txt b/aptos-move/e2e-move-tests/proptest-regressions/tests/resource_groups.txt new file mode 100644 index 0000000000000..26507f2857efe --- /dev/null +++ b/aptos-move/e2e-move-tests/proptest-regressions/tests/resource_groups.txt @@ -0,0 +1,8 @@ +# Seeds for failure cases proptest has generated in the past. It is +# automatically read and these particular cases re-run before any +# novel cases are generated. +# +# It is recommended to check this file in to source control so that +# everyone who runs the test benefits from these saved cases. +cc 17bdb261289d43e22788e8f8b037b5ab1e1506a0861ef365ef9d541d9b435e92 # shrinks to test_env = TestEnvConfig { executor_mode: BothComparison, resource_group_mode: BothComparison, block_split: Whole } +cc ff8bd81f06d0dad48a62a47f0297c4bfbee25ed651c25c929bef14bfe80b6f93 # shrinks to test_env = TestEnvConfig { executor_mode: BothComparison, resource_group_mode: DisabledOnly, block_split: Whole } diff --git a/aptos-move/e2e-move-tests/proptest-regressions/tests/transaction_context.txt b/aptos-move/e2e-move-tests/proptest-regressions/tests/transaction_context.txt new file mode 100644 index 0000000000000..1f2cc147d5643 --- /dev/null +++ b/aptos-move/e2e-move-tests/proptest-regressions/tests/transaction_context.txt @@ -0,0 +1,7 @@ +# Seeds for failure cases proptest has generated in the past. It is +# automatically read and these particular cases re-run before any +# novel cases are generated. +# +# It is recommended to check this file in to source control so that +# everyone who runs the test benefits from these saved cases. +cc ea657426e5e371dd23491fcee015a44b5fb6ba7ca06a6ef0a344f8a3e8bc1abd # shrinks to block_split = Whole diff --git a/aptos-move/framework/move-stdlib/src/natives/bcs.rs b/aptos-move/framework/move-stdlib/src/natives/bcs.rs index 3c5ec2c32e973..a1639c25dd757 100644 --- a/aptos-move/framework/move-stdlib/src/natives/bcs.rs +++ b/aptos-move/framework/move-stdlib/src/natives/bcs.rs @@ -20,8 +20,8 @@ use move_core_types::{ }; use move_vm_runtime::native_functions::NativeFunction; use move_vm_types::{ - loaded_data::runtime_types::Type, natives::function::{PartialVMError, PartialVMResult}, + ty_interner::TypeId, value_serde::ValueSerDeContext, values::{values_impl::Reference, Struct, Value}, }; @@ -56,14 +56,14 @@ pub fn create_option_u64(enum_option_enabled: bool, value: Option) -> Value #[inline] fn native_to_bytes( context: &mut SafeNativeContext, - mut ty_args: Vec, + ty_args: &[TypeId], mut args: VecDeque, ) -> SafeNativeResult> { debug_assert!(ty_args.len() == 1); debug_assert!(args.len() == 1); let ref_to_val = safely_pop_arg!(args, Reference); - let arg_type = ty_args.pop().unwrap(); + let arg_type = ty_args[0]; let layout = if context.get_feature_flags().is_lazy_loading_enabled() { // With lazy loading, propagate the error directly. This is because errors here are likely @@ -76,9 +76,9 @@ fn native_to_bytes( // - Constructing layout runs into dependency limit. // - We cannot do `context.charge(BCS_TO_BYTES_FAILURE)?;` because then we can end up in // the state where out of gas and dependency limit are hit at the same time. - context.type_to_type_layout(&arg_type)? + context.type_to_type_layout(arg_type)? } else { - match context.type_to_type_layout(&arg_type) { + match context.type_to_type_layout(arg_type) { Ok(layout) => layout, Err(_) => { context.charge(BCS_TO_BYTES_FAILURE)?; @@ -125,7 +125,7 @@ fn native_to_bytes( **************************************************************************************************/ fn native_serialized_size( context: &mut SafeNativeContext, - mut ty_args: Vec, + ty_args: &[TypeId], mut args: VecDeque, ) -> SafeNativeResult> { debug_assert!(ty_args.len() == 1); @@ -134,9 +134,8 @@ fn native_serialized_size( context.charge(BCS_SERIALIZED_SIZE_BASE)?; let reference = safely_pop_arg!(args, Reference); - let ty = ty_args.pop().unwrap(); - let serialized_size = match serialized_size_impl(context, reference, &ty) { + let serialized_size = match serialized_size_impl(context, reference, ty_args[0]) { Ok(serialized_size) => serialized_size as u64, Err(_) => { context.charge(BCS_SERIALIZED_SIZE_FAILURE)?; @@ -155,7 +154,7 @@ fn native_serialized_size( fn serialized_size_impl( context: &mut SafeNativeContext, reference: Reference, - ty: &Type, + ty: TypeId, ) -> PartialVMResult { // TODO(#14175): Reading the reference performs a deep copy, and we can // implement it in a more efficient way. @@ -173,15 +172,15 @@ fn serialized_size_impl( fn native_constant_serialized_size( context: &mut SafeNativeContext, - mut ty_args: Vec, + ty_args: &[TypeId], _args: VecDeque, ) -> SafeNativeResult> { debug_assert!(ty_args.len() == 1); context.charge(BCS_CONSTANT_SERIALIZED_SIZE_BASE)?; - let ty = ty_args.pop().unwrap(); - let ty_layout = context.type_to_type_layout(&ty)?; + let ty = ty_args[0]; + let ty_layout = context.type_to_type_layout(ty)?; let (visited_count, serialized_size_result) = constant_serialized_size(&ty_layout); context diff --git a/aptos-move/framework/move-stdlib/src/natives/cmp.rs b/aptos-move/framework/move-stdlib/src/natives/cmp.rs index e3950b81736c3..a186879db5b3c 100644 --- a/aptos-move/framework/move-stdlib/src/natives/cmp.rs +++ b/aptos-move/framework/move-stdlib/src/natives/cmp.rs @@ -16,8 +16,8 @@ use aptos_native_interface::{ use move_core_types::vm_status::StatusCode; use move_vm_runtime::native_functions::NativeFunction; use move_vm_types::{ - loaded_data::runtime_types::Type, natives::function::PartialVMError, + ty_interner::TypeId, values::{Struct, Value}, }; use smallvec::{smallvec, SmallVec}; @@ -35,7 +35,7 @@ const ORDERING_GREATER_THAN_VARIANT: u16 = 2; **************************************************************************************************/ fn native_compare( context: &mut SafeNativeContext, - _ty_args: Vec, + _ty_args: &[TypeId], args: VecDeque, ) -> SafeNativeResult> { debug_assert!(args.len() == 2); diff --git a/aptos-move/framework/move-stdlib/src/natives/hash.rs b/aptos-move/framework/move-stdlib/src/natives/hash.rs index 2509cb321acbf..5afa786c37561 100644 --- a/aptos-move/framework/move-stdlib/src/natives/hash.rs +++ b/aptos-move/framework/move-stdlib/src/natives/hash.rs @@ -11,7 +11,7 @@ use aptos_native_interface::{ }; use move_core_types::gas_algebra::NumBytes; use move_vm_runtime::native_functions::NativeFunction; -use move_vm_types::{loaded_data::runtime_types::Type, values::Value}; +use move_vm_types::{ty_interner::TypeId, values::Value}; use sha2::{Digest, Sha256}; use sha3::Sha3_256; use smallvec::{smallvec, SmallVec}; @@ -26,7 +26,7 @@ use std::collections::VecDeque; #[inline] fn native_sha2_256( context: &mut SafeNativeContext, - _ty_args: Vec, + _ty_args: &[TypeId], mut arguments: VecDeque, ) -> SafeNativeResult> { debug_assert!(_ty_args.is_empty()); @@ -51,7 +51,7 @@ fn native_sha2_256( #[inline] fn native_sha3_256( context: &mut SafeNativeContext, - _ty_args: Vec, + _ty_args: &[TypeId], mut arguments: VecDeque, ) -> SafeNativeResult> { debug_assert!(_ty_args.is_empty()); diff --git a/aptos-move/framework/move-stdlib/src/natives/mem.rs b/aptos-move/framework/move-stdlib/src/natives/mem.rs index 578d4dc02d685..ecbcc4be2ff06 100644 --- a/aptos-move/framework/move-stdlib/src/natives/mem.rs +++ b/aptos-move/framework/move-stdlib/src/natives/mem.rs @@ -11,7 +11,7 @@ use aptos_native_interface::{ use aptos_types::error; use move_vm_runtime::native_functions::NativeFunction; use move_vm_types::{ - loaded_data::runtime_types::Type, + ty_interner::TypeId, values::{Reference, Value}, }; use smallvec::{smallvec, SmallVec}; @@ -28,7 +28,7 @@ pub const EFEATURE_NOT_ENABLED: u64 = 1; **************************************************************************************************/ fn native_swap( context: &mut SafeNativeContext, - _ty_args: Vec, + _ty_args: &[TypeId], mut args: VecDeque, ) -> SafeNativeResult> { if !context diff --git a/aptos-move/framework/move-stdlib/src/natives/signer.rs b/aptos-move/framework/move-stdlib/src/natives/signer.rs index e0e202fd3ca18..e2da26949fddd 100644 --- a/aptos-move/framework/move-stdlib/src/natives/signer.rs +++ b/aptos-move/framework/move-stdlib/src/natives/signer.rs @@ -11,7 +11,7 @@ use aptos_native_interface::{ }; use move_vm_runtime::native_functions::NativeFunction; use move_vm_types::{ - loaded_data::runtime_types::Type, + ty_interner::TypeId, values::{values_impl::SignerRef, Value}, }; use smallvec::{smallvec, SmallVec}; @@ -26,7 +26,7 @@ use std::collections::VecDeque; #[inline] fn native_borrow_address( context: &mut SafeNativeContext, - _ty_args: Vec, + _ty_args: &[TypeId], mut arguments: VecDeque, ) -> SafeNativeResult> { debug_assert!(_ty_args.is_empty()); diff --git a/aptos-move/framework/move-stdlib/src/natives/string.rs b/aptos-move/framework/move-stdlib/src/natives/string.rs index f90f705049137..24c15ddc59be7 100644 --- a/aptos-move/framework/move-stdlib/src/natives/string.rs +++ b/aptos-move/framework/move-stdlib/src/natives/string.rs @@ -14,7 +14,7 @@ use aptos_native_interface::{ use move_core_types::gas_algebra::NumBytes; use move_vm_runtime::native_functions::NativeFunction; use move_vm_types::{ - loaded_data::runtime_types::Type, + ty_interner::TypeId, values::{Value, VectorRef}, }; use smallvec::{smallvec, SmallVec}; @@ -36,7 +36,7 @@ use std::collections::VecDeque; **************************************************************************************************/ fn native_check_utf8( context: &mut SafeNativeContext, - _ty_args: Vec, + _ty_args: &[TypeId], mut args: VecDeque, ) -> SafeNativeResult> { debug_assert!(args.len() == 1); @@ -62,7 +62,7 @@ fn native_check_utf8( **************************************************************************************************/ fn native_is_char_boundary( context: &mut SafeNativeContext, - _ty_args: Vec, + _ty_args: &[TypeId], mut args: VecDeque, ) -> SafeNativeResult> { debug_assert!(args.len() == 2); @@ -88,7 +88,7 @@ fn native_is_char_boundary( **************************************************************************************************/ fn native_sub_string( context: &mut SafeNativeContext, - _ty_args: Vec, + _ty_args: &[TypeId], mut args: VecDeque, ) -> SafeNativeResult> { debug_assert!(args.len() == 3); @@ -124,7 +124,7 @@ fn native_sub_string( **************************************************************************************************/ fn native_index_of( context: &mut SafeNativeContext, - _ty_args: Vec, + _ty_args: &[TypeId], mut args: VecDeque, ) -> SafeNativeResult> { debug_assert!(args.len() == 2); diff --git a/aptos-move/framework/move-stdlib/src/natives/unit_test.rs b/aptos-move/framework/move-stdlib/src/natives/unit_test.rs index 6ce5045be3dc2..255518ba9dde3 100644 --- a/aptos-move/framework/move-stdlib/src/natives/unit_test.rs +++ b/aptos-move/framework/move-stdlib/src/natives/unit_test.rs @@ -10,7 +10,7 @@ use aptos_native_interface::{ }; use move_core_types::account_address::AccountAddress; use move_vm_runtime::native_functions::NativeFunction; -use move_vm_types::{loaded_data::runtime_types::Type, values::Value}; +use move_vm_types::{ty_interner::TypeId, values::Value}; use smallvec::{smallvec, SmallVec}; use std::collections::VecDeque; @@ -29,7 +29,7 @@ fn to_le_bytes(i: u64) -> [u8; AccountAddress::LENGTH] { fn native_create_signers_for_testing( _context: &mut SafeNativeContext, - ty_args: Vec, + ty_args: &[TypeId], mut args: VecDeque, ) -> SafeNativeResult> { debug_assert!(ty_args.is_empty()); diff --git a/aptos-move/framework/move-stdlib/src/natives/vector.rs b/aptos-move/framework/move-stdlib/src/natives/vector.rs index edb15ad0f79be..c9cb4229688ec 100644 --- a/aptos-move/framework/move-stdlib/src/natives/vector.rs +++ b/aptos-move/framework/move-stdlib/src/natives/vector.rs @@ -18,7 +18,7 @@ use aptos_types::error; use move_core_types::gas_algebra::NumArgs; use move_vm_runtime::native_functions::NativeFunction; use move_vm_types::{ - loaded_data::runtime_types::Type, + ty_interner::TypeId, values::{Value, VectorRef}, }; use smallvec::{smallvec, SmallVec}; @@ -38,7 +38,7 @@ pub const EFEATURE_NOT_ENABLED: u64 = 2; **************************************************************************************************/ fn native_move_range( context: &mut SafeNativeContext, - ty_args: Vec, + ty_args: &[TypeId], mut args: VecDeque, ) -> SafeNativeResult> { if !context @@ -98,7 +98,7 @@ fn native_move_range( length, &to, insert_position, - &ty_args[0], + ty_args[0], )?; Ok(smallvec![]) diff --git a/aptos-move/framework/src/natives/account.rs b/aptos-move/framework/src/natives/account.rs index 163ca71f00864..911246837c5ad 100644 --- a/aptos-move/framework/src/natives/account.rs +++ b/aptos-move/framework/src/natives/account.rs @@ -10,7 +10,7 @@ use aptos_native_interface::{ }; use move_core_types::{account_address::AccountAddress, gas_algebra::InternalGas}; use move_vm_runtime::native_functions::NativeFunction; -use move_vm_types::{loaded_data::runtime_types::Type, values::Value}; +use move_vm_types::{ty_interner::TypeId, values::Value}; use smallvec::{smallvec, SmallVec}; use std::collections::VecDeque; @@ -27,7 +27,7 @@ pub struct CreateAddressGasParameters { fn native_create_address( context: &mut SafeNativeContext, - ty_args: Vec, + ty_args: &[TypeId], mut arguments: VecDeque, ) -> SafeNativeResult> { debug_assert!(ty_args.is_empty()); diff --git a/aptos-move/framework/src/natives/account_abstraction.rs b/aptos-move/framework/src/natives/account_abstraction.rs index c236fafb9a2ef..79a3860648831 100644 --- a/aptos-move/framework/src/natives/account_abstraction.rs +++ b/aptos-move/framework/src/natives/account_abstraction.rs @@ -7,7 +7,7 @@ use aptos_native_interface::{ RawSafeNative, SafeNativeBuilder, SafeNativeContext, SafeNativeError, SafeNativeResult, }; use move_vm_runtime::native_functions::NativeFunction; -use move_vm_types::{loaded_data::runtime_types::Type, values::Value}; +use move_vm_types::{ty_interner::TypeId, values::Value}; use smallvec::SmallVec; use std::collections::VecDeque; @@ -21,7 +21,7 @@ use std::collections::VecDeque; **************************************************************************************************/ pub(crate) fn native_dispatch( context: &mut SafeNativeContext, - ty_args: Vec, + ty_args: &[TypeId], mut arguments: VecDeque, ) -> SafeNativeResult> { let (module_name, func_name) = extract_function_info(&mut arguments)?; @@ -38,7 +38,7 @@ pub(crate) fn native_dispatch( Err(SafeNativeError::FunctionDispatch { module_name, func_name, - ty_args, + ty_args: ty_args.to_vec(), args: arguments.into_iter().collect(), }) } diff --git a/aptos-move/framework/src/natives/aggregator_natives/aggregator.rs b/aptos-move/framework/src/natives/aggregator_natives/aggregator.rs index 628fc7f591730..29556e2bac5d1 100644 --- a/aptos-move/framework/src/natives/aggregator_natives/aggregator.rs +++ b/aptos-move/framework/src/natives/aggregator_natives/aggregator.rs @@ -12,7 +12,7 @@ use aptos_native_interface::{ }; use move_vm_runtime::native_functions::NativeFunction; use move_vm_types::{ - loaded_data::runtime_types::Type, + ty_interner::TypeId, values::{Struct, StructRef, Value}, }; use smallvec::{smallvec, SmallVec}; @@ -26,7 +26,7 @@ use std::collections::VecDeque; **************************************************************************************************/ fn native_add( context: &mut SafeNativeContext, - _ty_args: Vec, + _ty_args: &[TypeId], mut args: VecDeque, ) -> SafeNativeResult> { debug_assert_eq!(args.len(), 2); @@ -55,7 +55,7 @@ fn native_add( **************************************************************************************************/ fn native_read( context: &mut SafeNativeContext, - _ty_args: Vec, + _ty_args: &[TypeId], mut args: VecDeque, ) -> SafeNativeResult> { debug_assert_eq!(args.len(), 1); @@ -84,7 +84,7 @@ fn native_read( fn native_sub( context: &mut SafeNativeContext, - _ty_args: Vec, + _ty_args: &[TypeId], mut args: VecDeque, ) -> SafeNativeResult> { debug_assert_eq!(args.len(), 2); @@ -113,7 +113,7 @@ fn native_sub( **************************************************************************************************/ fn native_destroy( context: &mut SafeNativeContext, - _ty_args: Vec, + _ty_args: &[TypeId], mut args: VecDeque, ) -> SafeNativeResult> { debug_assert_eq!(args.len(), 1); diff --git a/aptos-move/framework/src/natives/aggregator_natives/aggregator_factory.rs b/aptos-move/framework/src/natives/aggregator_natives/aggregator_factory.rs index ff7b2695c4bda..191aa85369949 100644 --- a/aptos-move/framework/src/natives/aggregator_natives/aggregator_factory.rs +++ b/aptos-move/framework/src/natives/aggregator_natives/aggregator_factory.rs @@ -14,7 +14,7 @@ use move_binary_format::errors::PartialVMError; use move_core_types::vm_status::StatusCode; use move_vm_runtime::native_functions::NativeFunction; use move_vm_types::{ - loaded_data::runtime_types::Type, + ty_interner::TypeId, values::{Struct, StructRef, Value}, }; use smallvec::{smallvec, SmallVec}; @@ -28,7 +28,7 @@ use std::collections::VecDeque; **************************************************************************************************/ fn native_new_aggregator( context: &mut SafeNativeContext, - _ty_args: Vec, + _ty_args: &[TypeId], mut args: VecDeque, ) -> SafeNativeResult> { debug_assert_eq!(args.len(), 2); diff --git a/aptos-move/framework/src/natives/aggregator_natives/aggregator_v2.rs b/aptos-move/framework/src/natives/aggregator_natives/aggregator_v2.rs index 6de952539f0c7..60f88e939999f 100644 --- a/aptos-move/framework/src/natives/aggregator_natives/aggregator_v2.rs +++ b/aptos-move/framework/src/natives/aggregator_natives/aggregator_v2.rs @@ -29,7 +29,7 @@ use move_vm_types::{ bytes_and_width_to_derived_string_struct, string_to_bytes, u128_to_u64, }, }, - loaded_data::runtime_types::Type, + ty_interner::TypeId, values::{Reference, Struct, StructRef, Value}, }; use smallvec::{smallvec, SmallVec}; @@ -53,10 +53,10 @@ pub const EAGGREGATOR_FUNCTION_NOT_YET_SUPPORTED: u64 = 0x03_0009; /// If we want to increase this, we need to modify BITS_FOR_SIZE in types/src/delayed_fields.rs. pub const DERIVED_STRING_INPUT_MAX_LENGTH: usize = 1024; -fn get_width_by_type(ty_arg: &Type, error_code_if_incorrect: u64) -> SafeNativeResult { +fn get_width_by_type(ty_arg: TypeId, error_code_if_incorrect: u64) -> SafeNativeResult { match ty_arg { - Type::U128 => Ok(16), - Type::U64 => Ok(8), + TypeId::U128 => Ok(16), + TypeId::U64 => Ok(8), _ => Err(SafeNativeError::Abort { abort_code: error_code_if_incorrect, }), @@ -65,13 +65,13 @@ fn get_width_by_type(ty_arg: &Type, error_code_if_incorrect: u64) -> SafeNativeR /// Given the list of native function arguments and a type, pop the next argument if it is of given type. fn pop_value_by_type( - ty_arg: &Type, + ty_arg: TypeId, args: &mut VecDeque, error_code_if_incorrect: u64, ) -> SafeNativeResult { match ty_arg { - Type::U128 => Ok(safely_pop_arg!(args, u128)), - Type::U64 => Ok(safely_pop_arg!(args, u64) as u128), + TypeId::U128 => Ok(safely_pop_arg!(args, u128)), + TypeId::U64 => Ok(safely_pop_arg!(args, u64) as u128), _ => Err(SafeNativeError::Abort { abort_code: error_code_if_incorrect, }), @@ -79,13 +79,13 @@ fn pop_value_by_type( } fn create_value_by_type( - value_ty: &Type, + value_ty: TypeId, value: u128, error_code_if_incorrect: u64, ) -> SafeNativeResult { match value_ty { - Type::U128 => Ok(Value::u128(value)), - Type::U64 => Ok(Value::u64(u128_to_u64(value)?)), + TypeId::U128 => Ok(Value::u128(value)), + TypeId::U64 => Ok(Value::u64(u128_to_u64(value)?)), _ => Err(SafeNativeError::Abort { abort_code: error_code_if_incorrect, }), @@ -112,7 +112,7 @@ fn get_context_data<'t, 'b>( fn create_aggregator_with_max_value( context: &mut SafeNativeContext, - aggregator_value_ty: &Type, + aggregator_value_ty: TypeId, max_value: u128, ) -> SafeNativeResult> { let value = if let Some((resolver, mut delayed_field_data)) = get_context_data(context) { @@ -137,15 +137,15 @@ fn create_aggregator_with_max_value( fn native_create_aggregator( context: &mut SafeNativeContext, - ty_args: Vec, + ty_args: &[TypeId], mut args: VecDeque, ) -> SafeNativeResult> { debug_assert_eq!(args.len(), 1); debug_assert_eq!(ty_args.len(), 1); context.charge(AGGREGATOR_V2_CREATE_AGGREGATOR_BASE)?; - let max_value = pop_value_by_type(&ty_args[0], &mut args, EUNSUPPORTED_AGGREGATOR_TYPE)?; - create_aggregator_with_max_value(context, &ty_args[0], max_value) + let max_value = pop_value_by_type(ty_args[0], &mut args, EUNSUPPORTED_AGGREGATOR_TYPE)?; + create_aggregator_with_max_value(context, ty_args[0], max_value) } /*************************************************************************************************** @@ -154,15 +154,16 @@ fn native_create_aggregator( fn native_create_unbounded_aggregator( context: &mut SafeNativeContext, - ty_args: Vec, + ty_args: &[TypeId], args: VecDeque, ) -> SafeNativeResult> { debug_assert_eq!(args.len(), 0); debug_assert_eq!(ty_args.len(), 1); context.charge(AGGREGATOR_V2_CREATE_AGGREGATOR_BASE)?; - let max_value = unbounded_aggregator_max_value(&ty_args[0])?; - create_aggregator_with_max_value(context, &ty_args[0], max_value) + let ty = ty_args[0]; + let max_value = unbounded_aggregator_max_value(ty)?; + create_aggregator_with_max_value(context, ty, max_value) } /*************************************************************************************************** @@ -170,14 +171,14 @@ fn native_create_unbounded_aggregator( **************************************************************************************************/ fn native_try_add( context: &mut SafeNativeContext, - ty_args: Vec, + ty_args: &[TypeId], mut args: VecDeque, ) -> SafeNativeResult> { debug_assert_eq!(args.len(), 2); debug_assert_eq!(ty_args.len(), 1); context.charge(AGGREGATOR_V2_TRY_ADD_BASE)?; - let aggregator_value_ty = &ty_args[0]; + let aggregator_value_ty = ty_args[0]; let rhs = pop_value_by_type(aggregator_value_ty, &mut args, EUNSUPPORTED_AGGREGATOR_TYPE)?; let aggregator = safely_pop_arg!(args, StructRef); @@ -216,14 +217,14 @@ fn native_try_add( **************************************************************************************************/ fn native_try_sub( context: &mut SafeNativeContext, - ty_args: Vec, + ty_args: &[TypeId], mut args: VecDeque, ) -> SafeNativeResult> { debug_assert_eq!(args.len(), 2); debug_assert_eq!(ty_args.len(), 1); context.charge(AGGREGATOR_V2_TRY_SUB_BASE)?; - let aggregator_value_ty = &ty_args[0]; + let aggregator_value_ty = ty_args[0]; let rhs = pop_value_by_type(aggregator_value_ty, &mut args, EUNSUPPORTED_AGGREGATOR_TYPE)?; let aggregator = safely_pop_arg!(args, StructRef); @@ -259,14 +260,14 @@ fn native_try_sub( fn native_is_at_least_impl( context: &mut SafeNativeContext, - ty_args: Vec, + ty_args: &[TypeId], mut args: VecDeque, ) -> SafeNativeResult> { debug_assert_eq!(args.len(), 2); debug_assert_eq!(ty_args.len(), 1); context.charge(AGGREGATOR_V2_IS_AT_LEAST_BASE)?; - let aggregator_value_ty = &ty_args[0]; + let aggregator_value_ty = ty_args[0]; let rhs = pop_value_by_type(aggregator_value_ty, &mut args, EUNSUPPORTED_AGGREGATOR_TYPE)?; let aggregator = safely_pop_arg!(args, StructRef); @@ -297,14 +298,14 @@ fn native_is_at_least_impl( fn native_read( context: &mut SafeNativeContext, - ty_args: Vec, + ty_args: &[TypeId], mut args: VecDeque, ) -> SafeNativeResult> { debug_assert_eq!(args.len(), 1); debug_assert_eq!(ty_args.len(), 1); context.charge(AGGREGATOR_V2_READ_BASE)?; - let aggregator_value_ty = &ty_args[0]; + let aggregator_value_ty = ty_args[0]; let aggregator = safely_pop_arg!(args, StructRef); let value = if let Some((resolver, delayed_field_data)) = get_context_data(context) { @@ -333,14 +334,14 @@ fn native_read( fn native_snapshot( context: &mut SafeNativeContext, - ty_args: Vec, + ty_args: &[TypeId], mut args: VecDeque, ) -> SafeNativeResult> { debug_assert_eq!(args.len(), 1); debug_assert_eq!(ty_args.len(), 1); context.charge(AGGREGATOR_V2_SNAPSHOT_BASE)?; - let aggregator_value_ty = &ty_args[0]; + let aggregator_value_ty = ty_args[0]; let aggregator = safely_pop_arg!(args, StructRef); let result_value = if let Some((resolver, mut delayed_field_data)) = get_context_data(context) { @@ -368,14 +369,14 @@ fn native_snapshot( fn native_create_snapshot( context: &mut SafeNativeContext, - ty_args: Vec, + ty_args: &[TypeId], mut args: VecDeque, ) -> SafeNativeResult> { debug_assert_eq!(ty_args.len(), 1); debug_assert_eq!(args.len(), 1); context.charge(AGGREGATOR_V2_CREATE_SNAPSHOT_BASE)?; - let snapshot_value_ty = &ty_args[0]; + let snapshot_value_ty = ty_args[0]; let value = pop_value_by_type( snapshot_value_ty, &mut args, @@ -406,7 +407,7 @@ fn native_create_snapshot( fn native_copy_snapshot( _context: &mut SafeNativeContext, - _ty_args: Vec, + _ty_args: &[TypeId], _args: VecDeque, ) -> SafeNativeResult> { Err(SafeNativeError::Abort { @@ -420,14 +421,14 @@ fn native_copy_snapshot( fn native_read_snapshot( context: &mut SafeNativeContext, - ty_args: Vec, + ty_args: &[TypeId], mut args: VecDeque, ) -> SafeNativeResult> { debug_assert_eq!(ty_args.len(), 1); debug_assert_eq!(args.len(), 1); context.charge(AGGREGATOR_V2_READ_SNAPSHOT_BASE)?; - let snapshot_value_ty = &ty_args[0]; + let snapshot_value_ty = ty_args[0]; let snapshot = safely_pop_arg!(args, StructRef); let result_value = if let Some((resolver, mut delayed_field_data)) = get_context_data(context) { @@ -449,7 +450,7 @@ fn native_read_snapshot( **************************************************************************************************/ fn native_string_concat( _context: &mut SafeNativeContext, - _ty_args: Vec, + _ty_args: &[TypeId], _args: VecDeque, ) -> SafeNativeResult> { // Deprecated function in favor of `derive_string_concat`. @@ -464,7 +465,7 @@ fn native_string_concat( fn native_read_derived_string( context: &mut SafeNativeContext, - ty_args: Vec, + ty_args: &[TypeId], mut args: VecDeque, ) -> SafeNativeResult> { debug_assert_eq!(ty_args.len(), 0); @@ -489,7 +490,7 @@ fn native_read_derived_string( fn native_create_derived_string( context: &mut SafeNativeContext, - ty_args: Vec, + ty_args: &[TypeId], mut args: VecDeque, ) -> SafeNativeResult> { debug_assert_eq!(ty_args.len(), 0); @@ -530,7 +531,7 @@ fn native_create_derived_string( fn native_derive_string_concat( context: &mut SafeNativeContext, - ty_args: Vec, + ty_args: &[TypeId], mut args: VecDeque, ) -> SafeNativeResult> { debug_assert_eq!(ty_args.len(), 1); @@ -542,7 +543,7 @@ fn native_derive_string_concat( .map_err(SafeNativeError::InvariantViolation)?; context.charge(AGGREGATOR_V2_STRING_CONCAT_PER_BYTE * NumBytes::new(suffix.len() as u64))?; - let snapshot_value_ty = &ty_args[0]; + let snapshot_value_ty = ty_args[0]; let snapshot = safely_pop_arg!(args, StructRef); let prefix = string_to_bytes(safely_pop_arg!(args, Struct)) diff --git a/aptos-move/framework/src/natives/aggregator_natives/helpers_v2.rs b/aptos-move/framework/src/natives/aggregator_natives/helpers_v2.rs index 2abc9cc46828a..2600fdacf8ba1 100644 --- a/aptos-move/framework/src/natives/aggregator_natives/helpers_v2.rs +++ b/aptos-move/framework/src/natives/aggregator_natives/helpers_v2.rs @@ -9,7 +9,7 @@ use aptos_native_interface::{safely_get_struct_field_as, SafeNativeError, SafeNa use move_binary_format::errors::PartialVMError; use move_vm_types::{ delayed_values::{delayed_field_id::DelayedFieldID, derived_string_snapshot::string_to_bytes}, - loaded_data::runtime_types::Type, + ty_interner::TypeId, values::{Reference, Struct, StructRef, Value}, }; @@ -26,10 +26,10 @@ const _DERIVED_STRING_SNAPSHOT_PADDING_FIELD_INDEX: usize = 1; macro_rules! get_value_impl { ($func_name:ident, $idx:expr, $e:expr) => { - pub(crate) fn $func_name(struct_ref: &StructRef, ty: &Type) -> SafeNativeResult { + pub(crate) fn $func_name(struct_ref: &StructRef, ty: TypeId) -> SafeNativeResult { Ok(match ty { - Type::U128 => safely_get_struct_field_as!(struct_ref, $idx, u128), - Type::U64 => safely_get_struct_field_as!(struct_ref, $idx, u64) as u128, + TypeId::U128 => safely_get_struct_field_as!(struct_ref, $idx, u128), + TypeId::U64 => safely_get_struct_field_as!(struct_ref, $idx, u64) as u128, _ => return Err(SafeNativeError::Abort { abort_code: $e }), }) } @@ -58,11 +58,11 @@ macro_rules! get_value_as_id_impl { ($func_name:ident, $idx:expr, $e:expr) => { pub(crate) fn $func_name( struct_ref: &StructRef, - ty: &Type, + ty: TypeId, resolver: &dyn DelayedFieldResolver, ) -> SafeNativeResult { let id = match ty { - Type::U64 | Type::U128 => { + TypeId::U64 | TypeId::U128 => { safely_get_struct_field_as!(struct_ref, $idx, DelayedFieldID) }, _ => return Err(SafeNativeError::Abort { abort_code: $e }), @@ -100,10 +100,10 @@ pub(crate) fn set_aggregator_value(aggregator: &StructRef, value: Value) -> Safe .map_err(SafeNativeError::InvariantViolation) } -pub(crate) fn unbounded_aggregator_max_value(ty: &Type) -> SafeNativeResult { +pub(crate) fn unbounded_aggregator_max_value(ty: TypeId) -> SafeNativeResult { Ok(match ty { - Type::U128 => u128::MAX, - Type::U64 => u64::MAX as u128, + TypeId::U128 => u128::MAX, + TypeId::U64 => u64::MAX as u128, _ => { return Err(SafeNativeError::Abort { abort_code: EUNSUPPORTED_AGGREGATOR_TYPE, diff --git a/aptos-move/framework/src/natives/code.rs b/aptos-move/framework/src/natives/code.rs index 08fdcc2d29cad..d79ef5e78850c 100644 --- a/aptos-move/framework/src/natives/code.rs +++ b/aptos-move/framework/src/natives/code.rs @@ -16,7 +16,7 @@ use move_binary_format::errors::{PartialVMError, PartialVMResult}; use move_core_types::{account_address::AccountAddress, gas_algebra::NumBytes}; use move_vm_runtime::{native_extensions::SessionListener, native_functions::NativeFunction}; use move_vm_types::{ - loaded_data::runtime_types::Type, + ty_interner::TypeId, values::{Struct, Value}, }; use serde::{Deserialize, Serialize}; @@ -263,7 +263,7 @@ fn unpack_allowed_dep(v: Value) -> PartialVMResult<(AccountAddress, String)> { **************************************************************************************************/ fn native_request_publish( context: &mut SafeNativeContext, - _ty_args: Vec, + _ty_args: &[TypeId], mut args: VecDeque, ) -> SafeNativeResult> { debug_assert!(matches!(args.len(), 4 | 5)); diff --git a/aptos-move/framework/src/natives/consensus_config.rs b/aptos-move/framework/src/natives/consensus_config.rs index 2cccebf7f6691..d44c4be51eacf 100644 --- a/aptos-move/framework/src/natives/consensus_config.rs +++ b/aptos-move/framework/src/natives/consensus_config.rs @@ -6,13 +6,13 @@ use aptos_native_interface::{ }; use aptos_types::on_chain_config::OnChainConsensusConfig; use move_vm_runtime::native_functions::NativeFunction; -use move_vm_types::{loaded_data::runtime_types::Type, values::Value}; +use move_vm_types::{ty_interner::TypeId, values::Value}; use smallvec::{smallvec, SmallVec}; use std::collections::VecDeque; pub fn validator_txn_enabled( _context: &mut SafeNativeContext, - _ty_args: Vec, + _ty_args: &[TypeId], mut args: VecDeque, ) -> SafeNativeResult> { let config_bytes = safely_pop_arg!(args, Vec); diff --git a/aptos-move/framework/src/natives/create_signer.rs b/aptos-move/framework/src/natives/create_signer.rs index 6ba6f79b578d9..5e0a691ea4173 100644 --- a/aptos-move/framework/src/natives/create_signer.rs +++ b/aptos-move/framework/src/natives/create_signer.rs @@ -7,7 +7,7 @@ use aptos_native_interface::{ }; use move_core_types::account_address::AccountAddress; use move_vm_runtime::native_functions::NativeFunction; -use move_vm_types::{loaded_data::runtime_types::Type, values::Value}; +use move_vm_types::{ty_interner::TypeId, values::Value}; use smallvec::{smallvec, SmallVec}; use std::collections::VecDeque; @@ -19,7 +19,7 @@ use std::collections::VecDeque; **************************************************************************************************/ pub(crate) fn native_create_signer( context: &mut SafeNativeContext, - ty_args: Vec, + ty_args: &[TypeId], mut arguments: VecDeque, ) -> SafeNativeResult> { debug_assert!(ty_args.is_empty()); diff --git a/aptos-move/framework/src/natives/cryptography/algebra/arithmetics/add.rs b/aptos-move/framework/src/natives/cryptography/algebra/arithmetics/add.rs index 60e422e73dd97..d8b3c83962289 100644 --- a/aptos-move/framework/src/natives/cryptography/algebra/arithmetics/add.rs +++ b/aptos-move/framework/src/natives/cryptography/algebra/arithmetics/add.rs @@ -12,7 +12,7 @@ use crate::{ }; use aptos_gas_schedule::gas_params::natives::aptos_framework::*; use aptos_native_interface::{SafeNativeContext, SafeNativeError, SafeNativeResult}; -use move_vm_types::{loaded_data::runtime_types::Type, values::Value}; +use move_vm_types::{ty_interner::TypeId, values::Value}; use smallvec::{smallvec, SmallVec}; use std::{ collections::VecDeque, @@ -22,11 +22,11 @@ use std::{ pub fn add_internal( context: &mut SafeNativeContext, - ty_args: Vec, + ty_args: &[TypeId], mut args: VecDeque, ) -> SafeNativeResult> { assert_eq!(1, ty_args.len()); - let structure_opt = structure_from_ty_arg!(context, &ty_args[0]); + let structure_opt = structure_from_ty_arg!(context, ty_args[0]); abort_unless_arithmetics_enabled_for_structure!(context, structure_opt); match structure_opt { Some(Structure::BLS12381Fr) => ark_binary_op_internal!( diff --git a/aptos-move/framework/src/natives/cryptography/algebra/arithmetics/div.rs b/aptos-move/framework/src/natives/cryptography/algebra/arithmetics/div.rs index 439979e0b53b9..278de622f13fc 100644 --- a/aptos-move/framework/src/natives/cryptography/algebra/arithmetics/div.rs +++ b/aptos-move/framework/src/natives/cryptography/algebra/arithmetics/div.rs @@ -13,7 +13,7 @@ use aptos_gas_schedule::gas_params::natives::aptos_framework::*; use aptos_native_interface::{ safely_pop_arg, SafeNativeContext, SafeNativeError, SafeNativeResult, }; -use move_vm_types::{loaded_data::runtime_types::Type, values::Value}; +use move_vm_types::{ty_interner::TypeId, values::Value}; use num_traits::Zero; use smallvec::{smallvec, SmallVec}; use std::{collections::VecDeque, ops::Div, rc::Rc}; @@ -37,11 +37,11 @@ macro_rules! ark_div_internal { pub fn div_internal( context: &mut SafeNativeContext, - ty_args: Vec, + ty_args: &[TypeId], mut args: VecDeque, ) -> SafeNativeResult> { assert_eq!(1, ty_args.len()); - let structure_opt = structure_from_ty_arg!(context, &ty_args[0]); + let structure_opt = structure_from_ty_arg!(context, ty_args[0]); abort_unless_arithmetics_enabled_for_structure!(context, structure_opt); match structure_opt { Some(Structure::BLS12381Fr) => ark_div_internal!( diff --git a/aptos-move/framework/src/natives/cryptography/algebra/arithmetics/double.rs b/aptos-move/framework/src/natives/cryptography/algebra/arithmetics/double.rs index c7a210e834c00..eead8fc7f9908 100644 --- a/aptos-move/framework/src/natives/cryptography/algebra/arithmetics/double.rs +++ b/aptos-move/framework/src/natives/cryptography/algebra/arithmetics/double.rs @@ -13,17 +13,17 @@ use crate::{ use aptos_gas_schedule::gas_params::natives::aptos_framework::*; use aptos_native_interface::{SafeNativeContext, SafeNativeError, SafeNativeResult}; use ark_ff::{AdditiveGroup, Field}; -use move_vm_types::{loaded_data::runtime_types::Type, values::Value}; +use move_vm_types::{ty_interner::TypeId, values::Value}; use smallvec::{smallvec, SmallVec}; use std::{collections::VecDeque, rc::Rc}; pub fn double_internal( context: &mut SafeNativeContext, - ty_args: Vec, + ty_args: &[TypeId], mut args: VecDeque, ) -> SafeNativeResult> { assert_eq!(1, ty_args.len()); - let structure_opt = structure_from_ty_arg!(context, &ty_args[0]); + let structure_opt = structure_from_ty_arg!(context, ty_args[0]); abort_unless_arithmetics_enabled_for_structure!(context, structure_opt); match structure_opt { Some(Structure::BLS12381G1) => ark_unary_op_internal!( diff --git a/aptos-move/framework/src/natives/cryptography/algebra/arithmetics/inv.rs b/aptos-move/framework/src/natives/cryptography/algebra/arithmetics/inv.rs index 96d55bfce30ac..fc515889ce189 100644 --- a/aptos-move/framework/src/natives/cryptography/algebra/arithmetics/inv.rs +++ b/aptos-move/framework/src/natives/cryptography/algebra/arithmetics/inv.rs @@ -14,7 +14,7 @@ use aptos_native_interface::{ safely_pop_arg, SafeNativeContext, SafeNativeError, SafeNativeResult, }; use ark_ff::Field; -use move_vm_types::{loaded_data::runtime_types::Type, values::Value}; +use move_vm_types::{ty_interner::TypeId, values::Value}; use smallvec::{smallvec, SmallVec}; use std::{collections::VecDeque, rc::Rc}; @@ -35,10 +35,10 @@ macro_rules! ark_inverse_internal { pub fn inv_internal( context: &mut SafeNativeContext, - ty_args: Vec, + ty_args: &[TypeId], mut args: VecDeque, ) -> SafeNativeResult> { - let structure_opt = structure_from_ty_arg!(context, &ty_args[0]); + let structure_opt = structure_from_ty_arg!(context, ty_args[0]); abort_unless_arithmetics_enabled_for_structure!(context, structure_opt); match structure_opt { Some(Structure::BLS12381Fr) => ark_inverse_internal!( diff --git a/aptos-move/framework/src/natives/cryptography/algebra/arithmetics/mul.rs b/aptos-move/framework/src/natives/cryptography/algebra/arithmetics/mul.rs index 3d56b6d6d735f..32838aca6a977 100644 --- a/aptos-move/framework/src/natives/cryptography/algebra/arithmetics/mul.rs +++ b/aptos-move/framework/src/natives/cryptography/algebra/arithmetics/mul.rs @@ -12,17 +12,17 @@ use crate::{ }; use aptos_gas_schedule::gas_params::natives::aptos_framework::*; use aptos_native_interface::{SafeNativeContext, SafeNativeError, SafeNativeResult}; -use move_vm_types::{loaded_data::runtime_types::Type, values::Value}; +use move_vm_types::{ty_interner::TypeId, values::Value}; use smallvec::{smallvec, SmallVec}; use std::{collections::VecDeque, ops::Mul, rc::Rc}; pub fn mul_internal( context: &mut SafeNativeContext, - ty_args: Vec, + ty_args: &[TypeId], mut args: VecDeque, ) -> SafeNativeResult> { assert_eq!(1, ty_args.len()); - let structure_opt = structure_from_ty_arg!(context, &ty_args[0]); + let structure_opt = structure_from_ty_arg!(context, ty_args[0]); abort_unless_arithmetics_enabled_for_structure!(context, structure_opt); match structure_opt { Some(Structure::BLS12381Fr) => ark_binary_op_internal!( diff --git a/aptos-move/framework/src/natives/cryptography/algebra/arithmetics/neg.rs b/aptos-move/framework/src/natives/cryptography/algebra/arithmetics/neg.rs index f0af2be66252b..be7479cf2844c 100644 --- a/aptos-move/framework/src/natives/cryptography/algebra/arithmetics/neg.rs +++ b/aptos-move/framework/src/natives/cryptography/algebra/arithmetics/neg.rs @@ -15,17 +15,17 @@ use aptos_native_interface::{ safely_pop_arg, SafeNativeContext, SafeNativeError, SafeNativeResult, }; use ark_ff::Field; -use move_vm_types::{loaded_data::runtime_types::Type, values::Value}; +use move_vm_types::{ty_interner::TypeId, values::Value}; use smallvec::{smallvec, SmallVec}; use std::{collections::VecDeque, ops::Neg, rc::Rc}; pub fn neg_internal( context: &mut SafeNativeContext, - ty_args: Vec, + ty_args: &[TypeId], mut args: VecDeque, ) -> SafeNativeResult> { assert_eq!(1, ty_args.len()); - let structure_opt = structure_from_ty_arg!(context, &ty_args[0]); + let structure_opt = structure_from_ty_arg!(context, ty_args[0]); abort_unless_arithmetics_enabled_for_structure!(context, structure_opt); match structure_opt { Some(Structure::BLS12381Fr) => ark_unary_op_internal!( diff --git a/aptos-move/framework/src/natives/cryptography/algebra/arithmetics/scalar_mul.rs b/aptos-move/framework/src/natives/cryptography/algebra/arithmetics/scalar_mul.rs index 0cb4a51a6b7cb..e96a29d1a4a4d 100644 --- a/aptos-move/framework/src/natives/cryptography/algebra/arithmetics/scalar_mul.rs +++ b/aptos-move/framework/src/natives/cryptography/algebra/arithmetics/scalar_mul.rs @@ -22,7 +22,7 @@ use aptos_types::on_chain_config::FeatureFlag; use ark_ec::{CurveGroup, PrimeGroup}; use ark_ff::Field; use move_core_types::gas_algebra::NumArgs; -use move_vm_types::{loaded_data::runtime_types::Type, values::Value}; +use move_vm_types::{ty_interner::TypeId, values::Value}; use smallvec::{smallvec, SmallVec}; use std::{collections::VecDeque, rc::Rc}; @@ -90,12 +90,12 @@ macro_rules! ark_msm_bigint_wnaf_cost { pub fn scalar_mul_internal( context: &mut SafeNativeContext, - ty_args: Vec, + ty_args: &[TypeId], mut args: VecDeque, ) -> SafeNativeResult> { assert_eq!(2, ty_args.len()); - let group_opt = structure_from_ty_arg!(context, &ty_args[0]); - let scalar_field_opt = structure_from_ty_arg!(context, &ty_args[1]); + let group_opt = structure_from_ty_arg!(context, ty_args[0]); + let scalar_field_opt = structure_from_ty_arg!(context, ty_args[1]); abort_unless_group_scalar_mul_enabled!(context, group_opt, scalar_field_opt); match (group_opt, scalar_field_opt) { (Some(Structure::BLS12381G1), Some(Structure::BLS12381Fr)) => { @@ -234,12 +234,12 @@ macro_rules! ark_msm_internal { pub fn multi_scalar_mul_internal( context: &mut SafeNativeContext, - ty_args: Vec, + ty_args: &[TypeId], mut args: VecDeque, ) -> SafeNativeResult> { assert_eq!(2, ty_args.len()); - let structure_opt = structure_from_ty_arg!(context, &ty_args[0]); - let scalar_opt = structure_from_ty_arg!(context, &ty_args[1]); + let structure_opt = structure_from_ty_arg!(context, ty_args[0]); + let scalar_opt = structure_from_ty_arg!(context, ty_args[1]); abort_unless_group_scalar_mul_enabled!(context, structure_opt, scalar_opt); match (structure_opt, scalar_opt) { (Some(Structure::BLS12381G1), Some(Structure::BLS12381Fr)) => { diff --git a/aptos-move/framework/src/natives/cryptography/algebra/arithmetics/sqr.rs b/aptos-move/framework/src/natives/cryptography/algebra/arithmetics/sqr.rs index d5ffab5ef589d..fd9e5add9e180 100644 --- a/aptos-move/framework/src/natives/cryptography/algebra/arithmetics/sqr.rs +++ b/aptos-move/framework/src/natives/cryptography/algebra/arithmetics/sqr.rs @@ -13,16 +13,16 @@ use crate::{ use aptos_gas_schedule::gas_params::natives::aptos_framework::*; use aptos_native_interface::{SafeNativeContext, SafeNativeError, SafeNativeResult}; use ark_ff::Field; -use move_vm_types::{loaded_data::runtime_types::Type, values::Value}; +use move_vm_types::{ty_interner::TypeId, values::Value}; use smallvec::{smallvec, SmallVec}; use std::{collections::VecDeque, rc::Rc}; pub fn sqr_internal( context: &mut SafeNativeContext, - ty_args: Vec, + ty_args: &[TypeId], mut args: VecDeque, ) -> SafeNativeResult> { - let structure_opt = structure_from_ty_arg!(context, &ty_args[0]); + let structure_opt = structure_from_ty_arg!(context, ty_args[0]); abort_unless_arithmetics_enabled_for_structure!(context, structure_opt); match structure_opt { Some(Structure::BLS12381Fr) => ark_unary_op_internal!( diff --git a/aptos-move/framework/src/natives/cryptography/algebra/arithmetics/sub.rs b/aptos-move/framework/src/natives/cryptography/algebra/arithmetics/sub.rs index 2817d2262ca74..100254bfe1806 100644 --- a/aptos-move/framework/src/natives/cryptography/algebra/arithmetics/sub.rs +++ b/aptos-move/framework/src/natives/cryptography/algebra/arithmetics/sub.rs @@ -12,7 +12,7 @@ use crate::{ }; use aptos_gas_schedule::gas_params::natives::aptos_framework::*; use aptos_native_interface::{SafeNativeContext, SafeNativeError, SafeNativeResult}; -use move_vm_types::{loaded_data::runtime_types::Type, values::Value}; +use move_vm_types::{ty_interner::TypeId, values::Value}; use smallvec::{smallvec, SmallVec}; use std::{ collections::VecDeque, @@ -22,11 +22,11 @@ use std::{ pub fn sub_internal( context: &mut SafeNativeContext, - ty_args: Vec, + ty_args: &[TypeId], mut args: VecDeque, ) -> SafeNativeResult> { assert_eq!(1, ty_args.len()); - let structure_opt = structure_from_ty_arg!(context, &ty_args[0]); + let structure_opt = structure_from_ty_arg!(context, ty_args[0]); abort_unless_arithmetics_enabled_for_structure!(context, structure_opt); match structure_opt { Some(Structure::BLS12381Fr) => ark_binary_op_internal!( diff --git a/aptos-move/framework/src/natives/cryptography/algebra/casting.rs b/aptos-move/framework/src/natives/cryptography/algebra/casting.rs index 22a25e4ab28f4..f40e0e28a9411 100644 --- a/aptos-move/framework/src/natives/cryptography/algebra/casting.rs +++ b/aptos-move/framework/src/natives/cryptography/algebra/casting.rs @@ -15,7 +15,7 @@ use aptos_native_interface::{ }; use aptos_types::on_chain_config::FeatureFlag; use ark_ff::Field; -use move_vm_types::{loaded_data::runtime_types::Type, values::Value}; +use move_vm_types::{ty_interner::TypeId, values::Value}; use num_traits::One; use smallvec::{smallvec, SmallVec}; use std::collections::VecDeque; @@ -44,12 +44,12 @@ macro_rules! abort_unless_casting_enabled { pub fn downcast_internal( context: &mut SafeNativeContext, - ty_args: Vec, + ty_args: &[TypeId], mut args: VecDeque, ) -> SafeNativeResult> { assert_eq!(2, ty_args.len()); - let super_opt = structure_from_ty_arg!(context, &ty_args[0]); - let sub_opt = structure_from_ty_arg!(context, &ty_args[1]); + let super_opt = structure_from_ty_arg!(context, ty_args[0]); + let sub_opt = structure_from_ty_arg!(context, ty_args[1]); abort_unless_casting_enabled!(context, super_opt, sub_opt); match (super_opt, sub_opt) { (Some(Structure::BLS12381Fq12), Some(Structure::BLS12381Gt)) => { @@ -80,12 +80,12 @@ pub fn downcast_internal( pub fn upcast_internal( context: &mut SafeNativeContext, - ty_args: Vec, + ty_args: &[TypeId], mut args: VecDeque, ) -> SafeNativeResult> { assert_eq!(2, ty_args.len()); - let sub_opt = structure_from_ty_arg!(context, &ty_args[0]); - let super_opt = structure_from_ty_arg!(context, &ty_args[1]); + let sub_opt = structure_from_ty_arg!(context, ty_args[0]); + let super_opt = structure_from_ty_arg!(context, ty_args[1]); abort_unless_casting_enabled!(context, super_opt, sub_opt); match (sub_opt, super_opt) { (Some(Structure::BLS12381Gt), Some(Structure::BLS12381Fq12)) => { diff --git a/aptos-move/framework/src/natives/cryptography/algebra/constants.rs b/aptos-move/framework/src/natives/cryptography/algebra/constants.rs index 9b20b4f5d3694..d2245787ab59d 100644 --- a/aptos-move/framework/src/natives/cryptography/algebra/constants.rs +++ b/aptos-move/framework/src/natives/cryptography/algebra/constants.rs @@ -14,7 +14,7 @@ use crate::{ use aptos_gas_schedule::gas_params::natives::aptos_framework::*; use aptos_native_interface::{SafeNativeContext, SafeNativeError, SafeNativeResult}; use ark_ec::PrimeGroup; -use move_vm_types::{loaded_data::runtime_types::Type, values::Value}; +use move_vm_types::{ty_interner::TypeId, values::Value}; use num_traits::{One, Zero}; use once_cell::sync::Lazy; use smallvec::{smallvec, SmallVec}; @@ -31,10 +31,10 @@ macro_rules! ark_constant_op_internal { pub fn zero_internal( context: &mut SafeNativeContext, - ty_args: Vec, + ty_args: &[TypeId], mut _args: VecDeque, ) -> SafeNativeResult> { - let structure_opt = structure_from_ty_arg!(context, &ty_args[0]); + let structure_opt = structure_from_ty_arg!(context, ty_args[0]); abort_unless_arithmetics_enabled_for_structure!(context, structure_opt); match structure_opt { Some(Structure::BLS12381Fr) => ark_constant_op_internal!( @@ -99,10 +99,10 @@ pub fn zero_internal( pub fn one_internal( context: &mut SafeNativeContext, - ty_args: Vec, + ty_args: &[TypeId], mut _args: VecDeque, ) -> SafeNativeResult> { - let structure_opt = structure_from_ty_arg!(context, &ty_args[0]); + let structure_opt = structure_from_ty_arg!(context, ty_args[0]); abort_unless_arithmetics_enabled_for_structure!(context, structure_opt); match structure_opt { Some(Structure::BLS12381Fr) => ark_constant_op_internal!( @@ -170,11 +170,11 @@ pub fn one_internal( pub fn order_internal( context: &mut SafeNativeContext, - ty_args: Vec, - mut _args: VecDeque, + ty_args: &[TypeId], + _args: VecDeque, ) -> SafeNativeResult> { assert_eq!(1, ty_args.len()); - let structure_opt = structure_from_ty_arg!(context, &ty_args[0]); + let structure_opt = structure_from_ty_arg!(context, ty_args[0]); abort_unless_arithmetics_enabled_for_structure!(context, structure_opt); match structure_opt { Some(Structure::BLS12381Fr) diff --git a/aptos-move/framework/src/natives/cryptography/algebra/eq.rs b/aptos-move/framework/src/natives/cryptography/algebra/eq.rs index b4836720b7765..28d663cc86683 100644 --- a/aptos-move/framework/src/natives/cryptography/algebra/eq.rs +++ b/aptos-move/framework/src/natives/cryptography/algebra/eq.rs @@ -13,7 +13,7 @@ use aptos_gas_schedule::gas_params::natives::aptos_framework::*; use aptos_native_interface::{ safely_pop_arg, SafeNativeContext, SafeNativeError, SafeNativeResult, }; -use move_vm_types::{loaded_data::runtime_types::Type, values::Value}; +use move_vm_types::{ty_interner::TypeId, values::Value}; use smallvec::{smallvec, SmallVec}; use std::collections::VecDeque; @@ -31,11 +31,11 @@ macro_rules! ark_eq_internal { pub fn eq_internal( context: &mut SafeNativeContext, - ty_args: Vec, + ty_args: &[TypeId], mut args: VecDeque, ) -> SafeNativeResult> { assert_eq!(1, ty_args.len()); - let structure_opt = structure_from_ty_arg!(context, &ty_args[0]); + let structure_opt = structure_from_ty_arg!(context, ty_args[0]); abort_unless_arithmetics_enabled_for_structure!(context, structure_opt); match structure_opt { Some(Structure::BLS12381Fr) => ark_eq_internal!( diff --git a/aptos-move/framework/src/natives/cryptography/algebra/hash_to_structure.rs b/aptos-move/framework/src/natives/cryptography/algebra/hash_to_structure.rs index f8de78bb9591b..e576ba8c13724 100644 --- a/aptos-move/framework/src/natives/cryptography/algebra/hash_to_structure.rs +++ b/aptos-move/framework/src/natives/cryptography/algebra/hash_to_structure.rs @@ -18,7 +18,7 @@ use ark_ec::hashing::HashToCurve; use either::Either; use move_core_types::gas_algebra::{InternalGas, NumBytes}; use move_vm_types::{ - loaded_data::runtime_types::Type, + ty_interner::TypeId, values::{Value, VectorRef}, }; use smallvec::{smallvec, SmallVec}; @@ -80,12 +80,12 @@ macro_rules! hash_to_bls12381gx_cost { pub fn hash_to_internal( context: &mut SafeNativeContext, - ty_args: Vec, + ty_args: &[TypeId], mut args: VecDeque, ) -> SafeNativeResult> { assert_eq!(2, ty_args.len()); - let structure_opt = structure_from_ty_arg!(context, &ty_args[0]); - let suite_opt = suite_from_ty_arg!(context, &ty_args[1]); + let structure_opt = structure_from_ty_arg!(context, ty_args[0]); + let suite_opt = suite_from_ty_arg!(context, ty_args[1]); abort_unless_hash_to_structure_enabled!(context, structure_opt, suite_opt); let vector_ref = safely_pop_arg!(args, VectorRef); let bytes_ref = vector_ref.as_bytes_ref(); diff --git a/aptos-move/framework/src/natives/cryptography/algebra/new.rs b/aptos-move/framework/src/natives/cryptography/algebra/new.rs index 05050c50ed475..1e71bec4f5c80 100644 --- a/aptos-move/framework/src/natives/cryptography/algebra/new.rs +++ b/aptos-move/framework/src/natives/cryptography/algebra/new.rs @@ -13,7 +13,7 @@ use aptos_gas_schedule::gas_params::natives::aptos_framework::*; use aptos_native_interface::{ safely_pop_arg, SafeNativeContext, SafeNativeError, SafeNativeResult, }; -use move_vm_types::{loaded_data::runtime_types::Type, values::Value}; +use move_vm_types::{ty_interner::TypeId, values::Value}; use smallvec::{smallvec, SmallVec}; use std::{collections::VecDeque, rc::Rc}; @@ -29,11 +29,11 @@ macro_rules! from_u64_internal { pub fn from_u64_internal( context: &mut SafeNativeContext, - ty_args: Vec, + ty_args: &[TypeId], mut args: VecDeque, ) -> SafeNativeResult> { assert_eq!(1, ty_args.len()); - let structure_opt = structure_from_ty_arg!(context, &ty_args[0]); + let structure_opt = structure_from_ty_arg!(context, ty_args[0]); abort_unless_arithmetics_enabled_for_structure!(context, structure_opt); match structure_opt { Some(Structure::BLS12381Fr) => from_u64_internal!( diff --git a/aptos-move/framework/src/natives/cryptography/algebra/pairing.rs b/aptos-move/framework/src/natives/cryptography/algebra/pairing.rs index dafbbcd50aa4c..ef119cffde6e7 100644 --- a/aptos-move/framework/src/natives/cryptography/algebra/pairing.rs +++ b/aptos-move/framework/src/natives/cryptography/algebra/pairing.rs @@ -18,7 +18,7 @@ use aptos_native_interface::{ use aptos_types::on_chain_config::FeatureFlag; use ark_ec::{pairing::Pairing, CurveGroup}; use move_core_types::gas_algebra::NumArgs; -use move_vm_types::{loaded_data::runtime_types::Type, values::Value}; +use move_vm_types::{ty_interner::TypeId, values::Value}; use smallvec::{smallvec, SmallVec}; use std::{collections::VecDeque, rc::Rc}; @@ -127,13 +127,13 @@ macro_rules! multi_pairing_internal { } pub fn multi_pairing_internal( context: &mut SafeNativeContext, - ty_args: Vec, + ty_args: &[TypeId], mut args: VecDeque, ) -> SafeNativeResult> { assert_eq!(3, ty_args.len()); - let g1_opt = structure_from_ty_arg!(context, &ty_args[0]); - let g2_opt = structure_from_ty_arg!(context, &ty_args[1]); - let gt_opt = structure_from_ty_arg!(context, &ty_args[2]); + let g1_opt = structure_from_ty_arg!(context, ty_args[0]); + let g2_opt = structure_from_ty_arg!(context, ty_args[1]); + let gt_opt = structure_from_ty_arg!(context, ty_args[2]); abort_unless_pairing_enabled!(context, g1_opt, g2_opt, gt_opt); match (g1_opt, g2_opt, gt_opt) { (Some(Structure::BLS12381G1), Some(Structure::BLS12381G2), Some(Structure::BLS12381Gt)) => { @@ -170,13 +170,13 @@ pub fn multi_pairing_internal( pub fn pairing_internal( context: &mut SafeNativeContext, - ty_args: Vec, + ty_args: &[TypeId], mut args: VecDeque, ) -> SafeNativeResult> { assert_eq!(3, ty_args.len()); - let g1_opt = structure_from_ty_arg!(context, &ty_args[0]); - let g2_opt = structure_from_ty_arg!(context, &ty_args[1]); - let gt_opt = structure_from_ty_arg!(context, &ty_args[2]); + let g1_opt = structure_from_ty_arg!(context, ty_args[0]); + let g2_opt = structure_from_ty_arg!(context, ty_args[1]); + let gt_opt = structure_from_ty_arg!(context, ty_args[2]); abort_unless_pairing_enabled!(context, g1_opt, g2_opt, gt_opt); match (g1_opt, g2_opt, gt_opt) { (Some(Structure::BLS12381G1), Some(Structure::BLS12381G2), Some(Structure::BLS12381Gt)) => { diff --git a/aptos-move/framework/src/natives/cryptography/algebra/rand.rs b/aptos-move/framework/src/natives/cryptography/algebra/rand.rs index 79cef4eef66c3..39959801e884a 100644 --- a/aptos-move/framework/src/natives/cryptography/algebra/rand.rs +++ b/aptos-move/framework/src/natives/cryptography/algebra/rand.rs @@ -15,7 +15,7 @@ use ark_ff::Field; #[cfg(feature = "testing")] use ark_std::{test_rng, UniformRand}; #[cfg(feature = "testing")] -use move_vm_types::{loaded_data::runtime_types::Type, values::Value}; +use move_vm_types::{ty_interner::TypeId, values::Value}; #[cfg(feature = "testing")] use smallvec::{smallvec, SmallVec}; #[cfg(feature = "testing")] @@ -51,11 +51,11 @@ macro_rules! ark_rand_internal { #[cfg(feature = "testing")] pub fn rand_insecure_internal( context: &mut SafeNativeContext, - ty_args: Vec, + ty_args: &[TypeId], mut _args: VecDeque, ) -> SafeNativeResult> { assert_eq!(1, ty_args.len()); - let structure_opt = structure_from_ty_arg!(context, &ty_args[0]); + let structure_opt = structure_from_ty_arg!(context, ty_args[0]); match structure_opt { Some(Structure::BLS12381Fr) => { ark_rand_internal!(context, ark_bls12_381::Fr) diff --git a/aptos-move/framework/src/natives/cryptography/algebra/serialization.rs b/aptos-move/framework/src/natives/cryptography/algebra/serialization.rs index 19a6457f30aa1..e836be41e8065 100644 --- a/aptos-move/framework/src/natives/cryptography/algebra/serialization.rs +++ b/aptos-move/framework/src/natives/cryptography/algebra/serialization.rs @@ -21,7 +21,7 @@ use ark_ec::CurveGroup; use ark_ff::Field; use ark_serialize::{CanonicalDeserialize, CanonicalSerialize}; use move_vm_types::{ - loaded_data::runtime_types::Type, + ty_interner::TypeId, values::{Value, VectorRef}, }; use num_traits::One; @@ -124,12 +124,12 @@ macro_rules! serialize_element { pub fn serialize_internal( context: &mut SafeNativeContext, - ty_args: Vec, + ty_args: &[TypeId], mut args: VecDeque, ) -> SafeNativeResult> { assert_eq!(2, ty_args.len()); - let structure_opt = structure_from_ty_arg!(context, &ty_args[0]); - let format_opt = format_from_ty_arg!(context, &ty_args[1]); + let structure_opt = structure_from_ty_arg!(context, ty_args[0]); + let format_opt = format_from_ty_arg!(context, ty_args[1]); abort_unless_serialization_format_enabled!(context, format_opt); if let (Some(structure), Some(format)) = (structure_opt, format_opt) { serialize_element!( @@ -335,12 +335,12 @@ macro_rules! ark_ec_point_deserialize_internal { pub fn deserialize_internal( context: &mut SafeNativeContext, - ty_args: Vec, + ty_args: &[TypeId], mut args: VecDeque, ) -> SafeNativeResult> { assert_eq!(2, ty_args.len()); - let structure_opt = structure_from_ty_arg!(context, &ty_args[0]); - let format_opt = format_from_ty_arg!(context, &ty_args[1]); + let structure_opt = structure_from_ty_arg!(context, ty_args[0]); + let format_opt = format_from_ty_arg!(context, ty_args[1]); abort_unless_serialization_format_enabled!(context, format_opt); let vector_ref = safely_pop_arg!(args, VectorRef); let bytes_ref = vector_ref.as_bytes_ref(); diff --git a/aptos-move/framework/src/natives/cryptography/bls12381.rs b/aptos-move/framework/src/natives/cryptography/bls12381.rs index 891b7a51991f8..bb97a2ce50e14 100644 --- a/aptos-move/framework/src/natives/cryptography/bls12381.rs +++ b/aptos-move/framework/src/natives/cryptography/bls12381.rs @@ -20,7 +20,7 @@ use move_core_types::{ }; use move_vm_runtime::native_functions::NativeFunction; use move_vm_types::{ - loaded_data::runtime_types::Type, + ty_interner::TypeId, values::{Struct, Value}, }; #[cfg(feature = "testing")] @@ -202,7 +202,7 @@ fn signature_verify( /// failed. pub fn bls12381_verify_signature_helper( context: &mut SafeNativeContext, - _ty_args: Vec, + _ty_args: &[TypeId], mut arguments: VecDeque, check_pk_subgroup: bool, ) -> SafeNativeResult> { @@ -258,7 +258,7 @@ pub fn bls12381_verify_signature_helper( **************************************************************************************************/ fn native_bls12381_aggregate_pubkeys( context: &mut SafeNativeContext, - _ty_args: Vec, + _ty_args: &[TypeId], mut arguments: VecDeque, ) -> SafeNativeResult> { debug_assert!(_ty_args.is_empty()); @@ -314,7 +314,7 @@ fn native_bls12381_aggregate_pubkeys( **************************************************************************************************/ pub fn native_bls12381_aggregate_signatures( context: &mut SafeNativeContext, - _ty_args: Vec, + _ty_args: &[TypeId], mut arguments: VecDeque, ) -> SafeNativeResult> { debug_assert!(_ty_args.is_empty()); @@ -361,7 +361,7 @@ pub fn native_bls12381_aggregate_signatures( **************************************************************************************************/ pub fn native_bls12381_signature_subgroup_check( context: &mut SafeNativeContext, - _ty_args: Vec, + _ty_args: &[TypeId], mut arguments: VecDeque, ) -> SafeNativeResult> { debug_assert!(_ty_args.is_empty()); @@ -391,7 +391,7 @@ pub fn native_bls12381_signature_subgroup_check( **************************************************************************************************/ fn native_bls12381_validate_pubkey( context: &mut SafeNativeContext, - _ty_args: Vec, + _ty_args: &[TypeId], mut arguments: VecDeque, ) -> SafeNativeResult> { debug_assert!(_ty_args.is_empty()); @@ -442,7 +442,7 @@ fn native_bls12381_validate_pubkey( **************************************************************************************************/ pub fn native_bls12381_verify_aggregate_signature( context: &mut SafeNativeContext, - _ty_args: Vec, + _ty_args: &[TypeId], mut arguments: VecDeque, ) -> SafeNativeResult> { debug_assert!(_ty_args.is_empty()); @@ -514,7 +514,7 @@ pub fn native_bls12381_verify_aggregate_signature( **************************************************************************************************/ pub fn native_bls12381_verify_multisignature( context: &mut SafeNativeContext, - _ty_args: Vec, + _ty_args: &[TypeId], arguments: VecDeque, ) -> SafeNativeResult> { let check_pk_subgroup = false; @@ -535,7 +535,7 @@ pub fn native_bls12381_verify_multisignature( **************************************************************************************************/ pub fn native_bls12381_verify_normal_signature( context: &mut SafeNativeContext, - _ty_args: Vec, + _ty_args: &[TypeId], arguments: VecDeque, ) -> SafeNativeResult> { // For normal (non-aggregated) signatures, PK's typically don't come with PoPs and the caller @@ -557,7 +557,7 @@ pub fn native_bls12381_verify_normal_signature( **************************************************************************************************/ fn native_bls12381_verify_proof_of_possession( context: &mut SafeNativeContext, - _ty_args: Vec, + _ty_args: &[TypeId], mut arguments: VecDeque, ) -> SafeNativeResult> { debug_assert!(_ty_args.is_empty()); @@ -598,7 +598,7 @@ fn native_bls12381_verify_proof_of_possession( **************************************************************************************************/ pub fn native_bls12381_verify_signature_share( context: &mut SafeNativeContext, - _ty_args: Vec, + _ty_args: &[TypeId], arguments: VecDeque, ) -> SafeNativeResult> { // For signature shares, the caller is REQUIRED to check the PK's PoP, and thus the PK is in the @@ -610,7 +610,7 @@ pub fn native_bls12381_verify_signature_share( #[cfg(feature = "testing")] pub fn native_generate_keys( _context: &mut SafeNativeContext, - _ty_args: Vec, + _ty_args: &[TypeId], mut _arguments: VecDeque, ) -> SafeNativeResult> { let key_pair = KeyPair::::generate(&mut OsRng); @@ -623,7 +623,7 @@ pub fn native_generate_keys( #[cfg(feature = "testing")] pub fn native_sign( _context: &mut SafeNativeContext, - _ty_args: Vec, + _ty_args: &[TypeId], mut arguments: VecDeque, ) -> SafeNativeResult> { let msg = safely_pop_arg!(arguments, Vec); @@ -636,7 +636,7 @@ pub fn native_sign( #[cfg(feature = "testing")] pub fn native_generate_proof_of_possession( _context: &mut SafeNativeContext, - _ty_args: Vec, + _ty_args: &[TypeId], mut arguments: VecDeque, ) -> SafeNativeResult> { let sk_bytes = safely_pop_arg!(arguments, Vec); diff --git a/aptos-move/framework/src/natives/cryptography/bulletproofs.rs b/aptos-move/framework/src/natives/cryptography/bulletproofs.rs index 6ee5dafa5c3c2..17ac2ba2d9a35 100644 --- a/aptos-move/framework/src/natives/cryptography/bulletproofs.rs +++ b/aptos-move/framework/src/natives/cryptography/bulletproofs.rs @@ -20,7 +20,7 @@ use merlin::Transcript; use move_core_types::gas_algebra::{NumArgs, NumBytes}; use move_vm_runtime::native_functions::NativeFunction; use move_vm_types::{ - loaded_data::runtime_types::Type, + ty_interner::TypeId, values::{StructRef, Value}, }; use once_cell::sync::Lazy; @@ -66,7 +66,7 @@ static BULLETPROOF_GENERATORS: Lazy = fn native_verify_range_proof( context: &mut SafeNativeContext, - _ty_args: Vec, + _ty_args: &[TypeId], mut args: VecDeque, ) -> SafeNativeResult> { debug_assert!(_ty_args.is_empty()); @@ -106,7 +106,7 @@ fn native_verify_range_proof( fn native_verify_batch_range_proof( context: &mut SafeNativeContext, - _ty_args: Vec, + _ty_args: &[TypeId], mut args: VecDeque, ) -> SafeNativeResult> { debug_assert!(_ty_args.is_empty()); @@ -156,7 +156,7 @@ fn native_verify_batch_range_proof( /// This is a test-only native that charges zero gas. It is only exported in testing mode. fn native_test_only_prove_range( context: &mut SafeNativeContext, - _ty_args: Vec, + _ty_args: &[TypeId], mut args: VecDeque, ) -> SafeNativeResult> { debug_assert!(_ty_args.is_empty()); @@ -222,7 +222,7 @@ fn native_test_only_prove_range( /// This is a test-only native that charges zero gas. It is only exported in testing mode. fn native_test_only_batch_prove_range( context: &mut SafeNativeContext, - _ty_args: Vec, + _ty_args: &[TypeId], mut args: VecDeque, ) -> SafeNativeResult> { debug_assert!(_ty_args.is_empty()); diff --git a/aptos-move/framework/src/natives/cryptography/ed25519.rs b/aptos-move/framework/src/natives/cryptography/ed25519.rs index 1f910b94b7ae1..2b1fed9dbb5a3 100644 --- a/aptos-move/framework/src/natives/cryptography/ed25519.rs +++ b/aptos-move/framework/src/natives/cryptography/ed25519.rs @@ -17,7 +17,7 @@ use move_core_types::gas_algebra::{ InternalGas, InternalGasPerArg, InternalGasPerByte, NumArgs, NumBytes, }; use move_vm_runtime::native_functions::NativeFunction; -use move_vm_types::{loaded_data::runtime_types::Type, values::Value}; +use move_vm_types::{ty_interner::TypeId, values::Value}; #[cfg(feature = "testing")] use rand_core::OsRng; use smallvec::{smallvec, SmallVec}; @@ -38,7 +38,7 @@ pub mod abort_codes { **************************************************************************************************/ fn native_public_key_validate( context: &mut SafeNativeContext, - _ty_args: Vec, + _ty_args: &[TypeId], mut arguments: VecDeque, ) -> SafeNativeResult> { debug_assert!(_ty_args.is_empty()); @@ -95,7 +95,7 @@ fn native_public_key_validate( **************************************************************************************************/ fn native_signature_verify_strict( context: &mut SafeNativeContext, - _ty_args: Vec, + _ty_args: &[TypeId], mut arguments: VecDeque, ) -> SafeNativeResult> { debug_assert!(_ty_args.is_empty()); @@ -182,7 +182,7 @@ pub fn make_all( #[cfg(feature = "testing")] fn native_test_only_generate_keys_internal( _context: &mut SafeNativeContext, - _ty_args: Vec, + _ty_args: &[TypeId], mut _args: VecDeque, ) -> SafeNativeResult> { let key_pair = KeyPair::::generate(&mut OsRng); @@ -195,7 +195,7 @@ fn native_test_only_generate_keys_internal( #[cfg(feature = "testing")] fn native_test_only_sign_internal( _context: &mut SafeNativeContext, - _ty_args: Vec, + _ty_args: &[TypeId], mut args: VecDeque, ) -> SafeNativeResult> { let msg_bytes = safely_pop_arg!(args, Vec); diff --git a/aptos-move/framework/src/natives/cryptography/multi_ed25519.rs b/aptos-move/framework/src/natives/cryptography/multi_ed25519.rs index e3de0f4e7b074..09d51fd531155 100644 --- a/aptos-move/framework/src/natives/cryptography/multi_ed25519.rs +++ b/aptos-move/framework/src/natives/cryptography/multi_ed25519.rs @@ -20,7 +20,7 @@ use aptos_native_interface::{ use curve25519_dalek::edwards::CompressedEdwardsY; use move_core_types::gas_algebra::{NumArgs, NumBytes}; use move_vm_runtime::native_functions::NativeFunction; -use move_vm_types::{loaded_data::runtime_types::Type, values::Value}; +use move_vm_types::{ty_interner::TypeId, values::Value}; #[cfg(feature = "testing")] use rand_core::OsRng; use smallvec::{smallvec, SmallVec}; @@ -29,7 +29,7 @@ use std::{collections::VecDeque, convert::TryFrom}; /// See `public_key_validate_v2_internal` comments in `multi_ed25519.move`. fn native_public_key_validate_v2( context: &mut SafeNativeContext, - _ty_args: Vec, + _ty_args: &[TypeId], mut arguments: VecDeque, ) -> SafeNativeResult> { safely_assert_eq!(_ty_args.len(), 0); @@ -58,7 +58,7 @@ fn native_public_key_validate_v2( fn native_public_key_validate_with_gas_fix( context: &mut SafeNativeContext, - _ty_args: Vec, + _ty_args: &[TypeId], mut arguments: VecDeque, ) -> SafeNativeResult> { safely_assert_eq!(_ty_args.len(), 0); @@ -115,7 +115,7 @@ fn num_valid_subpks( fn native_signature_verify_strict( context: &mut SafeNativeContext, - _ty_args: Vec, + _ty_args: &[TypeId], mut arguments: VecDeque, ) -> SafeNativeResult> { debug_assert!(_ty_args.is_empty()); @@ -160,7 +160,7 @@ fn native_signature_verify_strict( #[cfg(feature = "testing")] fn native_generate_keys( _context: &mut SafeNativeContext, - _ty_args: Vec, + _ty_args: &[TypeId], mut arguments: VecDeque, ) -> SafeNativeResult> { let n = safely_pop_arg!(arguments, u8); @@ -187,7 +187,7 @@ fn native_generate_keys( #[cfg(feature = "testing")] fn native_sign( _context: &mut SafeNativeContext, - _ty_args: Vec, + _ty_args: &[TypeId], mut arguments: VecDeque, ) -> SafeNativeResult> { let message = safely_pop_arg!(arguments, Vec); diff --git a/aptos-move/framework/src/natives/cryptography/ristretto255_point.rs b/aptos-move/framework/src/natives/cryptography/ristretto255_point.rs index 7d79e3979e3f2..fc13dd992e380 100644 --- a/aptos-move/framework/src/natives/cryptography/ristretto255_point.rs +++ b/aptos-move/framework/src/natives/cryptography/ristretto255_point.rs @@ -23,7 +23,7 @@ use curve25519_dalek::{ use move_core_types::gas_algebra::{NumArgs, NumBytes}; use move_vm_runtime::native_extensions::SessionListener; use move_vm_types::{ - loaded_data::runtime_types::Type, + ty_interner::TypeId, values::{Reference, StructRef, Value, VectorRef}, }; use sha2::Sha512; @@ -188,7 +188,7 @@ fn decompress_maybe_non_canonical_point_bytes( pub(crate) fn native_point_identity( context: &mut SafeNativeContext, - ty_args: Vec, + ty_args: &[TypeId], args: VecDeque, ) -> SafeNativeResult> { safely_assert_eq!(ty_args.len(), 0); @@ -205,7 +205,7 @@ pub(crate) fn native_point_identity( pub(crate) fn native_point_is_canonical( context: &mut SafeNativeContext, - _ty_args: Vec, + _ty_args: &[TypeId], mut args: VecDeque, ) -> SafeNativeResult> { safely_assert_eq!(_ty_args.len(), 0); @@ -220,7 +220,7 @@ pub(crate) fn native_point_is_canonical( pub(crate) fn native_point_decompress( context: &mut SafeNativeContext, - _ty_args: Vec, + _ty_args: &[TypeId], mut args: VecDeque, ) -> SafeNativeResult> { safely_assert_eq!(_ty_args.len(), 0); @@ -249,7 +249,7 @@ pub(crate) fn native_point_decompress( pub(crate) fn native_point_clone( context: &mut SafeNativeContext, - ty_args: Vec, + ty_args: &[TypeId], mut args: VecDeque, ) -> SafeNativeResult> { assert_eq!(ty_args.len(), 0); @@ -269,7 +269,7 @@ pub(crate) fn native_point_clone( pub(crate) fn native_point_compress( context: &mut SafeNativeContext, - ty_args: Vec, + ty_args: &[TypeId], mut args: VecDeque, ) -> SafeNativeResult> { safely_assert_eq!(ty_args.len(), 0); @@ -288,7 +288,7 @@ pub(crate) fn native_point_compress( pub(crate) fn native_point_mul( context: &mut SafeNativeContext, - ty_args: Vec, + ty_args: &[TypeId], mut args: VecDeque, ) -> SafeNativeResult> { safely_assert_eq!(ty_args.len(), 0); @@ -320,7 +320,7 @@ pub(crate) fn native_point_mul( pub(crate) fn native_point_equals( context: &mut SafeNativeContext, - ty_args: Vec, + ty_args: &[TypeId], mut args: VecDeque, ) -> SafeNativeResult> { safely_assert_eq!(ty_args.len(), 0); @@ -343,7 +343,7 @@ pub(crate) fn native_point_equals( pub(crate) fn native_point_neg( context: &mut SafeNativeContext, - ty_args: Vec, + ty_args: &[TypeId], mut args: VecDeque, ) -> SafeNativeResult> { safely_assert_eq!(ty_args.len(), 0); @@ -375,7 +375,7 @@ pub(crate) fn native_point_neg( pub(crate) fn native_point_add( context: &mut SafeNativeContext, - ty_args: Vec, + ty_args: &[TypeId], mut args: VecDeque, ) -> SafeNativeResult> { safely_assert_eq!(ty_args.len(), 0); @@ -417,7 +417,7 @@ pub(crate) fn native_point_add( pub(crate) fn native_point_sub( context: &mut SafeNativeContext, - ty_args: Vec, + ty_args: &[TypeId], mut args: VecDeque, ) -> SafeNativeResult> { safely_assert_eq!(ty_args.len(), 0); @@ -458,7 +458,7 @@ pub(crate) fn native_point_sub( pub(crate) fn native_basepoint_mul( context: &mut SafeNativeContext, - ty_args: Vec, + ty_args: &[TypeId], mut args: VecDeque, ) -> SafeNativeResult> { safely_assert_eq!(ty_args.len(), 0); @@ -481,7 +481,7 @@ pub(crate) fn native_basepoint_mul( #[allow(non_snake_case)] pub(crate) fn native_basepoint_double_mul( context: &mut SafeNativeContext, - ty_args: Vec, + ty_args: &[TypeId], mut args: VecDeque, ) -> SafeNativeResult> { safely_assert_eq!(ty_args.len(), 0); @@ -507,7 +507,7 @@ pub(crate) fn native_basepoint_double_mul( // NOTE: This was supposed to be more clearly named with *_sha2_512_* pub(crate) fn native_new_point_from_sha512( context: &mut SafeNativeContext, - ty_args: Vec, + ty_args: &[TypeId], mut args: VecDeque, ) -> SafeNativeResult> { safely_assert_eq!(ty_args.len(), 0); @@ -531,7 +531,7 @@ pub(crate) fn native_new_point_from_sha512( pub(crate) fn native_new_point_from_64_uniform_bytes( context: &mut SafeNativeContext, - ty_args: Vec, + ty_args: &[TypeId], mut args: VecDeque, ) -> SafeNativeResult> { safely_assert_eq!(ty_args.len(), 0); @@ -552,7 +552,7 @@ pub(crate) fn native_new_point_from_64_uniform_bytes( pub(crate) fn native_double_scalar_mul( context: &mut SafeNativeContext, - mut _ty_args: Vec, + mut _ty_args: &[TypeId], mut args: VecDeque, ) -> SafeNativeResult> { assert_eq!(args.len(), 4); @@ -589,7 +589,7 @@ pub(crate) fn native_double_scalar_mul( /// function. pub(crate) fn safe_native_multi_scalar_mul_no_floating_point( context: &mut SafeNativeContext, - _ty_args: Vec, + _ty_args: &[TypeId], mut args: VecDeque, ) -> SafeNativeResult> { safely_assert_eq!(args.len(), 2); diff --git a/aptos-move/framework/src/natives/cryptography/ristretto255_scalar.rs b/aptos-move/framework/src/natives/cryptography/ristretto255_scalar.rs index fae7d5f498183..b17ceb6ffa34f 100644 --- a/aptos-move/framework/src/natives/cryptography/ristretto255_scalar.rs +++ b/aptos-move/framework/src/natives/cryptography/ristretto255_scalar.rs @@ -10,7 +10,7 @@ use aptos_native_interface::{ }; use curve25519_dalek::scalar::Scalar; use move_core_types::gas_algebra::{NumArgs, NumBytes}; -use move_vm_types::{loaded_data::runtime_types::Type, values::Value}; +use move_vm_types::{ty_interner::TypeId, values::Value}; #[cfg(feature = "testing")] use rand::thread_rng; #[cfg(feature = "testing")] @@ -27,7 +27,7 @@ use std::{ /// This is a test-only native that charges zero gas. It is only exported in testing mode. pub(crate) fn native_scalar_random( _context: &mut SafeNativeContext, - _ty_args: Vec, + _ty_args: &[TypeId], args: VecDeque, ) -> SafeNativeResult> { debug_assert!(_ty_args.is_empty()); @@ -47,7 +47,7 @@ pub(crate) fn native_scalar_random( pub(crate) fn native_scalar_is_canonical( context: &mut SafeNativeContext, - _ty_args: Vec, + _ty_args: &[TypeId], mut arguments: VecDeque, ) -> SafeNativeResult> { safely_assert_eq!(_ty_args.len(), 0); @@ -70,7 +70,7 @@ pub(crate) fn native_scalar_is_canonical( pub(crate) fn native_scalar_invert( context: &mut SafeNativeContext, - _ty_args: Vec, + _ty_args: &[TypeId], mut arguments: VecDeque, ) -> SafeNativeResult> { safely_assert_eq!(_ty_args.len(), 0); @@ -87,7 +87,7 @@ pub(crate) fn native_scalar_invert( // NOTE: This was supposed to be more clearly named with *_sha2_512_*. pub(crate) fn native_scalar_from_sha512( context: &mut SafeNativeContext, - _ty_args: Vec, + _ty_args: &[TypeId], mut arguments: VecDeque, ) -> SafeNativeResult> { safely_assert_eq!(_ty_args.len(), 0); @@ -108,7 +108,7 @@ pub(crate) fn native_scalar_from_sha512( pub(crate) fn native_scalar_mul( context: &mut SafeNativeContext, - _ty_args: Vec, + _ty_args: &[TypeId], mut arguments: VecDeque, ) -> SafeNativeResult> { safely_assert_eq!(_ty_args.len(), 0); @@ -126,7 +126,7 @@ pub(crate) fn native_scalar_mul( pub(crate) fn native_scalar_add( context: &mut SafeNativeContext, - _ty_args: Vec, + _ty_args: &[TypeId], mut arguments: VecDeque, ) -> SafeNativeResult> { safely_assert_eq!(_ty_args.len(), 0); @@ -144,7 +144,7 @@ pub(crate) fn native_scalar_add( pub(crate) fn native_scalar_sub( context: &mut SafeNativeContext, - _ty_args: Vec, + _ty_args: &[TypeId], mut arguments: VecDeque, ) -> SafeNativeResult> { safely_assert_eq!(_ty_args.len(), 0); @@ -162,7 +162,7 @@ pub(crate) fn native_scalar_sub( pub(crate) fn native_scalar_neg( context: &mut SafeNativeContext, - _ty_args: Vec, + _ty_args: &[TypeId], mut arguments: VecDeque, ) -> SafeNativeResult> { safely_assert_eq!(_ty_args.len(), 0); @@ -179,7 +179,7 @@ pub(crate) fn native_scalar_neg( pub(crate) fn native_scalar_from_u64( context: &mut SafeNativeContext, - _ty_args: Vec, + _ty_args: &[TypeId], mut arguments: VecDeque, ) -> SafeNativeResult> { safely_assert_eq!(_ty_args.len(), 0); @@ -196,7 +196,7 @@ pub(crate) fn native_scalar_from_u64( pub(crate) fn native_scalar_from_u128( context: &mut SafeNativeContext, - _ty_args: Vec, + _ty_args: &[TypeId], mut arguments: VecDeque, ) -> SafeNativeResult> { safely_assert_eq!(_ty_args.len(), 0); @@ -213,7 +213,7 @@ pub(crate) fn native_scalar_from_u128( pub(crate) fn native_scalar_reduced_from_32_bytes( context: &mut SafeNativeContext, - _ty_args: Vec, + _ty_args: &[TypeId], mut arguments: VecDeque, ) -> SafeNativeResult> { safely_assert_eq!(_ty_args.len(), 0); @@ -230,7 +230,7 @@ pub(crate) fn native_scalar_reduced_from_32_bytes( pub(crate) fn native_scalar_uniform_from_64_bytes( context: &mut SafeNativeContext, - _ty_args: Vec, + _ty_args: &[TypeId], mut args: VecDeque, ) -> SafeNativeResult> { safely_assert_eq!(_ty_args.len(), 0); diff --git a/aptos-move/framework/src/natives/cryptography/secp256k1.rs b/aptos-move/framework/src/natives/cryptography/secp256k1.rs index 73632b3a64416..6f50bdf0e1e1e 100644 --- a/aptos-move/framework/src/natives/cryptography/secp256k1.rs +++ b/aptos-move/framework/src/natives/cryptography/secp256k1.rs @@ -8,7 +8,7 @@ use aptos_native_interface::{ }; use move_core_types::gas_algebra::NumArgs; use move_vm_runtime::native_functions::NativeFunction; -use move_vm_types::{loaded_data::runtime_types::Type, values::Value}; +use move_vm_types::{ty_interner::TypeId, values::Value}; use smallvec::{smallvec, SmallVec}; use std::collections::VecDeque; @@ -26,7 +26,7 @@ pub mod abort_codes { **************************************************************************************************/ fn native_ecdsa_recover( context: &mut SafeNativeContext, - _ty_args: Vec, + _ty_args: &[TypeId], mut arguments: VecDeque, ) -> SafeNativeResult> { debug_assert!(_ty_args.is_empty()); diff --git a/aptos-move/framework/src/natives/debug.rs b/aptos-move/framework/src/natives/debug.rs index 25922f99fe2f9..c7bee5d187242 100644 --- a/aptos-move/framework/src/natives/debug.rs +++ b/aptos-move/framework/src/natives/debug.rs @@ -13,8 +13,8 @@ use aptos_native_interface::{ use move_vm_runtime::native_functions::NativeFunction; #[allow(unused_imports)] use move_vm_types::{ - loaded_data::runtime_types::Type, natives::function::NativeResult, + ty_interner::TypeId, values::{Reference, Struct, Value}, }; use smallvec::{smallvec, SmallVec}; @@ -27,7 +27,7 @@ use std::collections::VecDeque; #[inline] fn native_print( _: &mut SafeNativeContext, - ty_args: Vec, + ty_args: &[TypeId], mut args: VecDeque, ) -> SafeNativeResult> { debug_assert!(ty_args.is_empty()); @@ -54,7 +54,7 @@ fn native_print( #[inline] fn native_stack_trace( context: &mut SafeNativeContext, - ty_args: Vec, + ty_args: &[TypeId], args: VecDeque, ) -> SafeNativeResult> { debug_assert!(ty_args.is_empty()); @@ -73,17 +73,14 @@ fn native_stack_trace( #[inline] fn native_old_debug_print( context: &mut SafeNativeContext, - ty_args: Vec, + ty_args: &[TypeId], mut args: VecDeque, ) -> SafeNativeResult> { if cfg!(feature = "testing") { let x = safely_pop_arg!(args, Reference); let val = x.read_ref().map_err(SafeNativeError::InvariantViolation)?; - println!( - "[debug] {}", - native_format_debug(context, &ty_args[0], val)? - ); + println!("[debug] {}", native_format_debug(context, ty_args[0], val)?); } Ok(smallvec![]) } @@ -91,7 +88,7 @@ fn native_old_debug_print( #[inline] fn native_old_print_stacktrace( context: &mut SafeNativeContext, - ty_args: Vec, + ty_args: &[TypeId], args: VecDeque, ) -> SafeNativeResult> { debug_assert!(ty_args.is_empty()); diff --git a/aptos-move/framework/src/natives/dispatchable_fungible_asset.rs b/aptos-move/framework/src/natives/dispatchable_fungible_asset.rs index 8d299545e655d..7386ae8d3e837 100644 --- a/aptos-move/framework/src/natives/dispatchable_fungible_asset.rs +++ b/aptos-move/framework/src/natives/dispatchable_fungible_asset.rs @@ -7,7 +7,7 @@ use aptos_native_interface::{ RawSafeNative, SafeNativeBuilder, SafeNativeContext, SafeNativeError, SafeNativeResult, }; use move_vm_runtime::native_functions::NativeFunction; -use move_vm_types::{loaded_data::runtime_types::Type, values::Value}; +use move_vm_types::{ty_interner::TypeId, values::Value}; use smallvec::SmallVec; use std::collections::VecDeque; @@ -21,7 +21,7 @@ use std::collections::VecDeque; **************************************************************************************************/ pub(crate) fn native_dispatch( context: &mut SafeNativeContext, - ty_args: Vec, + ty_args: &[TypeId], mut arguments: VecDeque, ) -> SafeNativeResult> { let (module_name, func_name) = extract_function_info(&mut arguments)?; @@ -50,7 +50,7 @@ pub(crate) fn native_dispatch( Err(SafeNativeError::FunctionDispatch { module_name, func_name, - ty_args, + ty_args: ty_args.to_vec(), args: arguments.into_iter().collect(), }) } diff --git a/aptos-move/framework/src/natives/event.rs b/aptos-move/framework/src/natives/event.rs index 4884e1aeed336..903aa8ae0f680 100644 --- a/aptos-move/framework/src/natives/event.rs +++ b/aptos-move/framework/src/natives/event.rs @@ -17,9 +17,7 @@ use move_core_types::{language_storage::TypeTag, value::MoveTypeLayout, vm_statu use move_vm_runtime::{native_extensions::SessionListener, native_functions::NativeFunction}; #[cfg(feature = "testing")] use move_vm_types::values::{Reference, Struct, StructRef}; -use move_vm_types::{ - loaded_data::runtime_types::Type, value_serde::ValueSerDeContext, values::Value, -}; +use move_vm_types::{ty_interner::TypeId, value_serde::ValueSerDeContext, values::Value}; use smallvec::{smallvec, SmallVec}; use std::collections::VecDeque; @@ -94,13 +92,13 @@ impl NativeEventContext { #[inline] fn native_write_to_event_store( context: &mut SafeNativeContext, - mut ty_args: Vec, + ty_args: &[TypeId], mut arguments: VecDeque, ) -> SafeNativeResult> { debug_assert!(ty_args.len() == 1); debug_assert!(arguments.len() == 3); - let ty = ty_args.pop().unwrap(); + let ty = ty_args[0]; let msg = arguments.pop_back().unwrap(); let seq_num = safely_pop_arg!(arguments, u64); let guid = safely_pop_arg!(arguments, Vec); @@ -110,9 +108,9 @@ fn native_write_to_event_store( EVENT_WRITE_TO_EVENT_STORE_BASE + EVENT_WRITE_TO_EVENT_STORE_PER_ABSTRACT_VALUE_UNIT * context.abs_val_size(&msg)?, )?; - let ty_tag = context.type_to_type_tag(&ty)?; + let ty_tag = context.type_to_type_tag(ty)?; let (layout, contains_delayed_fields) = context - .type_to_type_layout_with_delayed_fields(&ty)? + .type_to_type_layout_with_delayed_fields(ty)? .unpack(); let function_value_extension = context.function_value_extension(); @@ -146,13 +144,13 @@ fn native_write_to_event_store( #[cfg(feature = "testing")] fn native_emitted_events_by_handle( context: &mut SafeNativeContext, - mut ty_args: Vec, + ty_args: &[TypeId], mut arguments: VecDeque, ) -> SafeNativeResult> { debug_assert!(ty_args.len() == 1); debug_assert!(arguments.len() == 1); - let ty = ty_args.pop().unwrap(); + let ty = ty_args[0]; let mut guid = safely_pop_arg!(arguments, StructRef) .borrow_field(1)? .value_as::()? @@ -179,8 +177,8 @@ fn native_emitted_events_by_handle( })? .value_as::()?; let key = EventKey::new(creation_num, addr); - let ty_tag = context.type_to_type_tag(&ty)?; - let ty_layout = context.type_to_type_layout_check_no_delayed_fields(&ty)?; + let ty_tag = context.type_to_type_tag(ty)?; + let ty_layout = context.type_to_type_layout_check_no_delayed_fields(ty)?; let ctx = context.extensions().get::(); let events = ctx .emitted_v1_events(&key, &ty_tag) @@ -204,16 +202,16 @@ fn native_emitted_events_by_handle( #[cfg(feature = "testing")] fn native_emitted_events( context: &mut SafeNativeContext, - mut ty_args: Vec, + ty_args: &[TypeId], arguments: VecDeque, ) -> SafeNativeResult> { debug_assert!(ty_args.len() == 1); debug_assert!(arguments.is_empty()); - let ty = ty_args.pop().unwrap(); + let ty = ty_args[0]; - let ty_tag = context.type_to_type_tag(&ty)?; - let ty_layout = context.type_to_type_layout_check_no_delayed_fields(&ty)?; + let ty_tag = context.type_to_type_tag(ty)?; + let ty_layout = context.type_to_type_layout_check_no_delayed_fields(ty)?; let ctx = context.extensions().get::(); let events = ctx @@ -239,13 +237,13 @@ fn native_emitted_events( #[inline] fn native_write_module_event_to_store( context: &mut SafeNativeContext, - mut ty_args: Vec, + ty_args: &[TypeId], mut arguments: VecDeque, ) -> SafeNativeResult> { debug_assert!(ty_args.len() == 1); debug_assert!(arguments.len() == 1); - let ty = ty_args.pop().unwrap(); + let ty = ty_args[0]; let msg = arguments.pop_back().unwrap(); context.charge( @@ -253,7 +251,7 @@ fn native_write_module_event_to_store( + EVENT_WRITE_TO_EVENT_STORE_PER_ABSTRACT_VALUE_UNIT * context.abs_val_size(&msg)?, )?; - let type_tag = context.type_to_type_tag(&ty)?; + let type_tag = context.type_to_type_tag(ty)?; // Additional runtime check for module call. let stack_frames = context.stack_frames(1); @@ -287,7 +285,7 @@ fn native_write_module_event_to_store( } let (layout, contains_delayed_fields) = context - .type_to_type_layout_with_delayed_fields(&ty)? + .type_to_type_layout_with_delayed_fields(ty)? .unpack(); let function_value_extension = context.function_value_extension(); diff --git a/aptos-move/framework/src/natives/function_info.rs b/aptos-move/framework/src/natives/function_info.rs index ef13782336098..a23eaa3b9066a 100644 --- a/aptos-move/framework/src/natives/function_info.rs +++ b/aptos-move/framework/src/natives/function_info.rs @@ -13,7 +13,7 @@ use move_core_types::{ }; use move_vm_runtime::native_functions::NativeFunction; use move_vm_types::{ - loaded_data::runtime_types::Type, + ty_interner::TypeId, values::{Reference, StructRef, Value, VectorRef}, }; use smallvec::{smallvec, SmallVec}; @@ -72,7 +72,7 @@ pub(crate) fn extract_function_info( **************************************************************************************************/ fn native_check_dispatch_type_compatibility_impl( context: &mut SafeNativeContext, - _ty_args: Vec, + _ty_args: &[TypeId], mut arguments: VecDeque, ) -> SafeNativeResult> { debug_assert!(arguments.len() == 2); @@ -142,7 +142,7 @@ fn native_check_dispatch_type_compatibility_impl( **************************************************************************************************/ fn native_is_identifier( context: &mut SafeNativeContext, - _ty_args: Vec, + _ty_args: &[TypeId], mut arguments: VecDeque, ) -> SafeNativeResult> { debug_assert!(arguments.len() == 1); @@ -174,7 +174,7 @@ fn native_is_identifier( **************************************************************************************************/ fn native_load_function_impl( context: &mut SafeNativeContext, - _ty_args: Vec, + _ty_args: &[TypeId], mut arguments: VecDeque, ) -> SafeNativeResult> { debug_assert!(arguments.len() == 1); diff --git a/aptos-move/framework/src/natives/hash.rs b/aptos-move/framework/src/natives/hash.rs index da91b3d8b2011..89a4887ba92f5 100644 --- a/aptos-move/framework/src/natives/hash.rs +++ b/aptos-move/framework/src/natives/hash.rs @@ -8,7 +8,7 @@ use aptos_native_interface::{ }; use move_core_types::gas_algebra::{InternalGas, InternalGasPerByte, NumBytes}; use move_vm_runtime::native_functions::NativeFunction; -use move_vm_types::{loaded_data::runtime_types::Type, values::Value}; +use move_vm_types::{ty_interner::TypeId, values::Value}; use ripemd::Digest as OtherDigest; use sha2::Digest; use smallvec::{smallvec, SmallVec}; @@ -23,7 +23,7 @@ use tiny_keccak::{Hasher as KeccakHasher, Keccak}; **************************************************************************************************/ fn native_sip_hash( context: &mut SafeNativeContext, - mut _ty_args: Vec, + mut _ty_args: &[TypeId], mut args: VecDeque, ) -> SafeNativeResult> { debug_assert!(_ty_args.is_empty()); @@ -44,7 +44,7 @@ fn native_sip_hash( fn native_keccak256( context: &mut SafeNativeContext, - mut _ty_args: Vec, + mut _ty_args: &[TypeId], mut args: VecDeque, ) -> SafeNativeResult> { debug_assert!(_ty_args.is_empty()); @@ -65,7 +65,7 @@ fn native_keccak256( fn native_sha2_512( context: &mut SafeNativeContext, - mut _ty_args: Vec, + mut _ty_args: &[TypeId], mut args: VecDeque, ) -> SafeNativeResult> { debug_assert!(_ty_args.is_empty()); @@ -85,7 +85,7 @@ fn native_sha2_512( fn native_sha3_512( context: &mut SafeNativeContext, - mut _ty_args: Vec, + mut _ty_args: &[TypeId], mut args: VecDeque, ) -> SafeNativeResult> { debug_assert!(_ty_args.is_empty()); @@ -111,7 +111,7 @@ pub struct Blake2B256HashGasParameters { fn native_blake2b_256( context: &mut SafeNativeContext, - mut _ty_args: Vec, + mut _ty_args: &[TypeId], mut args: VecDeque, ) -> SafeNativeResult> { safely_assert_eq!(_ty_args.len(), 0); @@ -138,7 +138,7 @@ pub struct Ripemd160HashGasParameters { fn native_ripemd160( context: &mut SafeNativeContext, - mut _ty_args: Vec, + mut _ty_args: &[TypeId], mut args: VecDeque, ) -> SafeNativeResult> { debug_assert!(_ty_args.is_empty()); diff --git a/aptos-move/framework/src/natives/object.rs b/aptos-move/framework/src/natives/object.rs index ee824db9689ab..c83cce09a4df1 100644 --- a/aptos-move/framework/src/natives/object.rs +++ b/aptos-move/framework/src/natives/object.rs @@ -14,9 +14,7 @@ use move_core_types::{ vm_status::StatusCode, }; use move_vm_runtime::{native_extensions::SessionListener, native_functions::NativeFunction}; -use move_vm_types::{ - loaded_data::runtime_types::Type, natives::function::PartialVMError, values::Value, -}; +use move_vm_types::{natives::function::PartialVMError, ty_interner::TypeId, values::Value}; use smallvec::{smallvec, SmallVec}; use std::{ cell::RefCell, @@ -65,21 +63,23 @@ pub struct ExistsAtGasParameters { fn native_exists_at( context: &mut SafeNativeContext, - mut ty_args: Vec, + ty_args: &[TypeId], mut args: VecDeque, ) -> SafeNativeResult> { safely_assert_eq!(ty_args.len(), 1); safely_assert_eq!(args.len(), 1); - let type_ = ty_args.pop().unwrap(); let address = safely_pop_arg!(args, AccountAddress); context.charge(OBJECT_EXISTS_AT_BASE)?; - let (exists, num_bytes) = context.exists_at(address, &type_).map_err(|err| { + let (exists, num_bytes) = context.exists_at(address, ty_args[0]).map_err(|err| { PartialVMError::new(StatusCode::VM_EXTENSION_ERROR).with_message(format!( "Failed to read resource: {:?} at {}. With error: {}", - type_, address, err + // TODO: fix error message? + ty_args[0], + address, + err )) })?; @@ -100,7 +100,7 @@ fn native_exists_at( **************************************************************************************************/ fn native_create_user_derived_object_address_impl( context: &mut SafeNativeContext, - ty_args: Vec, + ty_args: &[TypeId], mut args: VecDeque, ) -> SafeNativeResult> { debug_assert!(ty_args.is_empty()); diff --git a/aptos-move/framework/src/natives/permissioned_signer.rs b/aptos-move/framework/src/natives/permissioned_signer.rs index 658bc7a8778ac..688b371063934 100644 --- a/aptos-move/framework/src/natives/permissioned_signer.rs +++ b/aptos-move/framework/src/natives/permissioned_signer.rs @@ -13,7 +13,7 @@ use aptos_native_interface::{ use move_core_types::account_address::AccountAddress; use move_vm_runtime::native_functions::NativeFunction; use move_vm_types::{ - loaded_data::runtime_types::Type, + ty_interner::TypeId, values::{SignerRef, Value}, }; use smallvec::{smallvec, SmallVec}; @@ -30,7 +30,7 @@ const EPERMISSION_SIGNER_DISABLED: u64 = 9; **************************************************************************************************/ fn native_is_permissioned_signer_impl( context: &mut SafeNativeContext, - _ty_args: Vec, + _ty_args: &[TypeId], mut arguments: VecDeque, ) -> SafeNativeResult> { debug_assert!(arguments.len() == 1); @@ -61,7 +61,7 @@ fn native_is_permissioned_signer_impl( **************************************************************************************************/ fn native_permission_address( context: &mut SafeNativeContext, - _ty_args: Vec, + _ty_args: &[TypeId], mut args: VecDeque, ) -> SafeNativeResult> { debug_assert!(args.len() == 1); @@ -94,7 +94,7 @@ fn native_permission_address( **************************************************************************************************/ fn native_signer_from_permissioned( context: &mut SafeNativeContext, - _ty_args: Vec, + _ty_args: &[TypeId], mut arguments: VecDeque, ) -> SafeNativeResult> { debug_assert!(arguments.len() == 2); @@ -127,7 +127,7 @@ fn native_signer_from_permissioned( #[inline] fn native_borrow_address( context: &mut SafeNativeContext, - _ty_args: Vec, + _ty_args: &[TypeId], mut arguments: VecDeque, ) -> SafeNativeResult> { debug_assert!(_ty_args.is_empty()); diff --git a/aptos-move/framework/src/natives/randomness.rs b/aptos-move/framework/src/natives/randomness.rs index 8547fcd3487ae..c1a09d3faa0a5 100644 --- a/aptos-move/framework/src/natives/randomness.rs +++ b/aptos-move/framework/src/natives/randomness.rs @@ -10,7 +10,7 @@ use aptos_native_interface::{ }; use better_any::{Tid, TidAble}; use move_vm_runtime::{native_extensions::SessionListener, native_functions::NativeFunction}; -use move_vm_types::{loaded_data::runtime_types::Type, values::Value}; +use move_vm_types::{ty_interner::TypeId, values::Value}; use smallvec::{smallvec, SmallVec}; use std::collections::VecDeque; @@ -71,7 +71,7 @@ impl RandomnessContext { pub fn fetch_and_increment_txn_counter( context: &mut SafeNativeContext, - _ty_args: Vec, + _ty_args: &[TypeId], _args: VecDeque, ) -> SafeNativeResult> { if context.gas_feature_version() >= RELEASE_V1_23 { @@ -92,7 +92,7 @@ pub fn fetch_and_increment_txn_counter( pub fn is_unbiasable( context: &mut SafeNativeContext, - _ty_args: Vec, + _ty_args: &[TypeId], _args: VecDeque, ) -> SafeNativeResult> { // Because we need to run a special transaction prologue to pre-charge maximum diff --git a/aptos-move/framework/src/natives/state_storage.rs b/aptos-move/framework/src/natives/state_storage.rs index d4cfe4e5b3054..c5814bf17164f 100644 --- a/aptos-move/framework/src/natives/state_storage.rs +++ b/aptos-move/framework/src/natives/state_storage.rs @@ -11,7 +11,7 @@ use better_any::{Tid, TidAble}; use move_binary_format::errors::PartialVMError; use move_vm_runtime::{native_extensions::SessionListener, native_functions::NativeFunction}; use move_vm_types::{ - loaded_data::runtime_types::Type, + ty_interner::TypeId, values::{Struct, Value}, }; use smallvec::{smallvec, SmallVec}; @@ -51,7 +51,7 @@ impl<'a> NativeStateStorageContext<'a> { /// guarantees a fresh state view then. fn native_get_usage( context: &mut SafeNativeContext, - _ty_args: Vec, + _ty_args: &[TypeId], _args: VecDeque, ) -> SafeNativeResult> { assert!(_ty_args.is_empty()); diff --git a/aptos-move/framework/src/natives/string_utils.rs b/aptos-move/framework/src/natives/string_utils.rs index d5d0285dd7fb6..177e929822bd1 100644 --- a/aptos-move/framework/src/natives/string_utils.rs +++ b/aptos-move/framework/src/natives/string_utils.rs @@ -21,7 +21,7 @@ use move_core_types::{ }; use move_vm_runtime::native_functions::NativeFunction; use move_vm_types::{ - loaded_data::runtime_types::Type, + ty_interner::{TypeId, TypeRepr}, values::{Closure, Reference, Struct, Value, Vector, VectorRef}, }; use smallvec::{smallvec, SmallVec}; @@ -532,7 +532,7 @@ fn native_format_impl( /// TODO: remove when old framework is completely removed pub(crate) fn native_format_debug( context: &mut SafeNativeContext, - ty: &Type, + ty: TypeId, v: Value, ) -> SafeNativeResult { let layout = @@ -558,13 +558,13 @@ pub(crate) fn native_format_debug( fn native_format( context: &mut SafeNativeContext, - ty_args: Vec, + ty_args: &[TypeId], mut arguments: VecDeque, ) -> SafeNativeResult> { debug_assert!(ty_args.len() == 1); let ty = context - .type_to_fully_annotated_layout(&ty_args[0])? + .type_to_fully_annotated_layout(ty_args[0])? .ok_or_else(|| SafeNativeError::Abort { abort_code: EUNABLE_TO_FORMAT_DELAYED_FIELD, })?; @@ -592,11 +592,11 @@ fn native_format( fn native_format_list( context: &mut SafeNativeContext, - ty_args: Vec, + ty_args: &[TypeId], mut arguments: VecDeque, ) -> SafeNativeResult> { debug_assert!(ty_args.len() == 1); - let mut list_ty = &ty_args[0]; + let mut list_ty = ty_args[0]; let val = safely_pop_arg!(arguments, Reference); let mut val = val @@ -643,18 +643,19 @@ fn native_format_list( match_list_ty(context, list_ty, "Cons")?; // We know that the type is a list, so we can safely unwrap - let ty_args = if let Type::StructInstantiation { ty_args, .. } = list_ty { - ty_args + let pool = context.module_storage().runtime_environment().ty_pool(); + let ty_args = if let TypeRepr::Struct { ty_args, .. } = pool.type_repr(list_ty) { + pool.get_type_vec(ty_args) } else { unreachable!() }; let mut it = val.value_as::()?.unpack()?; let car = it.next().unwrap(); val = it.next().unwrap(); - list_ty = &ty_args[1]; + list_ty = ty_args[1]; let ty = context - .type_to_fully_annotated_layout(&ty_args[0])? + .type_to_fully_annotated_layout(ty_args[0])? .ok_or_else(|| SafeNativeError::Abort { abort_code: EUNABLE_TO_FORMAT_DELAYED_FIELD, })?; diff --git a/aptos-move/framework/src/natives/transaction_context.rs b/aptos-move/framework/src/natives/transaction_context.rs index 454ec01e49f0c..bf9777d35e313 100644 --- a/aptos-move/framework/src/natives/transaction_context.rs +++ b/aptos-move/framework/src/natives/transaction_context.rs @@ -18,7 +18,7 @@ use move_binary_format::errors::PartialVMResult; use move_core_types::gas_algebra::{NumArgs, NumBytes}; use move_vm_runtime::{native_extensions::SessionListener, native_functions::NativeFunction}; use move_vm_types::{ - loaded_data::runtime_types::Type, + ty_interner::TypeId, values::{Struct, Value}, }; use smallvec::{smallvec, SmallVec}; @@ -107,7 +107,7 @@ impl NativeTransactionContext { **************************************************************************************************/ fn native_get_txn_hash( context: &mut SafeNativeContext, - _ty_args: Vec, + _ty_args: &[TypeId], _args: VecDeque, ) -> SafeNativeResult> { context.charge(TRANSACTION_CONTEXT_GET_TXN_HASH_BASE)?; @@ -126,7 +126,7 @@ fn native_get_txn_hash( **************************************************************************************************/ fn native_generate_unique_address( context: &mut SafeNativeContext, - _ty_args: Vec, + _ty_args: &[TypeId], _args: VecDeque, ) -> SafeNativeResult> { context.charge(TRANSACTION_CONTEXT_GENERATE_UNIQUE_ADDRESS_BASE)?; @@ -152,7 +152,7 @@ fn native_generate_unique_address( **************************************************************************************************/ fn native_monotonically_increasing_counter_internal( context: &mut SafeNativeContext, - _ty_args: Vec, + _ty_args: &[TypeId], mut args: VecDeque, ) -> SafeNativeResult> { context.charge(TRANSACTION_CONTEXT_MONOTONICALLY_INCREASING_COUNTER_BASE)?; @@ -200,7 +200,7 @@ fn native_monotonically_increasing_counter_internal( **************************************************************************************************/ fn native_monotonically_increasing_counter_internal_for_test_only( context: &mut SafeNativeContext, - _ty_args: Vec, + _ty_args: &[TypeId], _args: VecDeque, ) -> SafeNativeResult> { context.charge(TRANSACTION_CONTEXT_MONOTONICALLY_INCREASING_COUNTER_BASE)?; @@ -230,7 +230,7 @@ fn native_monotonically_increasing_counter_internal_for_test_only( **************************************************************************************************/ fn native_get_script_hash( context: &mut SafeNativeContext, - _ty_args: Vec, + _ty_args: &[TypeId], _args: VecDeque, ) -> SafeNativeResult> { context.charge(TRANSACTION_CONTEXT_GET_SCRIPT_HASH_BASE)?; @@ -244,7 +244,7 @@ fn native_get_script_hash( fn native_sender_internal( context: &mut SafeNativeContext, - _ty_args: Vec, + _ty_args: &[TypeId], _args: VecDeque, ) -> SafeNativeResult> { context.charge(TRANSACTION_CONTEXT_SENDER_BASE)?; @@ -261,7 +261,7 @@ fn native_sender_internal( fn native_secondary_signers_internal( context: &mut SafeNativeContext, - _ty_args: Vec, + _ty_args: &[TypeId], _args: VecDeque, ) -> SafeNativeResult> { context.charge(TRANSACTION_CONTEXT_SECONDARY_SIGNERS_BASE)?; @@ -283,7 +283,7 @@ fn native_secondary_signers_internal( fn native_gas_payer_internal( context: &mut SafeNativeContext, - _ty_args: Vec, + _ty_args: &[TypeId], _args: VecDeque, ) -> SafeNativeResult> { context.charge(TRANSACTION_CONTEXT_FEE_PAYER_BASE)?; @@ -300,7 +300,7 @@ fn native_gas_payer_internal( fn native_max_gas_amount_internal( context: &mut SafeNativeContext, - _ty_args: Vec, + _ty_args: &[TypeId], _args: VecDeque, ) -> SafeNativeResult> { context.charge(TRANSACTION_CONTEXT_MAX_GAS_AMOUNT_BASE)?; @@ -317,7 +317,7 @@ fn native_max_gas_amount_internal( fn native_gas_unit_price_internal( context: &mut SafeNativeContext, - _ty_args: Vec, + _ty_args: &[TypeId], _args: VecDeque, ) -> SafeNativeResult> { context.charge(TRANSACTION_CONTEXT_GAS_UNIT_PRICE_BASE)?; @@ -334,7 +334,7 @@ fn native_gas_unit_price_internal( fn native_chain_id_internal( context: &mut SafeNativeContext, - _ty_args: Vec, + _ty_args: &[TypeId], _args: VecDeque, ) -> SafeNativeResult> { context.charge(TRANSACTION_CONTEXT_CHAIN_ID_BASE)?; @@ -414,7 +414,7 @@ fn create_entry_function_payload( fn native_entry_function_payload_internal( context: &mut SafeNativeContext, - _ty_args: Vec, + _ty_args: &[TypeId], _args: VecDeque, ) -> SafeNativeResult> { context.charge(TRANSACTION_CONTEXT_ENTRY_FUNCTION_PAYLOAD_BASE)?; @@ -442,7 +442,7 @@ fn native_entry_function_payload_internal( fn native_multisig_payload_internal( context: &mut SafeNativeContext, - _ty_args: Vec, + _ty_args: &[TypeId], _args: VecDeque, ) -> SafeNativeResult> { context.charge(TRANSACTION_CONTEXT_MULTISIG_PAYLOAD_BASE)?; diff --git a/aptos-move/framework/src/natives/type_info.rs b/aptos-move/framework/src/natives/type_info.rs index b33e3271ee60a..61f6d19f979c6 100644 --- a/aptos-move/framework/src/natives/type_info.rs +++ b/aptos-move/framework/src/natives/type_info.rs @@ -11,7 +11,7 @@ use move_core_types::{ }; use move_vm_runtime::native_functions::NativeFunction; use move_vm_types::{ - loaded_data::runtime_types::Type, + ty_interner::TypeId, values::{Struct, Value}, }; use smallvec::{smallvec, SmallVec}; @@ -46,7 +46,7 @@ fn type_of_internal(struct_tag: &StructTag) -> Result, std: **************************************************************************************************/ fn native_type_of( context: &mut SafeNativeContext, - ty_args: Vec, + ty_args: &[TypeId], arguments: VecDeque, ) -> SafeNativeResult> { debug_assert!(ty_args.len() == 1); @@ -54,7 +54,7 @@ fn native_type_of( context.charge(TYPE_INFO_TYPE_OF_BASE)?; - let type_tag = context.type_to_type_tag(&ty_args[0])?; + let type_tag = context.type_to_type_tag(ty_args[0])?; if context.eval_gas(TYPE_INFO_TYPE_OF_PER_BYTE_IN_STR) > 0.into() { let type_tag_str = type_tag.to_canonical_string(); @@ -83,7 +83,7 @@ fn native_type_of( **************************************************************************************************/ fn native_type_name( context: &mut SafeNativeContext, - ty_args: Vec, + ty_args: &[TypeId], arguments: VecDeque, ) -> SafeNativeResult> { debug_assert!(ty_args.len() == 1); @@ -91,7 +91,7 @@ fn native_type_name( context.charge(TYPE_INFO_TYPE_NAME_BASE)?; - let type_tag = context.type_to_type_tag(&ty_args[0])?; + let type_tag = context.type_to_type_tag(ty_args[0])?; let type_name = type_tag.to_canonical_string(); // TODO: Ideally, we would charge *before* the `type_to_type_tag()` and `type_tag.to_string()` calls above. @@ -112,7 +112,7 @@ fn native_type_name( **************************************************************************************************/ fn native_chain_id( context: &mut SafeNativeContext, - _ty_args: Vec, + _ty_args: &[TypeId], arguments: VecDeque, ) -> SafeNativeResult> { debug_assert!(_ty_args.is_empty()); diff --git a/aptos-move/framework/src/natives/util.rs b/aptos-move/framework/src/natives/util.rs index 444cc143e3fa5..1880e88264a5c 100644 --- a/aptos-move/framework/src/natives/util.rs +++ b/aptos-move/framework/src/natives/util.rs @@ -8,9 +8,7 @@ use aptos_native_interface::{ }; use move_core_types::gas_algebra::NumBytes; use move_vm_runtime::native_functions::NativeFunction; -use move_vm_types::{ - loaded_data::runtime_types::Type, value_serde::ValueSerDeContext, values::Value, -}; +use move_vm_types::{ty_interner::TypeId, value_serde::ValueSerDeContext, values::Value}; use smallvec::{smallvec, SmallVec}; use std::collections::VecDeque; @@ -29,14 +27,14 @@ const EFROM_BYTES: u64 = 0x01_0001; **************************************************************************************************/ fn native_from_bytes( context: &mut SafeNativeContext, - ty_args: Vec, + ty_args: &[TypeId], mut args: VecDeque, ) -> SafeNativeResult> { debug_assert_eq!(ty_args.len(), 1); debug_assert_eq!(args.len(), 1); // TODO(Gas): charge for getting the layout - let layout = context.type_to_type_layout(&ty_args[0])?; + let layout = context.type_to_type_layout(ty_args[0])?; let bytes = safely_pop_arg!(args, Vec); context.charge( diff --git a/aptos-move/framework/table-natives/src/lib.rs b/aptos-move/framework/table-natives/src/lib.rs index 171f452aafc30..137435b3cab93 100644 --- a/aptos-move/framework/table-natives/src/lib.rs +++ b/aptos-move/framework/table-natives/src/lib.rs @@ -29,7 +29,7 @@ use move_vm_runtime::{ native_functions::{LoaderContext, NativeFunctionTable}, }; use move_vm_types::{ - loaded_data::runtime_types::Type, + ty_interner::TypeId, value_serde::{FunctionValueExtension, ValueSerDeContext}, values::{GlobalValue, Reference, StructRef, Value}, }; @@ -206,8 +206,8 @@ impl TableData { &mut self, loader_context: &mut LoaderContext, handle: TableHandle, - key_ty: &Type, - value_ty: &Type, + key_ty: TypeId, + value_ty: TypeId, ) -> PartialVMResult<&mut Table> { Ok(match self.tables.entry(handle) { Entry::Vacant(e) => { @@ -230,7 +230,10 @@ impl TableData { } impl LayoutInfo { - fn from_value_ty(loader_context: &mut LoaderContext, value_ty: &Type) -> PartialVMResult { + fn from_value_ty( + loader_context: &mut LoaderContext, + value_ty: TypeId, + ) -> PartialVMResult { let (layout, contains_delayed_fields) = loader_context .type_to_type_layout_with_delayed_fields(value_ty)? .unpack(); @@ -347,7 +350,7 @@ fn charge_load_cost( fn native_new_table_handle( context: &mut SafeNativeContext, - ty_args: Vec, + ty_args: &[TypeId], args: VecDeque, ) -> SafeNativeResult> { assert_eq!(ty_args.len(), 2); @@ -368,8 +371,8 @@ fn native_new_table_handle( let bytes = digest.finalize().to_vec(); let handle = AccountAddress::from_bytes(&bytes[0..AccountAddress::LENGTH]) .map_err(|_| partial_extension_error("Unable to create table handle"))?; - let key_type = context.type_to_type_tag(&ty_args[0])?; - let value_type = context.type_to_type_tag(&ty_args[1])?; + let key_type = context.type_to_type_tag(ty_args[0])?; + let value_type = context.type_to_type_tag(ty_args[1])?; assert!(table_data .new_tables .insert(TableHandle(handle), TableInfo::new(key_type, value_type)) @@ -380,7 +383,7 @@ fn native_new_table_handle( fn native_add_box( context: &mut SafeNativeContext, - ty_args: Vec, + ty_args: &[TypeId], mut args: VecDeque, ) -> SafeNativeResult> { assert_eq!(ty_args.len(), 3); @@ -400,7 +403,7 @@ fn native_add_box( let handle = get_table_handle(&safely_pop_arg!(args, StructRef))?; let table = - table_data.get_or_create_table(&mut loader_context, handle, &ty_args[0], &ty_args[2])?; + table_data.get_or_create_table(&mut loader_context, handle, ty_args[0], ty_args[2])?; let function_value_extension = loader_context.function_value_extension(); let key_bytes = serialize_key(&function_value_extension, &table.key_layout, &key)?; @@ -441,7 +444,7 @@ fn native_add_box( fn native_borrow_box( context: &mut SafeNativeContext, - ty_args: Vec, + ty_args: &[TypeId], mut args: VecDeque, ) -> SafeNativeResult> { assert_eq!(ty_args.len(), 3); @@ -460,7 +463,7 @@ fn native_borrow_box( let handle = get_table_handle(&safely_pop_arg!(args, StructRef))?; let table = - table_data.get_or_create_table(&mut loader_context, handle, &ty_args[0], &ty_args[2])?; + table_data.get_or_create_table(&mut loader_context, handle, ty_args[0], ty_args[2])?; let function_value_extension = loader_context.function_value_extension(); let key_bytes = serialize_key(&function_value_extension, &table.key_layout, &key)?; @@ -501,7 +504,7 @@ fn native_borrow_box( fn native_contains_box( context: &mut SafeNativeContext, - ty_args: Vec, + ty_args: &[TypeId], mut args: VecDeque, ) -> SafeNativeResult> { assert_eq!(ty_args.len(), 3); @@ -520,7 +523,7 @@ fn native_contains_box( let handle = get_table_handle(&safely_pop_arg!(args, StructRef))?; let table = - table_data.get_or_create_table(&mut loader_context, handle, &ty_args[0], &ty_args[2])?; + table_data.get_or_create_table(&mut loader_context, handle, ty_args[0], ty_args[2])?; let function_value_extension = loader_context.function_value_extension(); let key_bytes = serialize_key(&function_value_extension, &table.key_layout, &key)?; @@ -555,7 +558,7 @@ fn native_contains_box( fn native_remove_box( context: &mut SafeNativeContext, - ty_args: Vec, + ty_args: &[TypeId], mut args: VecDeque, ) -> SafeNativeResult> { assert_eq!(ty_args.len(), 3); @@ -574,7 +577,7 @@ fn native_remove_box( let handle = get_table_handle(&safely_pop_arg!(args, StructRef))?; let table = - table_data.get_or_create_table(&mut loader_context, handle, &ty_args[0], &ty_args[2])?; + table_data.get_or_create_table(&mut loader_context, handle, ty_args[0], ty_args[2])?; let function_value_extension = loader_context.function_value_extension(); let key_bytes = serialize_key(&function_value_extension, &table.key_layout, &key)?; @@ -615,7 +618,7 @@ fn native_remove_box( fn native_destroy_empty_box( context: &mut SafeNativeContext, - ty_args: Vec, + ty_args: &[TypeId], mut args: VecDeque, ) -> SafeNativeResult> { assert_eq!(ty_args.len(), 3); @@ -629,7 +632,7 @@ fn native_destroy_empty_box( let handle = get_table_handle(&safely_pop_arg!(args, StructRef))?; // TODO: Can the following line be removed? - table_data.get_or_create_table(&mut loader_context, handle, &ty_args[0], &ty_args[2])?; + table_data.get_or_create_table(&mut loader_context, handle, ty_args[0], ty_args[2])?; assert!(table_data.removed_tables.insert(handle)); @@ -638,7 +641,7 @@ fn native_destroy_empty_box( fn native_drop_unchecked_box( context: &mut SafeNativeContext, - ty_args: Vec, + ty_args: &[TypeId], args: VecDeque, ) -> SafeNativeResult> { assert_eq!(ty_args.len(), 3); diff --git a/third_party/move/extensions/move-table-extension/src/lib.rs b/third_party/move/extensions/move-table-extension/src/lib.rs index 3e2c8c5bf99ac..2fc5ba0451f38 100644 --- a/third_party/move/extensions/move-table-extension/src/lib.rs +++ b/third_party/move/extensions/move-table-extension/src/lib.rs @@ -24,9 +24,9 @@ use move_vm_runtime::{ native_functions::{LoaderContext, NativeContext, NativeFunction, NativeFunctionTable}, }; use move_vm_types::{ - loaded_data::runtime_types::Type, natives::function::NativeResult, pop_arg, + ty_interner::TypeId, value_serde::{FunctionValueExtension, ValueSerDeContext}, values::{GlobalValue, Reference, StructRef, Value}, }; @@ -221,8 +221,8 @@ impl TableData { &mut self, loader_context: &mut LoaderContext, handle: TableHandle, - key_ty: &Type, - value_ty: &Type, + key_ty: TypeId, + value_ty: TypeId, ) -> PartialVMResult<&mut Table> { Ok(match self.tables.entry(handle) { Entry::Vacant(e) => { @@ -355,7 +355,7 @@ pub struct NewTableHandleGasParameters { fn native_new_table_handle( gas_params: &NewTableHandleGasParameters, context: &mut NativeContext, - ty_args: Vec, + ty_args: &[TypeId], args: VecDeque, ) -> PartialVMResult { assert_eq!(ty_args.len(), 2); @@ -374,8 +374,8 @@ fn native_new_table_handle( let bytes = digest.finalize().to_vec(); let handle = AccountAddress::from_bytes(&bytes[0..AccountAddress::LENGTH]) .map_err(|_| partial_extension_error("Unable to create table handle"))?; - let key_type = context.type_to_type_tag(&ty_args[0])?; - let value_type = context.type_to_type_tag(&ty_args[1])?; + let key_type = context.type_to_type_tag(ty_args[0])?; + let value_type = context.type_to_type_tag(ty_args[1])?; assert!(table_data .new_tables .insert(TableHandle(handle), TableInfo::new(key_type, value_type)) @@ -404,7 +404,7 @@ fn native_add_box( common_gas_params: &CommonGasParameters, gas_params: &AddBoxGasParameters, context: &mut NativeContext, - ty_args: Vec, + ty_args: &[TypeId], mut args: VecDeque, ) -> PartialVMResult { assert_eq!(ty_args.len(), 3); @@ -421,7 +421,7 @@ fn native_add_box( let mut cost = gas_params.base; let table = - table_data.get_or_create_table(&mut loader_context, handle, &ty_args[0], &ty_args[2])?; + table_data.get_or_create_table(&mut loader_context, handle, ty_args[0], ty_args[2])?; let function_value_extension = loader_context.function_value_extension(); let key_bytes = serialize(&function_value_extension, &table.key_layout, &key)?; @@ -458,7 +458,7 @@ fn native_borrow_box( common_gas_params: &CommonGasParameters, gas_params: &BorrowBoxGasParameters, context: &mut NativeContext, - ty_args: Vec, + ty_args: &[TypeId], mut args: VecDeque, ) -> PartialVMResult { assert_eq!(ty_args.len(), 3); @@ -472,7 +472,7 @@ fn native_borrow_box( let handle = get_table_handle(&pop_arg!(args, StructRef))?; let table = - table_data.get_or_create_table(&mut loader_context, handle, &ty_args[0], &ty_args[2])?; + table_data.get_or_create_table(&mut loader_context, handle, ty_args[0], ty_args[2])?; let mut cost = gas_params.base; @@ -511,7 +511,7 @@ fn native_contains_box( common_gas_params: &CommonGasParameters, gas_params: &ContainsBoxGasParameters, context: &mut NativeContext, - ty_args: Vec, + ty_args: &[TypeId], mut args: VecDeque, ) -> PartialVMResult { assert_eq!(ty_args.len(), 3); @@ -525,7 +525,7 @@ fn native_contains_box( let handle = get_table_handle(&pop_arg!(args, StructRef))?; let table = - table_data.get_or_create_table(&mut loader_context, handle, &ty_args[0], &ty_args[2])?; + table_data.get_or_create_table(&mut loader_context, handle, ty_args[0], ty_args[2])?; let mut cost = gas_params.base; @@ -563,7 +563,7 @@ fn native_remove_box( common_gas_params: &CommonGasParameters, gas_params: &RemoveGasParameters, context: &mut NativeContext, - ty_args: Vec, + ty_args: &[TypeId], mut args: VecDeque, ) -> PartialVMResult { assert_eq!(ty_args.len(), 3); @@ -577,7 +577,7 @@ fn native_remove_box( let handle = get_table_handle(&pop_arg!(args, StructRef))?; let table = - table_data.get_or_create_table(&mut loader_context, handle, &ty_args[0], &ty_args[2])?; + table_data.get_or_create_table(&mut loader_context, handle, ty_args[0], ty_args[2])?; let mut cost = gas_params.base; @@ -614,7 +614,7 @@ pub struct DestroyEmptyBoxGasParameters { fn native_destroy_empty_box( gas_params: &DestroyEmptyBoxGasParameters, context: &mut NativeContext, - ty_args: Vec, + ty_args: &[TypeId], mut args: VecDeque, ) -> PartialVMResult { assert_eq!(ty_args.len(), 3); @@ -626,7 +626,7 @@ fn native_destroy_empty_box( let handle = get_table_handle(&pop_arg!(args, StructRef))?; // TODO: Can the following line be removed? - table_data.get_or_create_table(&mut loader_context, handle, &ty_args[0], &ty_args[2])?; + table_data.get_or_create_table(&mut loader_context, handle, ty_args[0], ty_args[2])?; assert!(table_data.removed_tables.insert(handle)); @@ -649,7 +649,7 @@ pub struct DropUncheckedBoxGasParameters { fn native_drop_unchecked_box( gas_params: &DropUncheckedBoxGasParameters, _context: &mut NativeContext, - ty_args: Vec, + ty_args: &[TypeId], args: VecDeque, ) -> PartialVMResult { assert_eq!(ty_args.len(), 3); diff --git a/third_party/move/move-binary-format/src/file_format.rs b/third_party/move/move-binary-format/src/file_format.rs index 06b22930577de..391b0cd9a3680 100644 --- a/third_party/move/move-binary-format/src/file_format.rs +++ b/third_party/move/move-binary-format/src/file_format.rs @@ -1271,6 +1271,12 @@ impl SignatureToken { self.preorder_traversal().count() } + /// Returns true if the signature is not fully instantiated. + pub fn is_not_instantiated(&self) -> bool { + self.preorder_traversal() + .any(|t| matches!(t, SignatureToken::TypeParameter(..))) + } + pub fn instantiate(&self, subst_mapping: &[SignatureToken]) -> SignatureToken { use SignatureToken::*; let inst_vec = |v: &[SignatureToken]| -> Vec { diff --git a/third_party/move/move-stdlib/src/natives/bcs.rs b/third_party/move/move-stdlib/src/natives/bcs.rs index 1904d06de6cb8..9ead468d8c7ed 100644 --- a/third_party/move/move-stdlib/src/natives/bcs.rs +++ b/third_party/move/move-stdlib/src/natives/bcs.rs @@ -10,9 +10,9 @@ use move_core_types::{ }; use move_vm_runtime::native_functions::{NativeContext, NativeFunction}; use move_vm_types::{ - loaded_data::runtime_types::Type, natives::function::NativeResult, pop_arg, + ty_interner::TypeId, value_serde::{FunctionValueExtension, ValueSerDeContext}, values::{values_impl::Reference, Value}, }; @@ -41,7 +41,7 @@ pub struct ToBytesGasParameters { fn native_to_bytes( gas_params: &ToBytesGasParameters, context: &mut NativeContext, - mut ty_args: Vec, + ty_args: &[TypeId], mut args: VecDeque, ) -> PartialVMResult { debug_assert!(ty_args.len() == 1); @@ -51,10 +51,9 @@ fn native_to_bytes( // pop type and value let ref_to_val = pop_arg!(args, Reference); - let arg_type = ty_args.pop().unwrap(); // get type layout - let layout = match context.type_to_type_layout(&arg_type) { + let layout = match context.type_to_type_layout(ty_args[0]) { Ok(layout) => layout, Err(_) => { cost += gas_params.failure; diff --git a/third_party/move/move-stdlib/src/natives/debug.rs b/third_party/move/move-stdlib/src/natives/debug.rs index 86befb63ee5d2..6862f48f8ce05 100644 --- a/third_party/move/move-stdlib/src/natives/debug.rs +++ b/third_party/move/move-stdlib/src/natives/debug.rs @@ -8,9 +8,9 @@ use move_core_types::{account_address::AccountAddress, gas_algebra::InternalGas} use move_vm_runtime::native_functions::{NativeContext, NativeFunction}; #[allow(unused_imports)] use move_vm_types::{ - loaded_data::runtime_types::Type, natives::function::NativeResult, pop_arg, + ty_interner::TypeId, values::{Reference, Value}, }; use smallvec::smallvec; @@ -30,7 +30,7 @@ pub struct PrintGasParameters { fn native_print( gas_params: &PrintGasParameters, _context: &mut NativeContext, - mut ty_args: Vec, + ty_args: &[TypeId], mut args: VecDeque, _move_std_addr: AccountAddress, ) -> PartialVMResult { @@ -38,7 +38,7 @@ fn native_print( debug_assert!(args.len() == 1); let _val = args.pop_back().unwrap(); - let _ty = ty_args.pop().unwrap(); + let _ty = ty_args[0]; // No-op if the feature flag is not present. #[cfg(feature = "testing")] @@ -93,7 +93,7 @@ pub struct PrintStackTraceGasParameters { fn native_print_stack_trace( gas_params: &PrintStackTraceGasParameters, context: &mut NativeContext, - ty_args: Vec, + ty_args: &[TypeId], args: VecDeque, ) -> PartialVMResult { debug_assert!(ty_args.is_empty()); @@ -151,7 +151,7 @@ mod testing { vm_status::StatusCode, }; use move_vm_runtime::native_functions::NativeContext; - use move_vm_types::{loaded_data::runtime_types::Type, values::Value}; + use move_vm_types::{ty_interner::TypeId, values::Value}; use std::{fmt, fmt::Write}; const VECTOR_BEGIN: &str = "["; @@ -176,7 +176,7 @@ mod testing { fn get_annotated_struct_layout( context: &mut NativeContext, - ty: &Type, + ty: TypeId, ) -> PartialVMResult { let annotated_type_layout = context.type_to_fully_annotated_layout(ty)?; if let Some(MoveTypeLayout::Struct(annotated_struct_layout)) = @@ -194,13 +194,13 @@ mod testing { } } - fn get_vector_inner_type(ty: &Type) -> PartialVMResult<&Type> { - match ty { - Type::Vector(ty) => Ok(ty), - _ => Err(PartialVMError::new(StatusCode::INTERNAL_TYPE_ERROR) - .with_message("Could not get the inner Type of a vector's Type".to_string())), - } - } + // fn get_vector_inner_type(ty: &Type) -> PartialVMResult<&Type> { + // match ty { + // Type::Vector(ty) => Ok(ty), + // _ => Err(PartialVMError::new(StatusCode::INTERNAL_TYPE_ERROR) + // .with_message("Could not get the inner Type of a vector's Type".to_string())), + // } + // } /// Converts a `MoveValue::Vector` of `u8`'s to a `String` by wrapping it in double quotes and /// escaping double quotes and backslashes. @@ -255,7 +255,7 @@ mod testing { context: &mut NativeContext, out: &mut String, val: Value, - ty: Type, + ty: TypeId, move_std_addr: &AccountAddress, depth: usize, canonicalize: bool, @@ -266,13 +266,18 @@ mod testing { // this debug implementation is // 1. Not used in production, instead debug implementation from 0x1::string_utils is used. // 2. Not called in block-execution context where delayed fields are relevant. - let ty_layout = context.type_to_type_layout_check_no_delayed_fields(&ty)?; + let ty_layout = context.type_to_type_layout_check_no_delayed_fields(ty)?; match ty_layout.as_ref() { MoveTypeLayout::Vector(_) => { // Get the inner type T of a vector. Again, we should not see any delayed fields // in the debug context. - let inner_ty = get_vector_inner_type(&ty)?; + let inner_ty = context + .module_storage() + .runtime_environment() + .ty_pool() + .get_vec_elem_ty(ty) + .expect("TODO"); let inner_tyl = context.type_to_type_layout_check_no_delayed_fields(inner_ty)?; match inner_tyl.as_ref() { @@ -298,7 +303,7 @@ mod testing { context, out, val, - inner_ty.clone(), + inner_ty, move_std_addr, depth, canonicalize, @@ -345,7 +350,7 @@ mod testing { }, }; - let annotated_struct_layout = get_annotated_struct_layout(context, &ty)?; + let annotated_struct_layout = get_annotated_struct_layout(context, ty)?; let decorated_struct = move_struct.decorate(&annotated_struct_layout); print_move_value( diff --git a/third_party/move/move-stdlib/src/natives/event.rs b/third_party/move/move-stdlib/src/natives/event.rs index 5ab61c203f805..588a01f2f781c 100644 --- a/third_party/move/move-stdlib/src/natives/event.rs +++ b/third_party/move/move-stdlib/src/natives/event.rs @@ -7,8 +7,7 @@ use move_binary_format::errors::PartialVMResult; use move_core_types::gas_algebra::InternalGasPerAbstractMemoryUnit; use move_vm_runtime::native_functions::{NativeContext, NativeFunction}; use move_vm_types::{ - loaded_data::runtime_types::Type, natives::function::NativeResult, values::Value, - views::ValueView, + natives::function::NativeResult, ty_interner::TypeId, values::Value, views::ValueView, }; use smallvec::smallvec; use std::{collections::VecDeque, sync::Arc}; @@ -28,7 +27,7 @@ pub struct WriteToEventStoreGasParameters { fn native_write_to_event_store( gas_params: &WriteToEventStoreGasParameters, _context: &mut NativeContext, - ty_args: Vec, + ty_args: &[TypeId], mut arguments: VecDeque, ) -> PartialVMResult { debug_assert!(ty_args.len() == 1); diff --git a/third_party/move/move-stdlib/src/natives/hash.rs b/third_party/move/move-stdlib/src/natives/hash.rs index f915fa77cd976..64f50b5ee9e3f 100644 --- a/third_party/move/move-stdlib/src/natives/hash.rs +++ b/third_party/move/move-stdlib/src/natives/hash.rs @@ -6,9 +6,7 @@ use crate::natives::helpers::make_module_natives; use move_binary_format::errors::PartialVMResult; use move_core_types::gas_algebra::{InternalGas, InternalGasPerByte, NumBytes}; use move_vm_runtime::native_functions::{NativeContext, NativeFunction}; -use move_vm_types::{ - loaded_data::runtime_types::Type, natives::function::NativeResult, pop_arg, values::Value, -}; +use move_vm_types::{natives::function::NativeResult, pop_arg, ty_interner::TypeId, values::Value}; use sha2::{Digest, Sha256}; use sha3::Sha3_256; use smallvec::smallvec; @@ -31,7 +29,7 @@ pub struct Sha2_256GasParameters { fn native_sha2_256( gas_params: &Sha2_256GasParameters, _context: &mut NativeContext, - _ty_args: Vec, + _ty_args: &[TypeId], mut arguments: VecDeque, ) -> PartialVMResult { debug_assert!(_ty_args.is_empty()); @@ -77,7 +75,7 @@ pub struct Sha3_256GasParameters { fn native_sha3_256( gas_params: &Sha3_256GasParameters, _context: &mut NativeContext, - _ty_args: Vec, + _ty_args: &[TypeId], mut arguments: VecDeque, ) -> PartialVMResult { debug_assert!(_ty_args.is_empty()); diff --git a/third_party/move/move-stdlib/src/natives/signer.rs b/third_party/move/move-stdlib/src/natives/signer.rs index 90c8ccac06b48..9233a1f323cf2 100644 --- a/third_party/move/move-stdlib/src/natives/signer.rs +++ b/third_party/move/move-stdlib/src/natives/signer.rs @@ -7,9 +7,9 @@ use move_binary_format::errors::PartialVMResult; use move_core_types::gas_algebra::InternalGas; use move_vm_runtime::native_functions::{NativeContext, NativeFunction}; use move_vm_types::{ - loaded_data::runtime_types::Type, natives::function::NativeResult, pop_arg, + ty_interner::TypeId, values::{values_impl::SignerRef, Value}, }; use smallvec::smallvec; @@ -30,7 +30,7 @@ pub struct BorrowAddressGasParameters { fn native_borrow_address( gas_params: &BorrowAddressGasParameters, _context: &mut NativeContext, - _ty_args: Vec, + _ty_args: &[TypeId], mut arguments: VecDeque, ) -> PartialVMResult { debug_assert!(_ty_args.is_empty()); diff --git a/third_party/move/move-stdlib/src/natives/string.rs b/third_party/move/move-stdlib/src/natives/string.rs index 24b1074dc0777..c8567cbd83d2c 100644 --- a/third_party/move/move-stdlib/src/natives/string.rs +++ b/third_party/move/move-stdlib/src/natives/string.rs @@ -9,9 +9,9 @@ use move_binary_format::errors::PartialVMResult; use move_core_types::gas_algebra::{InternalGas, InternalGasPerByte, NumBytes}; use move_vm_runtime::native_functions::{NativeContext, NativeFunction}; use move_vm_types::{ - loaded_data::runtime_types::Type, natives::function::NativeResult, pop_arg, + ty_interner::TypeId, values::{Value, VectorRef}, }; use std::{collections::VecDeque, sync::Arc}; @@ -39,7 +39,7 @@ pub struct CheckUtf8GasParameters { fn native_check_utf8( gas_params: &CheckUtf8GasParameters, _context: &mut NativeContext, - _ty_args: Vec, + _ty_args: &[TypeId], mut args: VecDeque, ) -> PartialVMResult { debug_assert!(args.len() == 1); @@ -75,7 +75,7 @@ pub struct IsCharBoundaryGasParameters { fn native_is_char_boundary( gas_params: &IsCharBoundaryGasParameters, _context: &mut NativeContext, - _ty_args: Vec, + _ty_args: &[TypeId], mut args: VecDeque, ) -> PartialVMResult { debug_assert!(args.len() == 2); @@ -112,7 +112,7 @@ pub struct SubStringGasParameters { fn native_sub_string( gas_params: &SubStringGasParameters, _context: &mut NativeContext, - _ty_args: Vec, + _ty_args: &[TypeId], mut args: VecDeque, ) -> PartialVMResult { debug_assert!(args.len() == 3); @@ -160,7 +160,7 @@ pub struct IndexOfGasParameters { fn native_index_of( gas_params: &IndexOfGasParameters, _context: &mut NativeContext, - _ty_args: Vec, + _ty_args: &[TypeId], mut args: VecDeque, ) -> PartialVMResult { debug_assert!(args.len() == 2); diff --git a/third_party/move/move-stdlib/src/natives/type_name.rs b/third_party/move/move-stdlib/src/natives/type_name.rs index 897ea168602d6..23390c769ca2e 100644 --- a/third_party/move/move-stdlib/src/natives/type_name.rs +++ b/third_party/move/move-stdlib/src/natives/type_name.rs @@ -5,8 +5,8 @@ use move_binary_format::errors::PartialVMResult; use move_core_types::gas_algebra::{InternalGas, InternalGasPerByte, NumBytes}; use move_vm_runtime::native_functions::{NativeContext, NativeFunction}; use move_vm_types::{ - loaded_data::runtime_types::Type, natives::function::NativeResult, + ty_interner::TypeId, values::{Struct, Value}, }; use smallvec::smallvec; @@ -21,13 +21,13 @@ pub struct GetGasParameters { fn native_get( gas_params: &GetGasParameters, context: &mut NativeContext, - ty_args: Vec, + ty_args: &[TypeId], arguments: VecDeque, ) -> PartialVMResult { debug_assert_eq!(ty_args.len(), 1); debug_assert!(arguments.is_empty()); - let type_tag = context.type_to_type_tag(&ty_args[0])?; + let type_tag = context.type_to_type_tag(ty_args[0])?; let type_name = type_tag.to_canonical_string(); // make a std::string::String let string_val = Value::struct_(Struct::pack(vec![Value::vector_u8( diff --git a/third_party/move/move-stdlib/src/natives/unit_test.rs b/third_party/move/move-stdlib/src/natives/unit_test.rs index a00dfeb68a3a7..c95b35b3676d4 100644 --- a/third_party/move/move-stdlib/src/natives/unit_test.rs +++ b/third_party/move/move-stdlib/src/natives/unit_test.rs @@ -9,9 +9,7 @@ use move_core_types::{ gas_algebra::{InternalGas, InternalGasPerArg, NumArgs}, }; use move_vm_runtime::native_functions::{NativeContext, NativeFunction}; -use move_vm_types::{ - loaded_data::runtime_types::Type, natives::function::NativeResult, pop_arg, values::Value, -}; +use move_vm_types::{natives::function::NativeResult, pop_arg, ty_interner::TypeId, values::Value}; use smallvec::smallvec; use std::{collections::VecDeque, sync::Arc}; @@ -37,7 +35,7 @@ pub struct CreateSignersForTestingGasParameters { fn native_create_signers_for_testing( gas_params: &CreateSignersForTestingGasParameters, _context: &mut NativeContext, - ty_args: Vec, + ty_args: &[TypeId], mut args: VecDeque, ) -> PartialVMResult { debug_assert!(ty_args.is_empty()); diff --git a/third_party/move/move-vm/runtime/src/access_control.rs b/third_party/move/move-vm/runtime/src/access_control.rs index 4c8b330d76391..64d005c5479b9 100644 --- a/third_party/move/move-vm/runtime/src/access_control.rs +++ b/third_party/move/move-vm/runtime/src/access_control.rs @@ -66,6 +66,7 @@ impl AccessControlState { } /// Check whether the given access is allowed in the current state. + #[allow(dead_code)] pub(crate) fn check_access(&self, access: AccessInstance) -> PartialVMResult<()> { for specifier in self.specifier_stack.iter().rev() { if !specifier.enables(&access) { diff --git a/third_party/move/move-vm/runtime/src/data_cache.rs b/third_party/move/move-vm/runtime/src/data_cache.rs index 174146acd164c..3b60bfb08a012 100644 --- a/third_party/move/move-vm/runtime/src/data_cache.rs +++ b/third_party/move/move-vm/runtime/src/data_cache.rs @@ -24,8 +24,8 @@ use move_core_types::{ }; use move_vm_types::{ gas::DependencyGasMeter, - loaded_data::runtime_types::Type, resolver::ResourceResolver, + ty_interner::TypeId, value_serde::{FunctionValueExtension, ValueSerDeContext}, values::{GlobalValue, Value}, }; @@ -42,7 +42,7 @@ pub trait NativeContextMoveVmDataCache { gas_meter: &mut dyn DependencyGasMeter, traversal_context: &mut TraversalContext, addr: &AccountAddress, - ty: &Type, + ty: TypeId, ) -> PartialVMResult<(bool, Option)>; } @@ -58,7 +58,7 @@ pub trait MoveVmDataCache: NativeContextMoveVmDataCache { gas_meter: &mut impl DependencyGasMeter, traversal_context: &mut TraversalContext, addr: &AccountAddress, - ty: &Type, + ty: TypeId, ) -> PartialVMResult<(&GlobalValue, Option)> { let (gv, bytes_loaded) = self.load_resource_mut(gas_meter, traversal_context, addr, ty)?; Ok((gv, bytes_loaded)) @@ -71,7 +71,7 @@ pub trait MoveVmDataCache: NativeContextMoveVmDataCache { gas_meter: &mut impl DependencyGasMeter, traversal_context: &mut TraversalContext, addr: &AccountAddress, - ty: &Type, + ty: TypeId, ) -> PartialVMResult<(&mut GlobalValue, Option)>; } @@ -92,7 +92,7 @@ where gas_meter: &mut dyn DependencyGasMeter, traversal_context: &mut TraversalContext, addr: &AccountAddress, - ty: &Type, + ty: TypeId, ) -> PartialVMResult<(bool, Option)> { let mut gas_meter = DependencyGasMeterWrapper::new(gas_meter); let (gv, bytes_loaded) = self.load_resource(&mut gas_meter, traversal_context, addr, ty)?; @@ -127,7 +127,7 @@ where gas_meter: &mut impl DependencyGasMeter, traversal_context: &mut TraversalContext, addr: &AccountAddress, - ty: &Type, + ty: TypeId, ) -> PartialVMResult<(&mut GlobalValue, Option)> { let bytes_loaded = if !self.data_cache.contains_resource(addr, ty) { let (entry, bytes_loaded) = TransactionDataCache::create_data_cache_entry( @@ -140,7 +140,7 @@ where addr, ty, )?; - self.data_cache.insert_resource(*addr, ty.clone(), entry)?; + self.data_cache.insert_resource(*addr, ty, entry)?; Some(bytes_loaded) } else { None @@ -175,7 +175,7 @@ struct DataCacheEntry { /// for a data store related to a transaction. Clients should create an instance of this type /// and pass it to the Move VM. pub struct TransactionDataCache { - account_map: BTreeMap>, + account_map: BTreeMap>, } impl TransactionDataCache { @@ -260,7 +260,7 @@ impl TransactionDataCache { module_storage: &dyn ModuleStorage, resource_resolver: &dyn ResourceResolver, addr: &AccountAddress, - ty: &Type, + ty: TypeId, ) -> PartialVMResult<(DataCacheEntry, NumBytes)> { let struct_tag = match module_storage.runtime_environment().ty_to_ty_tag(ty)? { TypeTag::Struct(struct_tag) => *struct_tag, @@ -328,10 +328,10 @@ impl TransactionDataCache { /// Returns true if resource has been inserted into the cache. Otherwise, returns false. The /// state of the cache does not chang when calling this function. - fn contains_resource(&self, addr: &AccountAddress, ty: &Type) -> bool { + fn contains_resource(&self, addr: &AccountAddress, ty: TypeId) -> bool { self.account_map .get(addr) - .is_some_and(|account_cache| account_cache.contains_key(ty)) + .is_some_and(|account_cache| account_cache.contains_key(&ty)) } /// Stores a new entry for loaded resource into the data cache. Returns an error if there is an @@ -339,10 +339,10 @@ impl TransactionDataCache { fn insert_resource( &mut self, addr: AccountAddress, - ty: Type, + ty: TypeId, data_cache_entry: DataCacheEntry, ) -> PartialVMResult<()> { - match self.account_map.entry(addr).or_default().entry(ty.clone()) { + match self.account_map.entry(addr).or_default().entry(ty) { Entry::Vacant(entry) => entry.insert(data_cache_entry), Entry::Occupied(_) => { let msg = format!("Entry for {:?} at {} already exists", ty, addr); @@ -359,10 +359,10 @@ impl TransactionDataCache { fn get_resource_mut( &mut self, addr: &AccountAddress, - ty: &Type, + ty: TypeId, ) -> PartialVMResult<&mut GlobalValue> { if let Some(account_cache) = self.account_map.get_mut(addr) { - if let Some(entry) = account_cache.get_mut(ty) { + if let Some(entry) = account_cache.get_mut(&ty) { return Ok(&mut entry.value); } } diff --git a/third_party/move/move-vm/runtime/src/frame.rs b/third_party/move/move-vm/runtime/src/frame.rs index 8c51247c9a0bc..b2ae24a698ecc 100644 --- a/third_party/move/move-vm/runtime/src/frame.rs +++ b/third_party/move/move-vm/runtime/src/frame.rs @@ -32,7 +32,7 @@ use move_vm_types::{ runtime_access_specifier::{AccessSpecifierEnv, AddressSpecifierFunction}, runtime_types::{AbilityInfo, StructType, Type, TypeBuilder}, }, - ty_interner::{InternedTypePool, TypeVecId}, + ty_interner::{InternedTypePool, TypeId, TypeVecId}, values::Locals, }; use std::{cell::RefCell, rc::Rc, sync::Arc}; @@ -46,14 +46,15 @@ pub(crate) enum LocalTys { /// Used for non-generic functions to avoid type clones around locals. BorrowFromFunction, /// Used for generic functions, where types are cached per-instantiation. - BorrowFromFunctionGeneric(Rc<[Type]>), + BorrowFromFunctionGeneric(Rc<[TypeId]>), } /// Represents the execution context for a function. When calls are made, frames are /// pushed and then popped to/from the call stack. -pub(crate) struct Frame { +pub(crate) struct Frame<'ctx> { pub(crate) pc: u16, ty_builder: TypeBuilder, + pub(crate) ty_pool: &'ctx InternedTypePool, // Currently being executed function. pub(crate) function: Rc, // How this frame was established. @@ -66,7 +67,7 @@ pub(crate) struct Frame { pub(crate) frame_cache: Rc>, } -impl AccessSpecifierEnv for Frame { +impl<'ctx> AccessSpecifierEnv for Frame<'ctx> { fn eval_address_specifier_function( &self, fun: AddressSpecifierFunction, @@ -84,7 +85,7 @@ macro_rules! build_loaded_function { gas_meter: &mut impl GasMeter, traversal_context: &mut TraversalContext, idx: $idx_ty, - verified_ty_args: Vec, + verified_ty_args: Vec, ty_args_id: TypeVecId, ) -> PartialVMResult { match self.function.owner() { @@ -135,7 +136,7 @@ macro_rules! build_loaded_function { }; } -impl Frame { +impl<'ctx> Frame<'ctx> { build_loaded_function!( build_loaded_function_from_handle_and_ty_args, FunctionHandleIndex, @@ -153,10 +154,11 @@ impl Frame { gas_meter: &mut impl GasMeter, call_type: CallType, vm_config: &VMConfig, + ty_pool: &'ctx InternedTypePool, function: Rc, locals: Locals, frame_cache: Rc>, - ) -> PartialVMResult { + ) -> PartialVMResult> { let ty_args = function.ty_args(); let ty_builder = vm_config.ty_builder.clone(); @@ -182,8 +184,9 @@ impl Frame { } else { let local_tys = function.local_tys(); let mut local_ty_counts = Vec::with_capacity(local_tys.len()); - for ty in local_tys { - let cnt = NumTypeNodes::new(ty.num_nodes_in_subst(ty_args)? as u64); + for _ in local_tys { + // ty.num_nodes_in_subst(ty_args)? as u64 + let cnt = NumTypeNodes::new(10); gas_meter.charge_create_ty(cnt)?; local_ty_counts.push(cnt); } @@ -194,10 +197,10 @@ impl Frame { if let Some(local_tys) = cache_borrow.instantiated_local_tys.as_ref().cloned() { LocalTys::BorrowFromFunctionGeneric(local_tys) } else { - let local_tys: Rc<[Type]> = function + let local_tys: Rc<[TypeId]> = function .local_tys() .iter() - .map(|ty| ty_builder.create_ty_with_subst(ty, ty_args)) + .map(|ty| Ok(ty_pool.instantiate_and_intern(ty, ty_args))) .collect::>>() .map(Rc::from)?; cache_borrow.instantiated_local_tys = Some(local_tys.clone()); @@ -211,6 +214,7 @@ impl Frame { Ok(Frame { pc: 0, ty_builder, + ty_pool, locals, function, call_type, @@ -219,8 +223,8 @@ impl Frame { }) } - pub(crate) fn ty_builder(&self) -> &TypeBuilder { - &self.ty_builder + pub(crate) fn ty_pool(&self) -> &InternedTypePool { + self.ty_pool } pub(crate) fn call_type(&self) -> CallType { @@ -230,12 +234,12 @@ impl Frame { /// Returns a local type at specified index. Used for runtime type checks only, and if called /// in non-type checking context will panic! #[cfg_attr(feature = "force-inline", inline(always))] - pub(crate) fn local_ty_at(&self, idx: usize) -> &Type { + pub(crate) fn local_ty_at(&self, idx: usize) -> &TypeId { match &self.local_tys { LocalTys::None => { unreachable!("Local types are not used when there are no runtime type checks") }, - LocalTys::BorrowFromFunction => &self.function.local_tys()[idx], + LocalTys::BorrowFromFunction => &self.function.local_type_ids()[idx], LocalTys::BorrowFromFunctionGeneric(tys) => &tys[idx], } } @@ -244,12 +248,13 @@ impl Frame { pub(crate) fn check_local_tys_have_drop_ability(&self) -> PartialVMResult<()> { let local_tys = match &self.local_tys { LocalTys::None => return Ok(()), - LocalTys::BorrowFromFunction => self.function.local_tys(), + LocalTys::BorrowFromFunction => self.function.local_type_ids(), LocalTys::BorrowFromFunctionGeneric(tys) => tys, }; for (idx, ty) in local_tys.iter().enumerate() { if !self.locals.is_invalid(idx)? { - ty.paranoid_check_has_ability(Ability::Drop)?; + self.ty_pool + .paranoid_check_has_ability(*ty, Ability::Drop)?; } } Ok(()) @@ -270,13 +275,14 @@ impl Frame { } #[cfg_attr(feature = "force-inline", inline(always))] - pub(crate) fn get_struct_ty(&self, idx: StructDefinitionIndex) -> Type { + pub(crate) fn get_struct_ty(&self, idx: StructDefinitionIndex) -> TypeId { use LoadedFunctionOwner::*; let struct_ty = match self.function.owner() { Module(module) => module.struct_at(idx), Script(_) => unreachable!("Scripts cannot have type instructions"), }; - self.create_struct_ty(struct_ty) + let ty = self.create_struct_ty(struct_ty); + self.ty_pool.instantiate_and_intern(&ty, &[]) } pub(crate) fn get_struct_variant_at( @@ -304,7 +310,7 @@ impl Frame { pub(crate) fn get_generic_struct_ty( &self, idx: StructDefInstantiationIndex, - ) -> PartialVMResult { + ) -> PartialVMResult { use LoadedFunctionOwner::*; let struct_inst = match self.function.owner() { Module(module) => module.struct_instantiation_at(idx.0), @@ -312,11 +318,11 @@ impl Frame { }; let struct_ty = &struct_inst.definition_struct_type; - self.ty_builder.create_struct_instantiation_ty( + Ok(self.ty_pool.intern_struct_instantiation( struct_ty, &struct_inst.instantiation, self.function.ty_args(), - ) + )) } #[cfg_attr(feature = "force-inline", inline(always))] @@ -335,7 +341,7 @@ impl Frame { pub(crate) fn get_generic_field_ty( &self, idx: FieldInstantiationIndex, - ) -> PartialVMResult { + ) -> PartialVMResult { use LoadedFunctionOwner::*; let field_instantiation = match self.function.owner() { Module(module) => &module.field_instantiations[idx.0 as usize], @@ -349,15 +355,21 @@ impl Frame { &self, ty: &Type, instantiation_tys: &[Type], - ) -> PartialVMResult { - let instantiation_tys = instantiation_tys + ) -> PartialVMResult { + // Then instantiate each instantiation type with the function's type arguments + let instantiation_ty_ids: Vec = instantiation_tys .iter() .map(|inst_ty| { - self.ty_builder - .create_ty_with_subst(inst_ty, self.function.ty_args()) + Ok(self + .ty_pool + .instantiate_and_intern(inst_ty, &self.function.ty_args)) }) - .collect::>>()?; - self.ty_builder.create_ty_with_subst(ty, &instantiation_tys) + .collect::>()?; + + // Finally, instantiate the target type with the instantiation type IDs + Ok(self + .ty_pool + .instantiate_and_intern(ty, &instantiation_ty_ids)) } pub(crate) fn variant_field_info_at(&self, idx: VariantFieldHandleIndex) -> &VariantFieldInfo { @@ -391,7 +403,7 @@ impl Frame { pub(crate) fn instantiate_generic_struct_fields( &self, idx: StructDefInstantiationIndex, - ) -> PartialVMResult> { + ) -> PartialVMResult> { use LoadedFunctionOwner::*; let struct_inst = match self.function.owner() { Module(module) => module.struct_instantiation_at(idx.0), @@ -404,7 +416,7 @@ impl Frame { pub(crate) fn instantiate_generic_struct_variant_fields( &self, idx: StructVariantInstantiationIndex, - ) -> PartialVMResult> { + ) -> PartialVMResult> { use LoadedFunctionOwner::*; let struct_inst = match self.function.owner() { Module(module) => module.struct_variant_instantiation_at(idx), @@ -423,21 +435,25 @@ impl Frame { struct_ty: &Arc, variant: Option, instantiation: &[Type], - ) -> PartialVMResult> { - let instantiation_tys = instantiation + ) -> PartialVMResult> { + // Then instantiate each instantiation type with the function's type arguments + let instantiation_ty_ids: Vec = instantiation .iter() .map(|inst_ty| { - self.ty_builder - .create_ty_with_subst(inst_ty, self.function.ty_args()) + Ok(self + .ty_pool + .instantiate_and_intern(inst_ty, &self.function.ty_args)) }) - .collect::>>()?; + .collect::>()?; + // Finally, instantiate each field type with the instantiation type IDs struct_ty .fields(variant)? .iter() .map(|(_, inst_ty)| { - self.ty_builder - .create_ty_with_subst(inst_ty, &instantiation_tys) + Ok(self + .ty_pool + .instantiate_and_intern(inst_ty, &instantiation_ty_ids)) }) .collect::>>() } @@ -450,14 +466,11 @@ impl Frame { } } - pub(crate) fn instantiate_single_type(&self, idx: SignatureIndex) -> PartialVMResult { + pub(crate) fn instantiate_single_type(&self, idx: SignatureIndex) -> PartialVMResult { let ty = self.single_type_at(idx); - let ty_args = self.function.ty_args(); - if !ty_args.is_empty() { - self.ty_builder.create_ty_with_subst(ty, ty_args) - } else { - Ok(ty.clone()) - } + Ok(self + .ty_pool + .instantiate_and_intern(ty, &self.function.ty_args)) } pub(crate) fn create_struct_ty(&self, struct_ty: &Arc) -> Type { @@ -469,12 +482,10 @@ impl Frame { &self, struct_ty: &Arc, ty_params: &[Type], - ) -> PartialVMResult { - self.ty_builder.create_struct_instantiation_ty( - struct_ty, - ty_params, - self.function.ty_args(), - ) + ) -> PartialVMResult { + Ok(self + .ty_pool + .intern_struct_instantiation(struct_ty, ty_params, self.function.ty_args())) } #[cfg_attr(feature = "force-inline", inline(always))] @@ -529,7 +540,7 @@ impl Frame { pub(crate) fn field_instantiation_to_struct( &self, idx: FieldInstantiationIndex, - ) -> PartialVMResult { + ) -> PartialVMResult { use LoadedFunctionOwner::*; match self.function.owner() { Module(module) => { @@ -548,7 +559,7 @@ impl Frame { ty_pool: &InternedTypePool, gas_meter: Option<&mut impl GasMeter>, idx: FunctionInstantiationIndex, - ) -> PartialVMResult<(Vec, TypeVecId)> { + ) -> PartialVMResult<(Vec, TypeVecId)> { use LoadedFunctionOwner::*; let (instantiation, ty_args_id) = match self.function.owner() { Module(module) => module.function_instantiation_at(idx.0), @@ -557,20 +568,20 @@ impl Frame { let ty_args = self.function.ty_args(); if let Some(gas_meter) = gas_meter { - for ty in instantiation { - gas_meter - .charge_create_ty(NumTypeNodes::new(ty.num_nodes_in_subst(ty_args)? as u64))?; + for _ in instantiation { + // ty.num_nodes_in_subst(ty_args)? as u64 + gas_meter.charge_create_ty(NumTypeNodes::new(5))?; } } let instantiation = instantiation .iter() - .map(|ty| self.ty_builder.create_ty_with_subst(ty, ty_args)) - .collect::>>()?; + .map(|ty| self.ty_pool.instantiate_and_intern(ty, ty_args)) + .collect::>(); let ty_args_id = match ty_args_id { Some(ty_args_id) => ty_args_id, // We can hit this case where original type args were only a partial instantiation. - None => ty_pool.intern_ty_args(&instantiation), + None => ty_pool.intern_ty_slice(&instantiation), }; Ok((instantiation, ty_args_id)) @@ -583,7 +594,7 @@ impl Frame { traversal_context: &mut TraversalContext, module_id: &ModuleId, function_name: &IdentStr, - verified_ty_args: Vec, + verified_ty_args: Vec, ty_args_id: TypeVecId, ) -> PartialVMResult { let (module, function) = loader diff --git a/third_party/move/move-vm/runtime/src/frame_type_cache.rs b/third_party/move/move-vm/runtime/src/frame_type_cache.rs index 64ab400290b69..285839515e0de 100644 --- a/third_party/move/move-vm/runtime/src/frame_type_cache.rs +++ b/third_party/move/move-vm/runtime/src/frame_type_cache.rs @@ -11,7 +11,7 @@ use move_binary_format::{ }, }; use move_core_types::gas_algebra::NumTypeNodes; -use move_vm_types::loaded_data::runtime_types::Type; +use move_vm_types::ty_interner::TypeId; use std::{cell::RefCell, collections::BTreeMap, rc::Rc}; /// Variants for each individual instruction cache. Should make sure @@ -31,21 +31,21 @@ pub(crate) enum PerInstructionCache { #[derive(Default)] pub(crate) struct FrameTypeCache { struct_field_type_instantiation: - BTreeMap>, + BTreeMap>, struct_variant_field_type_instantiation: - BTreeMap>, - struct_def_instantiation_type: BTreeMap, + BTreeMap>, + struct_def_instantiation_type: BTreeMap, struct_variant_instantiation_type: - BTreeMap, + BTreeMap, /// For a given field instantiation, the: - /// ((Type of the field, size of the field type) and (Type of its defining struct, + /// ((TypeId of the field, size of the field type) and (TypeId of its defining struct, /// size of its defining struct) field_instantiation: - BTreeMap, + BTreeMap, /// Same as above, bot for variant field instantiations variant_field_instantiation: - BTreeMap, - single_sig_token_type: BTreeMap, + BTreeMap, + single_sig_token_type: BTreeMap, /// Stores a variant for each individual instruction in the /// function's bytecode. We keep the size of the variant to be /// small. The caches are indexed by the index of the given @@ -64,7 +64,7 @@ pub(crate) struct FrameTypeCache { BTreeMap, Rc>)>, /// Cached instantiated local types for generic functions. - pub(crate) instantiated_local_tys: Option>, + pub(crate) instantiated_local_tys: Option>, /// Cached number of type nodes per instantiated local type for gas charging re-use. pub(crate) instantiated_local_ty_counts: Option>, } @@ -97,16 +97,16 @@ impl FrameTypeCache { &mut self, idx: FieldInstantiationIndex, frame: &Frame, - ) -> PartialVMResult<((&Type, NumTypeNodes), (&Type, NumTypeNodes))> { + ) -> PartialVMResult<((TypeId, NumTypeNodes), (TypeId, NumTypeNodes))> { let ((field_ty, field_ty_count), (struct_ty, struct_ty_count)) = Self::get_or(&mut self.field_instantiation, idx, |idx| { let struct_type = frame.field_instantiation_to_struct(idx)?; - let struct_ty_count = NumTypeNodes::new(struct_type.num_nodes() as u64); + let struct_ty_count = NumTypeNodes::new(0); // TODO: revisit gas metering let field_ty = frame.get_generic_field_ty(idx)?; - let field_ty_count = NumTypeNodes::new(field_ty.num_nodes() as u64); + let field_ty_count = NumTypeNodes::new(0); // TODO: revisit gas metering Ok(((field_ty, field_ty_count), (struct_type, struct_ty_count))) })?; - Ok(((field_ty, *field_ty_count), (struct_ty, *struct_ty_count))) + Ok(((*field_ty, *field_ty_count), (*struct_ty, *struct_ty_count))) } // note(inline): do not inline, increases size a lot, might even decrease the performance @@ -114,7 +114,7 @@ impl FrameTypeCache { &mut self, idx: VariantFieldInstantiationIndex, frame: &Frame, - ) -> PartialVMResult<((&Type, NumTypeNodes), (&Type, NumTypeNodes))> { + ) -> PartialVMResult<((TypeId, NumTypeNodes), (TypeId, NumTypeNodes))> { let ((field_ty, field_ty_count), (struct_ty, struct_ty_count)) = Self::get_or(&mut self.variant_field_instantiation, idx, |idx| { let info = frame.variant_field_instantiation_info_at(idx); @@ -122,13 +122,13 @@ impl FrameTypeCache { &info.definition_struct_type, &info.instantiation, )?; - let struct_ty_count = NumTypeNodes::new(struct_type.num_nodes() as u64); + let struct_ty_count = NumTypeNodes::new(0); // TODO: revisit gas metering let field_ty = frame.instantiate_ty(&info.uninstantiated_field_ty, &info.instantiation)?; - let field_ty_count = NumTypeNodes::new(field_ty.num_nodes() as u64); + let field_ty_count = NumTypeNodes::new(0); // TODO: revisit gas metering Ok(((field_ty, field_ty_count), (struct_type, struct_ty_count))) })?; - Ok(((field_ty, *field_ty_count), (struct_ty, *struct_ty_count))) + Ok(((*field_ty, *field_ty_count), (*struct_ty, *struct_ty_count))) } // note(inline): do not inline, increases size a lot, might even decrease the performance @@ -136,13 +136,13 @@ impl FrameTypeCache { &mut self, idx: StructDefInstantiationIndex, frame: &Frame, - ) -> PartialVMResult<(&Type, NumTypeNodes)> { + ) -> PartialVMResult<(TypeId, NumTypeNodes)> { let (ty, ty_count) = Self::get_or(&mut self.struct_def_instantiation_type, idx, |idx| { let ty = frame.get_generic_struct_ty(idx)?; - let ty_count = NumTypeNodes::new(ty.num_nodes() as u64); + let ty_count = NumTypeNodes::new(0); // TODO: revisit gas metering Ok((ty, ty_count)) })?; - Ok((ty, *ty_count)) + Ok((*ty, *ty_count)) } // note(inline): do not inline, increases size a lot, might even decrease the performance @@ -150,7 +150,7 @@ impl FrameTypeCache { &mut self, idx: StructVariantInstantiationIndex, frame: &Frame, - ) -> PartialVMResult<(&Type, NumTypeNodes)> { + ) -> PartialVMResult<(TypeId, NumTypeNodes)> { let (ty, ty_count) = Self::get_or(&mut self.struct_variant_instantiation_type, idx, |idx| { let info = frame.get_struct_variant_instantiation_at(idx); @@ -158,10 +158,10 @@ impl FrameTypeCache { &info.definition_struct_type, &info.instantiation, )?; - let ty_count = NumTypeNodes::new(ty.num_nodes() as u64); + let ty_count = NumTypeNodes::new(0); // TODO: revisit gas metering Ok((ty, ty_count)) })?; - Ok((ty, *ty_count)) + Ok((*ty, *ty_count)) } // note(inline): do not inline, increases size a lot, might even decrease the performance @@ -169,7 +169,7 @@ impl FrameTypeCache { &mut self, idx: StructDefInstantiationIndex, frame: &Frame, - ) -> PartialVMResult<&[(Type, NumTypeNodes)]> { + ) -> PartialVMResult<&[(TypeId, NumTypeNodes)]> { Ok(Self::get_or( &mut self.struct_field_type_instantiation, idx, @@ -178,7 +178,7 @@ impl FrameTypeCache { .instantiate_generic_struct_fields(idx)? .into_iter() .map(|ty| { - let num_nodes = NumTypeNodes::new(ty.num_nodes() as u64); + let num_nodes = NumTypeNodes::new(0); // TODO: revisit gas metering (ty, num_nodes) }) .collect::>()) @@ -191,7 +191,7 @@ impl FrameTypeCache { &mut self, idx: StructVariantInstantiationIndex, frame: &Frame, - ) -> PartialVMResult<&[(Type, NumTypeNodes)]> { + ) -> PartialVMResult<&[(TypeId, NumTypeNodes)]> { Ok(Self::get_or( &mut self.struct_variant_field_type_instantiation, idx, @@ -200,7 +200,7 @@ impl FrameTypeCache { .instantiate_generic_struct_variant_fields(idx)? .into_iter() .map(|ty| { - let num_nodes = NumTypeNodes::new(ty.num_nodes() as u64); + let num_nodes = NumTypeNodes::new(0); // TODO: revisit gas metering (ty, num_nodes) }) .collect::>()) @@ -213,13 +213,13 @@ impl FrameTypeCache { &mut self, idx: SignatureIndex, frame: &Frame, - ) -> PartialVMResult<(&Type, NumTypeNodes)> { + ) -> PartialVMResult<(TypeId, NumTypeNodes)> { let (ty, ty_count) = Self::get_or(&mut self.single_sig_token_type, idx, |idx| { let ty = frame.instantiate_single_type(idx)?; - let ty_count = NumTypeNodes::new(ty.num_nodes() as u64); + let ty_count = NumTypeNodes::new(0); // TODO: revisit gas metering Ok((ty, ty_count)) })?; - Ok((ty, *ty_count)) + Ok((*ty, *ty_count)) } pub(crate) fn make_rc() -> Rc> { diff --git a/third_party/move/move-vm/runtime/src/interpreter.rs b/third_party/move/move-vm/runtime/src/interpreter.rs index f23bdd3a25c2d..f610cf87bb929 100644 --- a/third_party/move/move-vm/runtime/src/interpreter.rs +++ b/third_party/move/move-vm/runtime/src/interpreter.rs @@ -46,9 +46,8 @@ use move_core_types::{ use move_vm_types::{ debug_write, debug_writeln, gas::{GasMeter, SimpleInstruction}, - loaded_data::{runtime_access_specifier::AccessInstance, runtime_types::Type}, natives::function::NativeResult, - ty_interner::InternedTypePool, + ty_interner::{InternedTypePool, TypeId, TypeRepr}, values::{ self, AbstractFunction, Closure, GlobalValue, Locals, Reference, SignerRef, Struct, StructRef, VMValueCast, Value, Vector, VectorRef, @@ -139,7 +138,7 @@ pub(crate) struct InterpreterImpl<'ctx, LoaderImpl> { /// Operand stack, where Move `Value`s are stored for stack operations. pub(crate) operand_stack: Stack, /// The stack of active functions. - call_stack: CallStack, + call_stack: CallStack<'ctx>, /// VM configuration used by the interpreter. vm_config: &'ctx VMConfig, /// Pool of interned types. @@ -152,6 +151,7 @@ pub(crate) struct InterpreterImpl<'ctx, LoaderImpl> { /// are metered. loader: &'ctx LoaderImpl, /// Checks depth of types of values. Used to bound packing too deep structs or vectors. + #[allow(dead_code)] ty_depth_checker: &'ctx TypeDepthChecker<'ctx, LoaderImpl>, /// Converts runtime types ([Type]) to layouts for (de)serialization. layout_converter: &'ctx LayoutConverter<'ctx, LoaderImpl>, @@ -159,12 +159,12 @@ pub(crate) struct InterpreterImpl<'ctx, LoaderImpl> { ref_state: RefCheckState, } -struct TypeWithRuntimeEnvironment<'a, 'b> { - ty: &'a Type, - runtime_environment: &'b RuntimeEnvironment, +struct TypeWithRuntimeEnvironment<'a> { + ty: TypeId, + runtime_environment: &'a RuntimeEnvironment, } -impl TypeView for TypeWithRuntimeEnvironment<'_, '_> { +impl TypeView for TypeWithRuntimeEnvironment<'_> { fn to_type_tag(&self) -> TypeTag { self.runtime_environment.ty_to_ty_tag(self.ty).unwrap() } @@ -203,7 +203,7 @@ impl Interpreter { } } -impl InterpreterImpl<'_, LoaderImpl> +impl<'ctx, LoaderImpl> InterpreterImpl<'ctx, LoaderImpl> where LoaderImpl: Loader, { @@ -305,7 +305,7 @@ where &mut self, gas_meter: &mut impl GasMeter, traversal_context: &mut TraversalContext, - current_frame: &Frame, + current_frame: &Frame<'ctx>, idx: FunctionInstantiationIndex, ) -> VMResult { let (ty_args, ty_args_id) = current_frame @@ -330,7 +330,7 @@ where &mut self, gas_meter: &mut impl GasMeter, traversal_context: &mut TraversalContext, - current_frame: &Frame, + current_frame: &Frame<'ctx>, fh_idx: FunctionHandleIndex, ) -> VMResult { let ty_args_id = self.ty_pool.intern_ty_args(&[]); @@ -387,6 +387,7 @@ where gas_meter, CallType::Regular, self.vm_config, + self.ty_pool, function, locals, frame_cache, @@ -440,19 +441,19 @@ where // We are not runtime checking this function, but in the caller, // so we must push the return types of the function onto the type stack, // following the runtime type checking protocol. - let ty_args = current_frame.function.ty_args(); + let ty_args = current_frame + .function + .ty_arg_ids(self.loader.runtime_environment()); if ty_args.is_empty() { - for ret_ty in current_frame.function.return_tys() { + for ret_ty in current_frame.function.return_ty_ids() { self.operand_stack - .push_ty(ret_ty.clone()) + .push_ty(*ret_ty) .map_err(|e| set_err_info!(current_frame, e))? } } else { for ret_ty in current_frame.function.return_tys() { - let ret_ty = current_frame - .ty_builder() - .create_ty_with_subst(ret_ty, ty_args) - .map_err(|e| set_err_info!(current_frame, e))?; + let ret_ty = self.ty_pool.instantiate_and_intern(ret_ty, &ty_args); + //.map_err(|e| set_err_info!(current_frame, e))?; self.operand_stack .push_ty(ret_ty) .map_err(|e| set_err_info!(current_frame, e))? @@ -626,10 +627,10 @@ where function.owner_as_module()?.self_id(), function.name(), function - .ty_args() + .ty_arg_ids(self.loader.runtime_environment()) .iter() .map(|ty| TypeWithRuntimeEnvironment { - ty, + ty: *ty, runtime_environment: self.loader.runtime_environment(), }), self.operand_stack @@ -764,12 +765,31 @@ where #[cfg_attr(feature = "force-inline", inline(always))] fn check_return_tys( &self, - current_frame: &mut Frame, + current_frame: &mut Frame<'ctx>, ) -> PartialVMResult<()> { - let expected_ret_tys = current_frame.function.return_tys(); + let ty_pool = ¤t_frame.ty_pool; + let ty_args = current_frame.function.ty_args(); + + // Get expected return type IDs + let expected_ret_ty_ids: Vec = if ty_args.is_empty() { + // Non-generic: use pre-computed TypeIds + current_frame.function.return_ty_ids().to_vec() + } else { + // Generic: instantiate and intern on the fly + let ty_arg_ids = current_frame + .function + .ty_arg_ids(self.loader.runtime_environment()); + current_frame + .function + .return_tys() + .iter() + .map(|ty| ty_pool.instantiate_and_intern(ty, &ty_arg_ids)) + .collect() + }; + if !RTTCheck::is_partial_checker() && self.call_stack.0.is_empty() - && self.operand_stack.types.len() != expected_ret_tys.len() + && self.operand_stack.types.len() != expected_ret_ty_ids.len() { // If we have full stack available and this is the outermost call on the stack, the // type stack must contain exactly the expected number of returns. @@ -778,21 +798,13 @@ where ) .with_sub_status(EPARANOID_FAILURE)); } - if expected_ret_tys.is_empty() { + if expected_ret_ty_ids.is_empty() { return Ok(()); } - let given_ret_tys = self.operand_stack.last_n_tys(expected_ret_tys.len())?; - for (expected, given) in expected_ret_tys.iter().zip(given_ret_tys) { - let ty_args = current_frame.function.ty_args(); - if ty_args.is_empty() { - given.paranoid_check_assignable(expected)?; - } else { - let expected_inst = self - .vm_config - .ty_builder - .create_ty_with_subst(expected, ty_args)?; - given.paranoid_check_assignable(&expected_inst)?; - } + + let given_ret_tys = self.operand_stack.last_n_tys(expected_ret_ty_ids.len())?; + for (expected_id, given_id) in expected_ret_ty_ids.iter().zip(given_ret_tys) { + ty_pool.paranoid_check_assignable(*given_id, *expected_id)?; } Ok(()) @@ -801,7 +813,7 @@ where #[cfg_attr(feature = "force-inline", inline(always))] fn set_new_call_frame( &mut self, - current_frame: &mut Frame, + current_frame: &mut Frame<'ctx>, gas_meter: &mut impl GasMeter, function: Rc, call_type: CallType, @@ -854,14 +866,14 @@ where #[inline(always)] fn make_call_frame( &mut self, - current_frame: &Frame, + current_frame: &Frame<'ctx>, gas_meter: &mut impl GasMeter, function: Rc, call_type: CallType, frame_cache: Rc>, mask: ClosureMask, mut captured: Vec, - ) -> PartialVMResult { + ) -> PartialVMResult> { let num_locals = function.local_tys().len(); let mut locals = Locals::new(num_locals); let num_param_tys = function.param_tys().len(); @@ -882,20 +894,18 @@ where if should_check && !is_captured { // Only perform paranoid type check for actual operands on the stack. // Captured arguments are already verified against function signature. - let ty_args = function.ty_args(); let ty = self.operand_stack.pop_ty()?; - let expected_ty = &function.local_tys()[i]; - if !ty_args.is_empty() { - let expected_ty = self - .vm_config - .ty_builder - .create_ty_with_subst(expected_ty, ty_args)?; - // For parameter to argument, use assignability - ty.paranoid_check_assignable(&expected_ty)?; + let expected_ty_id = if function.ty_args().is_empty() { + // Non-generic: use pre-computed TypeId + function.param_ty_ids()[i] } else { - // Directly check against the expected type to save a clone here. - ty.paranoid_check_assignable(expected_ty)?; - } + // Generic: instantiate and intern on the fly + let ty_arg_ids = function.ty_arg_ids(self.loader.runtime_environment()); + let param_ty = &function.param_tys()[i]; + self.ty_pool.instantiate_and_intern(param_ty, &ty_arg_ids) + }; + // For parameter to argument, use assignability + self.ty_pool.paranoid_check_assignable(ty, expected_ty_id)?; } } RTRCheck::core_call_transition(num_param_tys, num_locals, mask, &mut self.ref_state)?; @@ -903,6 +913,7 @@ where gas_meter, call_type, self.vm_config, + self.ty_pool, function, locals, frame_cache, @@ -912,7 +923,7 @@ where /// Call a native functions. fn call_native( &mut self, - current_frame: &mut Frame, + current_frame: &mut Frame<'ctx>, data_cache: &mut impl MoveVmDataCache, function_caches: &mut InterpreterFunctionCaches, gas_meter: &mut impl GasMeter, @@ -954,7 +965,7 @@ where fn call_native_impl( &mut self, - current_frame: &mut Frame, + current_frame: &mut Frame<'ctx>, data_cache: &mut impl MoveVmDataCache, function_caches: &mut InterpreterFunctionCaches, gas_meter: &mut impl GasMeter, @@ -964,8 +975,6 @@ where mask: ClosureMask, mut captured: Vec, ) -> PartialVMResult<()> { - let ty_builder = &self.vm_config.ty_builder; - let num_param_tys = function.param_tys().len(); let mut args = VecDeque::new(); for i in (0..num_param_tys).rev() { @@ -983,28 +992,40 @@ where let ty_args = function.ty_args(); if RTTCheck::should_perform_checks(¤t_frame.function.function) { for i in (0..num_param_tys).rev() { - let expected_ty = &function.param_tys()[i]; if !mask.is_captured(i) { let ty = self.operand_stack.pop_ty()?; // For param type to argument, use assignability - if !ty_args.is_empty() { - let expected_ty = ty_builder.create_ty_with_subst(expected_ty, ty_args)?; - ty.paranoid_check_assignable(&expected_ty)?; + let expected_ty_id = if ty_args.is_empty() { + // Non-generic: use pre-computed TypeId + function.param_ty_ids()[i] } else { - ty.paranoid_check_assignable(expected_ty)?; - } + // Generic: instantiate and intern on the fly + let ty_arg_ids = function.ty_arg_ids(self.loader.runtime_environment()); + let param_ty = &function.param_tys()[i]; + self.ty_pool.instantiate_and_intern(param_ty, &ty_arg_ids) + }; + self.ty_pool.paranoid_check_assignable(ty, expected_ty_id)?; arg_tys.push_front(ty); } else { - arg_tys.push_front(expected_ty.clone()) + // For captured arguments, compute the expected TypeId + let expected_ty_id = if ty_args.is_empty() { + function.param_ty_ids()[i] + } else { + let ty_arg_ids = function.ty_arg_ids(self.loader.runtime_environment()); + let param_ty = &function.param_tys()[i]; + self.ty_pool.instantiate_and_intern(param_ty, &ty_arg_ids) + }; + arg_tys.push_front(expected_ty_id); } } } let native_function = function.get_native()?; + let ty_arg_ids = function.ty_arg_ids(self.loader.runtime_environment()); gas_meter.charge_native_function_before_execution( - ty_args.iter().map(|ty| TypeWithRuntimeEnvironment { - ty, + ty_arg_ids.iter().map(|ty| TypeWithRuntimeEnvironment { + ty: *ty, runtime_environment: self.loader.runtime_environment(), }), args.iter(), @@ -1018,7 +1039,7 @@ where gas_meter, traversal_context, ); - let result = native_function(&mut native_context, ty_args.to_vec(), args)?; + let result = native_function(&mut native_context, &ty_arg_ids, args)?; // Note(Gas): The order by which gas is charged / error gets returned MUST NOT be modified // here or otherwise it becomes an incompatible change!!! @@ -1046,12 +1067,12 @@ where // satisfy runtime check protocol. if RTTCheck::should_perform_checks(¤t_frame.function.function) { if function.ty_args().is_empty() { - for ty in function.return_tys() { - self.operand_stack.push_ty(ty.clone())?; + for ty in function.return_ty_ids() { + self.operand_stack.push_ty(*ty)?; } } else { for ty in function.return_tys() { - let ty = ty_builder.create_ty_with_subst(ty, ty_args)?; + let ty = self.ty_pool.instantiate_and_intern(ty, &ty_arg_ids); self.operand_stack.push_ty(ty)?; } } @@ -1087,7 +1108,7 @@ where } => { gas_meter.charge_native_function(cost, Option::>::None)?; - let ty_args_id = self.ty_pool.intern_ty_args(&ty_args); + let ty_args_id = self.ty_pool.intern_ty_slice(&ty_args); let target_func = current_frame.build_loaded_function_from_name_and_ty_args( self.loader, gas_meter, @@ -1210,7 +1231,7 @@ where gas_meter: &mut impl GasMeter, traversal_context: &mut TraversalContext, addr: AccountAddress, - ty: &Type, + ty: TypeId, ) -> PartialVMResult<&'cache mut GlobalValue> { let (gv, bytes_loaded) = data_cache.load_resource_mut(gas_meter, traversal_context, &addr, ty)?; @@ -1236,7 +1257,7 @@ where gas_meter: &mut impl GasMeter, traversal_context: &mut TraversalContext, addr: AccountAddress, - ty: &Type, + ty: TypeId, ) -> PartialVMResult<&'cache GlobalValue> { let (gv, bytes_loaded) = data_cache.load_resource(gas_meter, traversal_context, &addr, ty)?; @@ -1264,7 +1285,7 @@ where gas_meter: &mut impl GasMeter, traversal_context: &mut TraversalContext, addr: AccountAddress, - ty: &Type, + ty: TypeId, ) -> PartialVMResult<()> { let runtime_environment = self.loader.runtime_environment(); let gv = if is_mut { @@ -1302,13 +1323,13 @@ where fn check_access( &self, runtime_environment: &RuntimeEnvironment, - kind: AccessKind, - ty: &Type, - addr: AccountAddress, + _kind: AccessKind, + ty: TypeId, + _addr: AccountAddress, ) -> PartialVMResult<()> { - let (struct_idx, instance) = match ty { - Type::Struct { idx, .. } => (*idx, [].as_slice()), - Type::StructInstantiation { idx, ty_args, .. } => (*idx, ty_args.as_slice()), + let ty_pool = runtime_environment.ty_pool(); + let idx = match ty_pool.type_repr(ty) { + TypeRepr::Struct { idx, .. } => idx, _ => { return Err( PartialVMError::new(StatusCode::UNKNOWN_INVARIANT_VIOLATION_ERROR) @@ -1318,16 +1339,17 @@ where }; let struct_name = runtime_environment .struct_name_index_map() - .idx_to_struct_name(struct_idx)?; + .idx_to_struct_name(idx)?; // Perform resource reentrancy check self.reentrancy_checker .check_resource_access(&struct_name)?; // Perform resource access control - if let Some(access) = AccessInstance::new(kind, struct_name, instance, addr) { - self.access_control.check_access(access)? - } + // TODO: support access control? It is disabled anyway, so can keep like this for now. + // if let Some(access) = AccessInstance::new(kind, struct_name, &instance, addr) { + // self.access_control.check_access(access)? + // } Ok(()) } @@ -1339,7 +1361,7 @@ where gas_meter: &mut impl GasMeter, traversal_context: &mut TraversalContext, addr: AccountAddress, - ty: &Type, + ty: TypeId, ) -> PartialVMResult<()> { let runtime_environment = self.loader.runtime_environment(); let gv = self.load_resource(data_cache, gas_meter, traversal_context, addr, ty)?; @@ -1365,7 +1387,7 @@ where gas_meter: &mut impl GasMeter, traversal_context: &mut TraversalContext, addr: AccountAddress, - ty: &Type, + ty: TypeId, ) -> PartialVMResult<()> { let runtime_environment = self.loader.runtime_environment(); let resource = match self @@ -1409,7 +1431,7 @@ where gas_meter: &mut impl GasMeter, traversal_context: &mut TraversalContext, addr: AccountAddress, - ty: &Type, + ty: TypeId, resource: Value, ) -> PartialVMResult<()> { let runtime_environment = self.loader.runtime_environment(); @@ -1454,7 +1476,7 @@ where fn attach_state_if_invariant_violation( &self, mut err: VMError, - current_frame: &Frame, + current_frame: &Frame<'ctx>, ) -> VMError { // A verification error can be returned when // 1) some check fails at runtime, e.g. type layout has too many type @@ -1495,7 +1517,7 @@ where buf: &mut B, runtime_environment: &RuntimeEnvironment, idx: usize, - frame: &Frame, + frame: &Frame<'ctx>, ) -> PartialVMResult<()> { debug_write!(buf, " [{}] ", idx)?; @@ -1504,11 +1526,11 @@ where debug_write!(buf, "{}", function.name_as_pretty_string())?; // Print out type arguments, if they exist. - let ty_args = function.ty_args(); + let ty_args = function.ty_arg_ids(runtime_environment); if !ty_args.is_empty() { let mut ty_tags = vec![]; - for ty in ty_args { - let tag = runtime_environment.ty_to_ty_tag(ty)?; + for ty in ty_args.iter() { + let tag = runtime_environment.ty_to_ty_tag(*ty)?; ty_tags.push(tag); } debug_write!(buf, "<")?; @@ -1559,7 +1581,7 @@ where /// It is used when generating a core dump but can be used for debugging of the interpreter. /// It will be exposed via a debug module to give developers a way to print the internals /// of an execution. - fn internal_state_str(&self, current_frame: &Frame) -> String { + fn internal_state_str(&self, current_frame: &Frame<'ctx>) -> String { let mut internal_state = "Call stack:\n".to_string(); for (i, frame) in self.call_stack.0.iter().enumerate() { internal_state.push_str( @@ -1610,7 +1632,7 @@ where } } -impl InterpreterDebugInterface for InterpreterImpl<'_, LoaderImpl> +impl<'ctx, LoaderImpl> InterpreterDebugInterface for InterpreterImpl<'ctx, LoaderImpl> where LoaderImpl: Loader, { @@ -1667,7 +1689,7 @@ pub(crate) const ACCESS_STACK_SIZE_LIMIT: usize = 256; /// The operand and runtime-type stacks. pub(crate) struct Stack { value: Vec, - types: Vec, + types: Vec, } impl Debug for Stack { @@ -1747,7 +1769,7 @@ impl Stack { /// Push a type on the stack if the max stack size has not been reached. Abort execution /// otherwise. // note(inline): bloats runtime_type_checks - pub(crate) fn push_ty(&mut self, ty: Type) -> PartialVMResult<()> { + pub(crate) fn push_ty(&mut self, ty: TypeId) -> PartialVMResult<()> { if self.types.len() < OPERAND_STACK_SIZE_LIMIT { self.types.push(ty); Ok(()) @@ -1758,7 +1780,7 @@ impl Stack { /// Pop a type off the stack or abort execution if the stack is empty. // note(inline): bloats runtime_type_checks - pub(crate) fn pop_ty(&mut self) -> PartialVMResult { + pub(crate) fn pop_ty(&mut self) -> PartialVMResult { self.types.pop().ok_or_else(|| { PartialVMError::new(StatusCode::EMPTY_VALUE_STACK) .with_message("runtime type stack empty") @@ -1766,8 +1788,8 @@ impl Stack { } // note(inline): bloats runtime_type_checks - pub(crate) fn top_ty(&mut self) -> PartialVMResult<&Type> { - self.types.last().ok_or_else(|| { + pub(crate) fn top_ty(&mut self) -> PartialVMResult { + self.types.last().copied().ok_or_else(|| { PartialVMError::new(StatusCode::EMPTY_VALUE_STACK) .with_message("runtime type stack empty") }) @@ -1775,7 +1797,7 @@ impl Stack { /// Pop n types off the stack. // note(inline): bloats runtime_type_checks - pub(crate) fn popn_tys(&mut self, n: u16) -> PartialVMResult> { + pub(crate) fn popn_tys(&mut self, n: u16) -> PartialVMResult> { let remaining_stack_size = self.types.len().checked_sub(n as usize).ok_or_else(|| { PartialVMError::new(StatusCode::EMPTY_VALUE_STACK) .with_message("runtime type stack empty") @@ -1794,7 +1816,7 @@ impl Stack { Ok(()) } - fn last_n_tys(&self, n: usize) -> PartialVMResult<&[Type]> { + fn last_n_tys(&self, n: usize) -> PartialVMResult<&[TypeId]> { if self.types.len() < n { return Err( PartialVMError::new(StatusCode::EMPTY_VALUE_STACK).with_message(format!( @@ -1822,9 +1844,9 @@ impl Stack { /// A call stack. // #[derive(Debug)] -struct CallStack(Vec); +struct CallStack<'ctx>(Vec>); -impl CallStack { +impl<'ctx> CallStack<'ctx> { /// Create a new empty call stack. fn new() -> Self { CallStack(vec![]) @@ -1832,7 +1854,7 @@ impl CallStack { /// Push a `Frame` on the call stack. #[cfg_attr(feature = "inline-callstack", inline(always))] - fn push(&mut self, frame: Frame) -> Result<(), Frame> { + fn push(&mut self, frame: Frame<'ctx>) -> Result<(), Frame<'ctx>> { if self.0.len() < CALL_STACK_SIZE_LIMIT { self.0.push(frame); Ok(()) @@ -1843,7 +1865,7 @@ impl CallStack { /// Pop a `Frame` off the call stack. #[cfg_attr(feature = "inline-callstack", inline(always))] - fn pop(&mut self) -> Option { + fn pop(&mut self) -> Option> { self.0.pop() } @@ -1862,7 +1884,7 @@ enum ExitCode { CallClosure(SignatureIndex), } -impl Frame { +impl<'ctx> Frame<'ctx> { /// Execute a Move function until a return or a call opcode is found. fn execute_code( &mut self, @@ -2184,12 +2206,12 @@ impl Frame { }, Bytecode::Pack(sd_idx) => { let field_count = self.field_count(*sd_idx); - let struct_type = self.get_struct_ty(*sd_idx); - interpreter.ty_depth_checker.check_depth_of_type( - gas_meter, - traversal_context, - &struct_type, - )?; + // let _struct_type = self.get_struct_ty(*sd_idx); + // interpreter.ty_depth_checker.check_depth_of_type( + // gas_meter, + // traversal_context, + // &struct_type, + // )?; gas_meter.charge_pack( false, @@ -2202,12 +2224,12 @@ impl Frame { }, Bytecode::PackVariant(idx) => { let info = self.get_struct_variant_at(*idx); - let struct_type = self.create_struct_ty(&info.definition_struct_type); - interpreter.ty_depth_checker.check_depth_of_type( - gas_meter, - traversal_context, - &struct_type, - )?; + // let _struct_type = self.create_struct_ty(&info.definition_struct_type); + // interpreter.ty_depth_checker.check_depth_of_type( + // gas_meter, + // traversal_context, + // &struct_type, + // )?; gas_meter.charge_pack_variant( false, interpreter @@ -2230,13 +2252,13 @@ impl Frame { gas_meter.charge_create_ty(*ty_count)?; } - let (ty, ty_count) = frame_cache.get_struct_type(*si_idx, self)?; + let (_, ty_count) = frame_cache.get_struct_type(*si_idx, self)?; gas_meter.charge_create_ty(ty_count)?; - interpreter.ty_depth_checker.check_depth_of_type( - gas_meter, - traversal_context, - ty, - )?; + // interpreter.ty_depth_checker.check_depth_of_type( + // gas_meter, + // traversal_context, + // ty, + // )?; let field_count = self.field_instantiation_count(*si_idx); gas_meter.charge_pack( @@ -2256,13 +2278,13 @@ impl Frame { gas_meter.charge_create_ty(*ty_count)?; } - let (ty, ty_count) = frame_cache.get_struct_variant_type(*si_idx, self)?; + let (_, ty_count) = frame_cache.get_struct_variant_type(*si_idx, self)?; gas_meter.charge_create_ty(ty_count)?; - interpreter.ty_depth_checker.check_depth_of_type( - gas_meter, - traversal_context, - ty, - )?; + // interpreter.ty_depth_checker.check_depth_of_type( + // gas_meter, + // traversal_context, + // ty, + // )?; let info = self.get_struct_variant_instantiation_at(*si_idx); gas_meter.charge_pack_variant( @@ -2389,7 +2411,7 @@ impl Frame { RTTCheck::check_pack_closure_visibility(&self.function, &function)?; if RTTCheck::should_perform_checks(&self.function.function) { verify_pack_closure( - self.ty_builder(), + self.ty_pool(), &mut interpreter.operand_stack, &function, *mask, @@ -2446,7 +2468,7 @@ impl Frame { if RTTCheck::should_perform_checks(&self.function.function) { verify_pack_closure( - self.ty_builder(), + self.ty_pool(), &mut interpreter.operand_stack, &function, *mask, @@ -2670,7 +2692,7 @@ impl Frame { gas_meter, traversal_context, addr, - &ty, + ty, )?; }, Bytecode::MutBorrowGlobalGeneric(si_idx) @@ -2698,7 +2720,7 @@ impl Frame { gas_meter, traversal_context, addr, - &ty, + ty, )?; }, Bytecode::ExistsGeneric(si_idx) => { @@ -2723,7 +2745,7 @@ impl Frame { gas_meter, traversal_context, addr, - &ty, + ty, )?; }, Bytecode::MoveFromGeneric(si_idx) => { @@ -2754,7 +2776,7 @@ impl Frame { gas_meter, traversal_context, addr, - &ty, + ty, resource, )?; }, @@ -2794,11 +2816,11 @@ impl Frame { Bytecode::VecPack(si, num) => { let (ty, ty_count) = frame_cache.get_signature_index_type(*si, self)?; gas_meter.charge_create_ty(ty_count)?; - interpreter.ty_depth_checker.check_depth_of_type( - gas_meter, - traversal_context, - ty, - )?; + // interpreter.ty_depth_checker.check_depth_of_type( + // gas_meter, + // traversal_context, + // ty, + // )?; gas_meter .charge_vec_pack(interpreter.operand_stack.last_n(*num as usize)?)?; let elements = interpreter.operand_stack.popn(*num as u16)?; diff --git a/third_party/move/move-vm/runtime/src/loader/function.rs b/third_party/move/move-vm/runtime/src/loader/function.rs index 62e19e0ea1460..56207c9ca9d9f 100644 --- a/third_party/move/move-vm/runtime/src/loader/function.rs +++ b/third_party/move/move-vm/runtime/src/loader/function.rs @@ -7,6 +7,7 @@ use crate::{ module_traversal::TraversalContext, native_functions::{NativeFunction, NativeFunctions, UnboxedNativeFunction}, storage::{loader::traits::Loader, ty_layout_converter::LayoutConverter}, + RuntimeEnvironment, }; use better_any::{Tid, TidAble, TidExt}; use move_binary_format::{ @@ -33,7 +34,7 @@ use move_vm_types::{ runtime_types::{StructIdentifier, Type}, }, module_id_interner::InternedModuleId, - ty_interner::TypeVecId, + ty_interner::{InternedTypePool, TypeId, TypeVecId}, values::{AbstractFunction, SerializedFunctionData}, }; use std::{ @@ -47,6 +48,7 @@ use std::{ }; /// A runtime function definition representation. +#[allow(dead_code)] pub struct Function { #[allow(unused)] pub(crate) file_format_version: u32, @@ -59,6 +61,8 @@ pub struct Function { pub(crate) visibility: Visibility, pub(crate) is_entry: bool, pub(crate) name: Identifier, + + // Type templates (may contain TyParam for generic functions) pub(crate) return_tys: Vec, // For non-native functions: parameter types first and then local types, if any. // For native functions, an empty vector (there are no locals). This is very important because @@ -66,6 +70,12 @@ pub struct Function { // compatible). pub(crate) local_tys: Vec, pub(crate) param_tys: Vec, + + // Pre-computed TypeIds for non-generic functions, empty for generic functions + pub(crate) return_type_ids: Vec, + pub(crate) local_type_ids: Vec, + pub(crate) param_type_ids: Vec, + pub(crate) access_specifier: AccessSpecifier, pub(crate) is_persistent: bool, pub(crate) has_module_reentrancy_lock: bool, @@ -119,7 +129,7 @@ pub struct LoadedFunction { pub owner: LoadedFunctionOwner, // A set of verified type arguments provided for this definition. If // function is not generic, an empty vector. - pub ty_args: Vec, + pub ty_args: Vec, // Unique identifier for type arguments. pub ty_args_id: TypeVecId, // Definition of the loaded function. @@ -241,10 +251,10 @@ impl LazyLoadedFunction { mask: ClosureMask, ) -> PartialVMResult { let runtime_environment = layout_converter.runtime_environment(); - let ty_args = fun - .ty_args + let ty_arg_ids = fun.ty_arg_ids(runtime_environment); + let ty_args = ty_arg_ids .iter() - .map(|t| runtime_environment.ty_to_ty_tag(t)) + .map(|t| runtime_environment.ty_to_ty_tag(*t)) .collect::>>()?; // When building a closure, if it captures arguments, and it is persistent (i.e., it may @@ -293,37 +303,45 @@ impl LazyLoadedFunction { fun: &LoadedFunction, mask: ClosureMask, ) -> PartialVMResult>> { - let ty_builder = &layout_converter - .runtime_environment() - .vm_config() - .ty_builder; - mask.extract(fun.param_tys(), true) - .into_iter() - .map(|ty| { - let layout = if fun.ty_args.is_empty() { - layout_converter.type_to_type_layout_with_delayed_fields( + let ty_pool = layout_converter.runtime_environment().ty_pool(); + if fun.ty_args.is_empty() { + mask.extract(fun.param_ty_ids(), true) + .into_iter() + .map(|ty_id| { + let layout = layout_converter.type_to_type_layout_with_delayed_fields( gas_meter, traversal_context, - ty, + *ty_id, true, - )? - } else { - let ty = ty_builder.create_ty_with_subst(ty, &fun.ty_args)?; - layout_converter.type_to_type_layout_with_delayed_fields( + )?; + + // Do not allow delayed fields to be serialized. + // TODO(layouts): consider not cloning layouts for captured arguments. + Ok(layout + .into_layout_when_has_no_delayed_fields() + .map(|l| l.as_ref().clone())) + }) + .collect::>>>() + } else { + mask.extract(fun.param_tys(), true) + .into_iter() + .map(|ty| { + let id = ty_pool.instantiate_and_intern(ty, &fun.ty_args); + let layout = layout_converter.type_to_type_layout_with_delayed_fields( gas_meter, traversal_context, - &ty, + id, true, - )? - }; + )?; - // Do not allow delayed fields to be serialized. - // TODO(layouts): consider not cloning layouts for captured arguments. - Ok(layout - .into_layout_when_has_no_delayed_fields() - .map(|l| l.as_ref().clone())) - }) - .collect::>>>() + // Do not allow delayed fields to be serialized. + // TODO(layouts): consider not cloning layouts for captured arguments. + Ok(layout + .into_layout_when_has_no_delayed_fields() + .map(|l| l.as_ref().clone())) + }) + .collect::>>>() + } } pub(crate) fn expect_this_impl( @@ -455,10 +473,19 @@ impl AbstractFunction for LazyLoadedFunction { impl LoadedFunction { /// Returns type arguments used to instantiate the loaded function. - pub fn ty_args(&self) -> &[Type] { + pub fn ty_args(&self) -> &[TypeId] { &self.ty_args } + /// Returns type argument IDs used to instantiate the loaded function. + pub fn ty_arg_ids(&self, runtime_environment: &RuntimeEnvironment) -> Arc<[TypeId]> { + runtime_environment.ty_pool().get_type_vec(self.ty_args_id) + } + + pub fn ty_arg_ids_from_pool(&self, pool: &InternedTypePool) -> Arc<[TypeId]> { + pool.get_type_vec(self.ty_args_id) + } + /// Returns the corresponding module id of this function, i.e., its address and module name. pub fn module_id(&self) -> Option<&ModuleId> { match &self.owner { @@ -520,11 +547,19 @@ impl LoadedFunction { self.function.param_tys() } + pub fn param_ty_ids(&self) -> &[TypeId] { + &self.function.param_type_ids + } + /// Returns return types from the function's definition signature. pub fn return_tys(&self) -> &[Type] { self.function.return_tys() } + pub fn return_ty_ids(&self) -> &[TypeId] { + &self.function.return_type_ids + } + /// Returns abilities of type parameters from the function's definition signature. pub fn ty_param_abilities(&self) -> &[AbilitySet] { self.function.ty_param_abilities() @@ -535,6 +570,10 @@ impl LoadedFunction { self.function.local_tys() } + pub fn local_type_ids(&self) -> &[TypeId] { + &self.function.local_type_ids + } + /// Returns true if this function is a native function, i.e. which does not contain /// code and instead using the Rust implementation. pub fn is_native(&self) -> bool { @@ -590,6 +629,7 @@ impl Function { module: &CompiledModule, signature_table: &[Vec], struct_names: &[StructIdentifier], + ty_pool: &InternedTypePool, ) -> PartialVMResult { let def = module.function_def_at(index); let handle = module.function_handle_at(def.function); @@ -633,6 +673,27 @@ impl Function { &handle.access_specifiers, )?; + // Compute TypeIds for non-generic functions + let (return_type_ids, local_type_ids, param_type_ids) = if ty_param_abilities.is_empty() { + // Non-generic: compute TypeIds by interning the types + let return_type_ids = return_tys + .iter() + .map(|ty| ty_pool.instantiate_and_intern(ty, &[])) + .collect(); + let local_type_ids = local_tys + .iter() + .map(|ty| ty_pool.instantiate_and_intern(ty, &[])) + .collect(); + let param_type_ids = param_tys + .iter() + .map(|ty| ty_pool.instantiate_and_intern(ty, &[])) + .collect(); + (return_type_ids, local_type_ids, param_type_ids) + } else { + // Generic: leave empty, will be computed at instantiation time + (vec![], vec![], vec![]) + }; + Ok(Self { file_format_version: module.version(), index, @@ -646,6 +707,9 @@ impl Function { local_tys, return_tys, param_tys, + return_type_ids, + local_type_ids, + param_type_ids, access_specifier, is_persistent: handle.attributes.contains(&FunctionAttribute::Persistent), has_module_reentrancy_lock: handle.attributes.contains(&FunctionAttribute::ModuleLock), diff --git a/third_party/move/move-vm/runtime/src/loader/modules.rs b/third_party/move/move-vm/runtime/src/loader/modules.rs index 27cb76dc666f0..7fab835f22c5c 100644 --- a/third_party/move/move-vm/runtime/src/loader/modules.rs +++ b/third_party/move/move-vm/runtime/src/loader/modules.rs @@ -266,6 +266,7 @@ impl Module { &module, signature_table.as_slice(), &struct_names, + ty_pool, )?; function_map.insert(function.name.to_owned(), idx); diff --git a/third_party/move/move-vm/runtime/src/loader/script.rs b/third_party/move/move-vm/runtime/src/loader/script.rs index b5fae61159fb6..d329780d75d01 100644 --- a/third_party/move/move-vm/runtime/src/loader/script.rs +++ b/third_party/move/move-vm/runtime/src/loader/script.rs @@ -119,6 +119,24 @@ impl Script { .collect::>>()?; let ty_param_abilities = script.type_parameters.clone(); + // Compute TypeIds for non-generic scripts + let (return_type_ids, local_type_ids, param_type_ids) = if ty_param_abilities.is_empty() { + // Non-generic: compute TypeIds by interning the types + let return_type_ids = vec![]; // Scripts don't return values + let local_type_ids = local_tys + .iter() + .map(|ty| ty_pool.instantiate_and_intern(ty, &[])) + .collect(); + let param_type_ids = param_tys + .iter() + .map(|ty| ty_pool.instantiate_and_intern(ty, &[])) + .collect(); + (return_type_ids, local_type_ids, param_type_ids) + } else { + // Generic: leave empty, will be computed at instantiation time + (vec![], vec![], vec![]) + }; + let main: Arc = Arc::new(Function { file_format_version: script.version(), index: FunctionDefinitionIndex(0), @@ -134,6 +152,9 @@ impl Script { return_tys: vec![], local_tys, param_tys, + return_type_ids, + local_type_ids, + param_type_ids, access_specifier: AccessSpecifier::Any, is_persistent: false, has_module_reentrancy_lock: false, diff --git a/third_party/move/move-vm/runtime/src/move_vm.rs b/third_party/move/move-vm/runtime/src/move_vm.rs index e7157a9b02bce..08319676b2417 100644 --- a/third_party/move/move-vm/runtime/src/move_vm.rs +++ b/third_party/move/move-vm/runtime/src/move_vm.rs @@ -22,7 +22,7 @@ use move_core_types::{value::MoveTypeLayout, vm_status::StatusCode}; use move_vm_metrics::{Timer, VM_TIMER}; use move_vm_types::{ gas::GasMeter, - loaded_data::runtime_types::Type, + ty_interner::TypeId, value_serde::{FunctionValueExtension, ValueSerDeContext}, values::{Locals, Reference, VMValueCast, Value}, }; @@ -63,23 +63,22 @@ impl MoveVM { extensions: &mut NativeContextExtensions, loader: &impl Loader, ) -> VMResult { - let vm_config = loader.runtime_environment().vm_config(); - let function_value_extension = FunctionValueExtensionAdapter { module_storage: loader.unmetered_module_storage(), }; let layout_converter = LayoutConverter::new(loader); let ty_depth_checker = TypeDepthChecker::new(loader); - let create_ty_with_subst = |tys: &[Type]| -> VMResult> { - let ty_builder = &vm_config.ty_builder; - tys.iter() - .map(|ty| ty_builder.create_ty_with_subst(ty, function.ty_args())) - .collect::>>() - .map_err(|err| err.finish(Location::Undefined)) + let pool = loader.runtime_environment().ty_pool(); + let param_tys = if function.ty_args.is_empty() { + function.param_ty_ids().to_vec() + } else { + function + .param_tys() + .iter() + .map(|ty| pool.instantiate_and_intern(ty, &function.ty_args)) + .collect::>() }; - - let param_tys = create_ty_with_subst(function.param_tys())?; let (mut dummy_locals, deserialized_args) = deserialize_args( &function_value_extension, &layout_converter, @@ -90,7 +89,15 @@ impl MoveVM { ) .map_err(|err| err.finish(Location::Undefined))?; - let return_tys = create_ty_with_subst(function.return_tys())?; + let return_tys = if function.ty_args.is_empty() { + function.return_ty_ids().to_vec() + } else { + function + .return_tys() + .iter() + .map(|ty| pool.instantiate_and_intern(ty, &function.ty_args)) + .collect::>() + }; let return_values = { let _timer = VM_TIMER.timer_with_label("Interpreter::entrypoint"); @@ -121,9 +128,9 @@ impl MoveVM { let mutable_reference_outputs = param_tys .iter() .enumerate() - .filter_map(|(idx, ty)| match ty { - Type::MutableReference(inner_ty) => Some((idx, inner_ty.as_ref())), - _ => None, + .filter_map(|(idx, ty)| { + let inner_ty = ty.is_mut_ref().then_some(ty.payload())?; + Some((idx, inner_ty)) }) .map(|(idx, ty)| { // serialize return values first in the case that a value points into this local @@ -156,7 +163,7 @@ fn deserialize_arg( layout_converter: &LayoutConverter, gas_meter: &mut impl GasMeter, traversal_context: &mut TraversalContext, - ty: &Type, + ty: TypeId, arg: impl Borrow<[u8]>, ) -> PartialVMResult { let deserialization_error = || -> PartialVMError { @@ -195,7 +202,7 @@ fn deserialize_args( layout_converter: &LayoutConverter, gas_meter: &mut impl GasMeter, traversal_context: &mut TraversalContext, - param_tys: &[Type], + param_tys: &[TypeId], serialized_args: Vec>, ) -> PartialVMResult<(Locals, Vec)> { if param_tys.len() != serialized_args.len() { @@ -217,8 +224,9 @@ fn deserialize_args( .iter() .zip(serialized_args) .enumerate() - .map(|(idx, (ty, arg_bytes))| match ty.get_ref_inner_ty() { - Some(inner_ty) => { + .map(|(idx, (ty, arg_bytes))| { + if ty.is_any_ref() { + let inner_ty = ty.payload(); dummy_locals.store_loc( idx, deserialize_arg( @@ -231,15 +239,16 @@ fn deserialize_args( )?, )?; dummy_locals.borrow_loc(idx) - }, - None => deserialize_arg( - function_value_extension, - layout_converter, - gas_meter, - traversal_context, - ty, - arg_bytes, - ), + } else { + deserialize_arg( + function_value_extension, + layout_converter, + gas_meter, + traversal_context, + *ty, + arg_bytes, + ) + } }) .collect::>>()?; Ok((dummy_locals, deserialized_args)) @@ -250,16 +259,15 @@ fn serialize_return_value( layout_converter: &LayoutConverter, gas_meter: &mut impl GasMeter, traversal_context: &mut TraversalContext, - ty: &Type, + ty: TypeId, value: Value, ) -> PartialVMResult<(Vec, MoveTypeLayout)> { - let (ty, value) = match ty.get_ref_inner_ty() { - Some(inner_ty) => { - let ref_value: Reference = value.cast()?; - let inner_value = ref_value.read_ref()?; - (inner_ty, inner_value) - }, - None => (ty, value), + let (ty, value) = if ty.is_any_ref() { + let ref_value: Reference = value.cast()?; + let inner_value = ref_value.read_ref()?; + (ty.payload(), inner_value) + } else { + (ty, value) }; let serialization_error = || -> PartialVMError { @@ -299,7 +307,7 @@ fn serialize_return_values( layout_converter: &LayoutConverter, gas_meter: &mut impl GasMeter, traversal_context: &mut TraversalContext, - return_tys: &[Type], + return_tys: &[TypeId], return_values: Vec, ) -> PartialVMResult, MoveTypeLayout)>> { if return_tys.len() != return_values.len() { @@ -323,7 +331,7 @@ fn serialize_return_values( layout_converter, gas_meter, traversal_context, - ty, + *ty, value, ) }) diff --git a/third_party/move/move-vm/runtime/src/native_functions.rs b/third_party/move/move-vm/runtime/src/native_functions.rs index edee0a04f4ef2..ef80479af7d42 100644 --- a/third_party/move/move-vm/runtime/src/native_functions.rs +++ b/third_party/move/move-vm/runtime/src/native_functions.rs @@ -11,7 +11,6 @@ use crate::{ module_traversal::TraversalContext, native_extensions::NativeContextExtensions, storage::{ - layout_cache::StructKey, loader::traits::NativeModuleLoader, module_storage::FunctionValueExtensionAdapter, ty_layout_converter::{LayoutConverter, LayoutWithDelayedFields}, @@ -36,8 +35,8 @@ use move_core_types::{ }; use move_vm_types::{ gas::{ambassador_impl_DependencyGasMeter, DependencyGasMeter, DependencyKind, NativeGasMeter}, - loaded_data::runtime_types::Type, natives::function::NativeResult, + ty_interner::TypeId, values::{AbstractFunction, Value}, }; use std::{ @@ -46,7 +45,7 @@ use std::{ }; use triomphe::Arc as TriompheArc; -pub type UnboxedNativeFunction = dyn Fn(&mut NativeContext, Vec, VecDeque) -> PartialVMResult +pub type UnboxedNativeFunction = dyn for<'a> Fn(&mut NativeContext, &'a [TypeId], VecDeque) -> PartialVMResult + Send + Sync + 'static; @@ -151,7 +150,7 @@ impl<'b, 'c> NativeContext<'_, 'b, 'c> { pub fn exists_at( &mut self, address: AccountAddress, - ty: &Type, + ty: TypeId, ) -> PartialVMResult<(bool, Option)> { self.data_cache.native_check_resource_exists( self.gas_meter, @@ -161,7 +160,7 @@ impl<'b, 'c> NativeContext<'_, 'b, 'c> { ) } - pub fn type_to_type_tag(&self, ty: &Type) -> PartialVMResult { + pub fn type_to_type_tag(&self, ty: TypeId) -> PartialVMResult { self.module_storage.runtime_environment().ty_to_ty_tag(ty) } @@ -170,7 +169,7 @@ impl<'b, 'c> NativeContext<'_, 'b, 'c> { /// NOTE: use with caution as this ignores the flag if layout contains delayed fields or not. pub fn type_to_type_layout( &mut self, - ty: &Type, + ty: TypeId, ) -> PartialVMResult> { let layout = self .loader_context() @@ -184,7 +183,7 @@ impl<'b, 'c> NativeContext<'_, 'b, 'c> { /// information whether there are any delayed fields in layouts is returned. pub fn type_to_type_layout_with_delayed_fields( &mut self, - ty: &Type, + ty: TypeId, ) -> PartialVMResult { self.loader_context() .type_to_type_layout_with_delayed_fields(ty) @@ -194,7 +193,7 @@ impl<'b, 'c> NativeContext<'_, 'b, 'c> { /// layout does not contain delayed fields (otherwise, invariant violation is returned). pub fn type_to_type_layout_check_no_delayed_fields( &mut self, - ty: &Type, + ty: TypeId, ) -> PartialVMResult> { let layout = self .loader_context() @@ -211,7 +210,7 @@ impl<'b, 'c> NativeContext<'_, 'b, 'c> { /// nodes are reached, or an internal invariant violation is raised). pub fn type_to_fully_annotated_layout( &mut self, - ty: &Type, + ty: TypeId, ) -> PartialVMResult>> { self.loader_context().type_to_fully_annotated_layout(ty) } @@ -335,7 +334,7 @@ impl<'a, 'b> LoaderContext<'a, 'b> { /// Converts a runtime type into layout for (de)serialization. pub fn type_to_type_layout_with_delayed_fields( &mut self, - ty: &Type, + ty: TypeId, ) -> PartialVMResult { dispatch_loader!(&self.module_storage, loader, { LayoutConverter::new(&loader).type_to_type_layout_with_delayed_fields( @@ -366,7 +365,7 @@ impl<'a, 'b> LoaderContext<'a, 'b> { /// Converts a runtime type into decorated layout for pretty-printing. fn type_to_fully_annotated_layout( &mut self, - ty: &Type, + ty: TypeId, ) -> PartialVMResult>> { let layout = dispatch_loader!(&self.module_storage, loader, { LayoutConverter::new(&loader).type_to_annotated_type_layout_with_delayed_fields( @@ -385,11 +384,11 @@ struct ModuleStorageWrapper<'a> { } impl<'a> LayoutCache for ModuleStorageWrapper<'a> { - fn get_struct_layout(&self, key: &StructKey) -> Option { + fn get_struct_layout(&self, key: TypeId) -> Option { self.module_storage.get_struct_layout(key) } - fn store_struct_layout(&self, key: &StructKey, entry: LayoutCacheEntry) -> PartialVMResult<()> { + fn store_struct_layout(&self, key: TypeId, entry: LayoutCacheEntry) -> PartialVMResult<()> { self.module_storage.store_struct_layout(key, entry) } } diff --git a/third_party/move/move-vm/runtime/src/runtime_ref_checks.rs b/third_party/move/move-vm/runtime/src/runtime_ref_checks.rs index 328355a74491f..6edeaf57b0f41 100644 --- a/third_party/move/move-vm/runtime/src/runtime_ref_checks.rs +++ b/third_party/move/move-vm/runtime/src/runtime_ref_checks.rs @@ -90,7 +90,7 @@ use move_core_types::{ function::ClosureMask, vm_status::{sub_status::unknown_invariant_violation::EREFERENCE_SAFETY_FAILURE, StatusCode}, }; -use move_vm_types::loaded_data::runtime_types::Type; +use move_vm_types::{loaded_data::runtime_types::Type, ty_interner::TypeId}; use std::{collections::BTreeSet, slice}; /// A deterministic hash map (used in the Rust compiler), expected to perform well. @@ -163,7 +163,7 @@ enum AccessPathTreeRoot { /// Root representing a local (non-ref) value Local { index: usize }, /// Root representing a global type - Global { type_: Type }, + Global { id: TypeId }, /// Special node representing the value behind a reference parameter ReferenceParameter { param_index: usize }, } @@ -173,7 +173,7 @@ struct AccessPathTreeRootsInfo { /// Mapping from local index to the corresponding access path tree locals: UnorderedMap, /// Mapping from global type to the corresponding access path tree - globals: UnorderedMap, + globals: UnorderedMap, /// Mapping from reference parameter index to the corresponding access path tree reference_params: UnorderedMap, } @@ -582,7 +582,7 @@ impl RuntimeRefCheck for FullRuntimeRefCheck { }, MutBorrowGlobalGeneric(index) => { let struct_ty = ty_cache.get_struct_type(*index, frame)?.0; - ref_state.borrow_global::(struct_ty.clone())?; + ref_state.borrow_global::(struct_ty)?; }, ImmBorrowGlobal(index) => { let struct_ty = frame.get_struct_ty(*index); @@ -590,7 +590,7 @@ impl RuntimeRefCheck for FullRuntimeRefCheck { }, ImmBorrowGlobalGeneric(index) => { let struct_ty = ty_cache.get_struct_type(*index, frame)?.0; - ref_state.borrow_global::(struct_ty.clone())?; + ref_state.borrow_global::(struct_ty)?; }, Add | Sub | Mul | Mod | Div | BitOr | BitAnd | Xor | Or | And | Lt | Gt | Le | Ge | Shl | Shr => { @@ -620,7 +620,7 @@ impl RuntimeRefCheck for FullRuntimeRefCheck { }, MoveFromGeneric(index) => { let struct_ty = ty_cache.get_struct_type(*index, frame)?.0; - ref_state.move_from(struct_ty.clone())?; + ref_state.move_from(struct_ty)?; }, MoveTo(_) => { ref_state.move_to()?; @@ -870,7 +870,7 @@ impl AccessPathTreeRootsInfo { fn get_access_path_tree(&self, root: &AccessPathTreeRoot) -> PartialVMResult<&AccessPathTree> { match root { AccessPathTreeRoot::Local { index } => Ok(safe_unwrap!(self.locals.get(index))), - AccessPathTreeRoot::Global { type_ } => Ok(safe_unwrap!(self.globals.get(type_))), + AccessPathTreeRoot::Global { id } => Ok(safe_unwrap!(self.globals.get(id))), AccessPathTreeRoot::ReferenceParameter { param_index } => { Ok(safe_unwrap!(self.reference_params.get(param_index))) }, @@ -893,7 +893,7 @@ impl AccessPathTreeRootsInfo { ) -> Option<&mut AccessPathTree> { match root { AccessPathTreeRoot::Local { index } => self.locals.get_mut(index), - AccessPathTreeRoot::Global { type_ } => self.globals.get_mut(type_), + AccessPathTreeRoot::Global { id } => self.globals.get_mut(id), AccessPathTreeRoot::ReferenceParameter { param_index } => { self.reference_params.get_mut(param_index) }, @@ -920,9 +920,9 @@ impl QualifiedNodeID { } /// A root node corresponding to a global type. - fn global_root(type_: Type) -> Self { + fn global_root(id: TypeId) -> Self { Self { - root: AccessPathTreeRoot::Global { type_ }, + root: AccessPathTreeRoot::Global { id }, node_id: 0, // root is always at 0 } } @@ -1139,10 +1139,10 @@ impl FrameRefState { } /// Ensure that the global root exists for the given type. - fn ensure_global_root_exists(&mut self, type_: Type) { + fn ensure_global_root_exists(&mut self, id: TypeId) { self.access_path_tree_roots .globals - .entry(type_) + .entry(id) .or_insert_with(AccessPathTree::new); } @@ -1530,13 +1530,13 @@ impl RefCheckState { /// Transition for borrow global family of instructions. /// We currently abstract over all addresses and only use types. - fn borrow_global(&mut self, type_: Type) -> PartialVMResult<()> { + fn borrow_global(&mut self, id: TypeId) -> PartialVMResult<()> { let _ = self.pop_from_shadow_stack()?; let frame_state = self.get_mut_latest_frame_state()?; - frame_state.ensure_global_root_exists(type_.clone()); + frame_state.ensure_global_root_exists(id); - let node_id = QualifiedNodeID::global_root(type_); + let node_id = QualifiedNodeID::global_root(id); // Unlike references to locals (where borrowing itself does not lead to violations, but use of // poisoned refs does), we perform a stricter check here (similar to bytecode verifier). if MUTABLE && frame_state.subtree_has_references(&node_id, ReferenceFilter::All)? { @@ -1556,13 +1556,13 @@ impl RefCheckState { } /// Transition for `MoveFrom` and `MoveFromGeneric` instruction. - fn move_from(&mut self, type_: Type) -> PartialVMResult<()> { + fn move_from(&mut self, id: TypeId) -> PartialVMResult<()> { let _ = self.pop_from_shadow_stack()?; let frame_state = self.get_mut_latest_frame_state()?; - frame_state.ensure_global_root_exists(type_.clone()); + frame_state.ensure_global_root_exists(id); - let node_id = QualifiedNodeID::global_root(type_); + let node_id = QualifiedNodeID::global_root(id); // Poison all references to the global type's subtree. frame_state.poison_refs_of_node(&node_id, VisitKind::SelfOnly, ReferenceFilter::All)?; frame_state.poison_refs_of_node( diff --git a/third_party/move/move-vm/runtime/src/runtime_type_checks.rs b/third_party/move/move-vm/runtime/src/runtime_type_checks.rs index 9c48ff717eee5..e259a15c85046 100644 --- a/third_party/move/move-vm/runtime/src/runtime_type_checks.rs +++ b/third_party/move/move-vm/runtime/src/runtime_type_checks.rs @@ -11,7 +11,7 @@ use move_core_types::{ function::ClosureMask, vm_status::{sub_status::unknown_invariant_violation::EPARANOID_FAILURE, StatusCode}, }; -use move_vm_types::loaded_data::runtime_types::{Type, TypeBuilder}; +use move_vm_types::ty_interner::{InternedTypePool, TypeId}; pub(crate) trait RuntimeTypeCheck { /// Paranoid type checks to perform before instruction execution. @@ -110,13 +110,14 @@ pub(crate) trait RuntimeTypeCheck { // note(inline): improves perf a little bit, but increases `post_execution_type_stack_transition` by 20% #[cfg_attr(feature = "force-inline", inline(always))] -fn verify_pack<'a>( +fn verify_pack( + ty_pool: &InternedTypePool, operand_stack: &mut Stack, field_count: u16, - field_tys: impl Iterator, - output_ty: Type, + field_tys: impl Iterator, + output_ty: TypeId, ) -> PartialVMResult<()> { - let ability = output_ty.abilities()?; + let ability = ty_pool.abilities(output_ty); // If the struct has a key ability, we expect all of its field to // have store ability but not key ability. @@ -138,16 +139,16 @@ fn verify_pack<'a>( // For example, it is ok to have a struct that doesn't have a // copy capability where its field is a struct that has copy // capability but not vice versa. - ty.paranoid_check_abilities(field_expected_abilities)?; + ty_pool.paranoid_check_abilities(ty, field_expected_abilities)?; // Similar, we use assignability for the value moved in the field - ty.paranoid_check_assignable(expected_ty)?; + ty_pool.paranoid_check_assignable(ty, expected_ty)?; } operand_stack.push_ty(output_ty) } pub fn verify_pack_closure( - ty_builder: &TypeBuilder, + ty_pool: &InternedTypePool, operand_stack: &mut Stack, func: &LoadedFunction, mask: ClosureMask, @@ -163,61 +164,42 @@ pub fn verify_pack_closure( let expected_capture_tys = mask.extract(func.param_tys(), true); let given_capture_tys = operand_stack.popn_tys(expected_capture_tys.len() as u16)?; - for (expected, given) in expected_capture_tys + for (expected_ty_type, given) in expected_capture_tys .into_iter() .zip(given_capture_tys.into_iter()) { - expected.paranoid_check_is_no_ref("Captured argument type")?; - with_instantiation(ty_builder, func, expected, |expected| { - // Intersect the captured type with the accumulated abilities - abilities = abilities.intersect(given.abilities()?); - given.paranoid_check_assignable(expected) - })? - } - // Push result type onto stack - let args = mask - .extract(func.param_tys(), false) - .into_iter() - .map(|curried| with_owned_instantiation(ty_builder, func, curried, Ok)) - .collect::>>()?; - let results = func - .return_tys() - .iter() - .map(|ret| with_owned_instantiation(ty_builder, func, ret, Ok)) - .collect::>>()?; - operand_stack.push_ty(Type::Function { - args, - results, - abilities, - })?; - - Ok(()) -} + let expected = ty_pool.instantiate_and_intern(expected_ty_type, func.ty_args()); + ty_pool.paranoid_check_is_no_ref(expected, "Captured argument type")?; -fn with_instantiation( - ty_builder: &TypeBuilder, - func: &LoadedFunction, - ty: &Type, - action: impl FnOnce(&Type) -> PartialVMResult, -) -> PartialVMResult { - if func.ty_args().is_empty() { - action(ty) - } else { - action(&ty_builder.create_ty_with_subst(ty, func.ty_args())?) + // Intersect the captured type with the accumulated abilities + abilities = abilities.intersect(ty_pool.abilities(given)); + ty_pool.paranoid_check_assignable(given, expected)?; } -} -fn with_owned_instantiation( - ty_builder: &TypeBuilder, - func: &LoadedFunction, - ty: &Type, - action: impl FnOnce(Type) -> PartialVMResult, -) -> PartialVMResult { - if func.ty_args().is_empty() { - action(ty.clone()) + let func_ty = if func.ty_args.is_empty() { + let args = mask + .extract(func.param_ty_ids(), false) + .into_iter() + .copied() + .collect::>(); + ty_pool.function_of_vec(args, func.return_ty_ids().to_vec(), abilities) } else { - action(ty_builder.create_ty_with_subst(ty, func.ty_args())?) - } + let args = mask + .extract(func.param_tys(), false) + .into_iter() + .map(|curried| Ok(ty_pool.instantiate_and_intern(curried, &func.ty_args))) + .collect::>>()?; + let results = func + .return_tys() + .iter() + .map(|ret| Ok(ty_pool.instantiate_and_intern(ret, &func.ty_args))) + .collect::>>()?; + ty_pool.function_of_vec(args, results, abilities) + }; + + operand_stack.push_ty(func_ty)?; + + Ok(()) } pub(crate) struct NoRuntimeTypeCheck; @@ -294,9 +276,10 @@ impl RuntimeTypeCheck for FullRuntimeTypeCheck { // top of the stack. The argument types are checked when the frame // is constructed in the interpreter, using the same code as for regular // calls. + let ty_pool = frame.ty_pool(); let (expected_ty, _) = ty_cache.get_signature_index_type(*sig_idx, frame)?; let given_ty = operand_stack.pop_ty()?; - given_ty.paranoid_check_assignable(expected_ty)?; + ty_pool.paranoid_check_assignable(given_ty, expected_ty)?; }, Bytecode::Branch(_) => (), Bytecode::Ret => { @@ -307,12 +290,13 @@ impl RuntimeTypeCheck for FullRuntimeTypeCheck { }, // StLoc needs to check before execution as we need to check the drop ability of values. Bytecode::StLoc(idx) => { - let expected_ty = frame.local_ty_at(*idx as usize); + let ty_pool = frame.ty_pool(); + let expected_ty = *frame.local_ty_at(*idx as usize); let val_ty = operand_stack.pop_ty()?; // For store, use assignability - val_ty.paranoid_check_assignable(expected_ty)?; + ty_pool.paranoid_check_assignable(val_ty, expected_ty)?; if !frame.locals.is_invalid(*idx as usize)? { - expected_ty.paranoid_check_has_ability(Ability::Drop)?; + ty_pool.paranoid_check_has_ability(expected_ty, Ability::Drop)?; } }, // We will check the rest of the instructions after execution phase. @@ -429,7 +413,7 @@ impl RuntimeTypeCheck for FullRuntimeTypeCheck { instruction: &Bytecode, ty_cache: &mut FrameTypeCache, ) -> PartialVMResult<()> { - let ty_builder = frame.ty_builder(); + let ty_pool = frame.ty_pool(); match instruction { Bytecode::BrTrue(_) | Bytecode::BrFalse(_) => (), Bytecode::Branch(_) @@ -445,129 +429,102 @@ impl RuntimeTypeCheck for FullRuntimeTypeCheck { }, Bytecode::Pop => { let ty = operand_stack.pop_ty()?; - ty.paranoid_check_has_ability(Ability::Drop)?; - }, - Bytecode::LdU8(_) => { - let u8_ty = ty_builder.create_u8_ty(); - operand_stack.push_ty(u8_ty)? - }, - Bytecode::LdU16(_) => { - let u16_ty = ty_builder.create_u16_ty(); - operand_stack.push_ty(u16_ty)? - }, - Bytecode::LdU32(_) => { - let u32_ty = ty_builder.create_u32_ty(); - operand_stack.push_ty(u32_ty)? - }, - Bytecode::LdU64(_) => { - let u64_ty = ty_builder.create_u64_ty(); - operand_stack.push_ty(u64_ty)? - }, - Bytecode::LdU128(_) => { - let u128_ty = ty_builder.create_u128_ty(); - operand_stack.push_ty(u128_ty)? - }, - Bytecode::LdU256(_) => { - let u256_ty = ty_builder.create_u256_ty(); - operand_stack.push_ty(u256_ty)? - }, - Bytecode::LdI8(_) => { - let i8_ty = ty_builder.create_i8_ty(); - operand_stack.push_ty(i8_ty)? - }, - Bytecode::LdI16(_) => { - let i16_ty = ty_builder.create_i16_ty(); - operand_stack.push_ty(i16_ty)? - }, - Bytecode::LdI32(_) => { - let i32_ty = ty_builder.create_i32_ty(); - operand_stack.push_ty(i32_ty)? - }, - Bytecode::LdI64(_) => { - let i64_ty = ty_builder.create_i64_ty(); - operand_stack.push_ty(i64_ty)? - }, - Bytecode::LdI128(_) => { - let i128_ty = ty_builder.create_i128_ty(); - operand_stack.push_ty(i128_ty)? - }, - Bytecode::LdI256(_) => { - let i256_ty = ty_builder.create_i256_ty(); - operand_stack.push_ty(i256_ty)? - }, - Bytecode::LdTrue | Bytecode::LdFalse => { - let bool_ty = ty_builder.create_bool_ty(); - operand_stack.push_ty(bool_ty)? - }, + ty_pool.paranoid_check_has_ability(ty, Ability::Drop)?; + }, + Bytecode::LdU8(_) => operand_stack.push_ty(TypeId::U8)?, + Bytecode::LdU16(_) => operand_stack.push_ty(TypeId::U16)?, + Bytecode::LdU32(_) => operand_stack.push_ty(TypeId::U32)?, + Bytecode::LdU64(_) => operand_stack.push_ty(TypeId::U64)?, + Bytecode::LdU128(_) => operand_stack.push_ty(TypeId::U128)?, + Bytecode::LdU256(_) => operand_stack.push_ty(TypeId::U256)?, + Bytecode::LdI8(_) => operand_stack.push_ty(TypeId::I8)?, + Bytecode::LdI16(_) => operand_stack.push_ty(TypeId::I16)?, + Bytecode::LdI32(_) => operand_stack.push_ty(TypeId::I32)?, + Bytecode::LdI64(_) => operand_stack.push_ty(TypeId::I64)?, + Bytecode::LdI128(_) => operand_stack.push_ty(TypeId::I128)?, + Bytecode::LdI256(_) => operand_stack.push_ty(TypeId::I256)?, + Bytecode::LdTrue | Bytecode::LdFalse => operand_stack.push_ty(TypeId::BOOL)?, Bytecode::LdConst(i) => { let constant = frame.constant_at(*i); - let ty = ty_builder.create_constant_ty(&constant.type_)?; + // TODO: cache at load-time. + let ty = ty_pool.create_constant_ty(&constant.type_); operand_stack.push_ty(ty)?; }, Bytecode::CopyLoc(idx) => { - let ty = frame.local_ty_at(*idx as usize).clone(); - ty.paranoid_check_has_ability(Ability::Copy)?; + let ty = *frame.local_ty_at(*idx as usize); + ty_pool.paranoid_check_has_ability(ty, Ability::Copy)?; operand_stack.push_ty(ty)?; }, Bytecode::MoveLoc(idx) => { - let ty = frame.local_ty_at(*idx as usize).clone(); + let ty = *frame.local_ty_at(*idx as usize); operand_stack.push_ty(ty)?; }, Bytecode::StLoc(_) => (), Bytecode::MutBorrowLoc(idx) => { - let ty = frame.local_ty_at(*idx as usize); - let mut_ref_ty = ty_builder.create_ref_ty(ty, true)?; + let ty = *frame.local_ty_at(*idx as usize); + let mut_ref_ty = TypeId::ref_mut_of(ty); operand_stack.push_ty(mut_ref_ty)?; }, Bytecode::ImmBorrowLoc(idx) => { - let ty = frame.local_ty_at(*idx as usize); - let ref_ty = ty_builder.create_ref_ty(ty, false)?; + let ty = *frame.local_ty_at(*idx as usize); + let ref_ty = TypeId::ref_of(ty); operand_stack.push_ty(ref_ty)?; }, Bytecode::ImmBorrowField(fh_idx) => { let ty = operand_stack.pop_ty()?; - let expected_ty = frame.field_handle_to_struct(*fh_idx); - ty.paranoid_check_ref_eq(&expected_ty, false)?; + let expected_ty_type = frame.field_handle_to_struct(*fh_idx); + let expected_ty = ty_pool.instantiate_and_intern(&expected_ty_type, &[]); + ty_pool.paranoid_check_ref_eq(ty, expected_ty, false)?; - let field_ty = frame.get_field_ty(*fh_idx)?; - let field_ref_ty = ty_builder.create_ref_ty(field_ty, false)?; + let field_ty_type = frame.get_field_ty(*fh_idx)?; + let field_ty = ty_pool.instantiate_and_intern(field_ty_type, &[]); + let field_ref_ty = TypeId::ref_of(field_ty); operand_stack.push_ty(field_ref_ty)?; }, Bytecode::MutBorrowField(fh_idx) => { let ref_ty = operand_stack.pop_ty()?; - let expected_inner_ty = frame.field_handle_to_struct(*fh_idx); - ref_ty.paranoid_check_ref_eq(&expected_inner_ty, true)?; + let expected_inner_ty_type = frame.field_handle_to_struct(*fh_idx); + let expected_inner_ty = + ty_pool.instantiate_and_intern(&expected_inner_ty_type, &[]); + ty_pool.paranoid_check_ref_eq(ref_ty, expected_inner_ty, true)?; - let field_ty = frame.get_field_ty(*fh_idx)?; - let field_mut_ref_ty = ty_builder.create_ref_ty(field_ty, true)?; + let field_ty_type = frame.get_field_ty(*fh_idx)?; + let field_ty = ty_pool.instantiate_and_intern(field_ty_type, &[]); + let field_mut_ref_ty = TypeId::ref_mut_of(field_ty); operand_stack.push_ty(field_mut_ref_ty)?; }, Bytecode::ImmBorrowFieldGeneric(idx) => { let struct_ty = operand_stack.pop_ty()?; let ((field_ty, _), (expected_struct_ty, _)) = ty_cache.get_field_type_and_struct_type(*idx, frame)?; - struct_ty.paranoid_check_ref_eq(expected_struct_ty, false)?; + ty_pool.paranoid_check_ref_eq(struct_ty, expected_struct_ty, false)?; - let field_ref_ty = ty_builder.create_ref_ty(field_ty, false)?; + let field_ref_ty = TypeId::ref_of(field_ty); operand_stack.push_ty(field_ref_ty)?; }, Bytecode::MutBorrowFieldGeneric(idx) => { let struct_ty = operand_stack.pop_ty()?; let ((field_ty, _), (expected_struct_ty, _)) = ty_cache.get_field_type_and_struct_type(*idx, frame)?; - struct_ty.paranoid_check_ref_eq(expected_struct_ty, true)?; + ty_pool.paranoid_check_ref_eq(struct_ty, expected_struct_ty, true)?; - let field_mut_ref_ty = ty_builder.create_ref_ty(field_ty, true)?; + let field_mut_ref_ty = TypeId::ref_mut_of(field_ty); operand_stack.push_ty(field_mut_ref_ty)?; }, Bytecode::ImmBorrowVariantField(fh_idx) | Bytecode::MutBorrowVariantField(fh_idx) => { let is_mut = matches!(instruction, Bytecode::MutBorrowVariantField(..)); let field_info = frame.variant_field_info_at(*fh_idx); let ty = operand_stack.pop_ty()?; - let expected_ty = frame.create_struct_ty(&field_info.definition_struct_type); - ty.paranoid_check_ref_eq(&expected_ty, is_mut)?; - let field_ty = &field_info.uninstantiated_field_ty; - let field_ref_ty = ty_builder.create_ref_ty(field_ty, is_mut)?; + let expected_ty_type = frame.create_struct_ty(&field_info.definition_struct_type); + let expected_ty = ty_pool.instantiate_and_intern(&expected_ty_type, &[]); + ty_pool.paranoid_check_ref_eq(ty, expected_ty, is_mut)?; + let field_ty_type = &field_info.uninstantiated_field_ty; + let field_ty = ty_pool.instantiate_and_intern(field_ty_type, &[]); + let field_ref_ty = if is_mut { + TypeId::ref_mut_of(field_ty) + } else { + TypeId::ref_of(field_ty) + }; operand_stack.push_ty(field_ref_ty)?; }, Bytecode::ImmBorrowVariantFieldGeneric(idx) @@ -576,8 +533,12 @@ impl RuntimeTypeCheck for FullRuntimeTypeCheck { let struct_ty = operand_stack.pop_ty()?; let ((field_ty, _), (expected_struct_ty, _)) = ty_cache.get_variant_field_type_and_struct_type(*idx, frame)?; - struct_ty.paranoid_check_ref_eq(expected_struct_ty, is_mut)?; - let field_ref_ty = ty_builder.create_ref_ty(field_ty, is_mut)?; + ty_pool.paranoid_check_ref_eq(struct_ty, expected_struct_ty, is_mut)?; + let field_ref_ty = if is_mut { + TypeId::ref_mut_of(field_ty) + } else { + TypeId::ref_of(field_ty) + }; operand_stack.push_ty(field_ref_ty)?; }, Bytecode::PackClosure(..) | Bytecode::PackClosureGeneric(..) => { @@ -587,13 +548,16 @@ impl RuntimeTypeCheck for FullRuntimeTypeCheck { Bytecode::Pack(idx) => { let field_count = frame.field_count(*idx); let args_ty = frame.get_struct(*idx); - let field_tys = args_ty.fields(None)?.iter().map(|(_, ty)| ty); + let field_tys = args_ty + .fields(None)? + .iter() + .map(|(_, ty)| ty_pool.instantiate_and_intern(ty, &[])); let output_ty = frame.get_struct_ty(*idx); - verify_pack(operand_stack, field_count, field_tys, output_ty)?; + verify_pack(ty_pool, operand_stack, field_count, field_tys, output_ty)?; }, Bytecode::PackGeneric(idx) => { let field_count = frame.field_instantiation_count(*idx); - let output_ty = ty_cache.get_struct_type(*idx, frame)?.0.clone(); + let output_ty = ty_cache.get_struct_type(*idx, frame)?.0; let args_ty = ty_cache.get_struct_fields_types(*idx, frame)?; if field_count as usize != args_ty.len() { @@ -608,28 +572,30 @@ impl RuntimeTypeCheck for FullRuntimeTypeCheck { } verify_pack( + ty_pool, operand_stack, field_count, - args_ty.iter().map(|(ty, _)| ty), + args_ty.iter().map(|(ty, _)| *ty), output_ty, )?; }, Bytecode::Unpack(idx) => { let struct_ty = operand_stack.pop_ty()?; - struct_ty.paranoid_check_eq(&frame.get_struct_ty(*idx))?; + ty_pool.paranoid_check_eq(struct_ty, frame.get_struct_ty(*idx))?; let struct_decl = frame.get_struct(*idx); for (_name, ty) in struct_decl.fields(None)?.iter() { - operand_stack.push_ty(ty.clone())?; + let ty_id = ty_pool.instantiate_and_intern(ty, &[]); + operand_stack.push_ty(ty_id)?; } }, Bytecode::UnpackGeneric(idx) => { let struct_ty = operand_stack.pop_ty()?; - struct_ty.paranoid_check_eq(ty_cache.get_struct_type(*idx, frame)?.0)?; + ty_pool.paranoid_check_eq(struct_ty, ty_cache.get_struct_type(*idx, frame)?.0)?; let struct_fields_types = ty_cache.get_struct_fields_types(*idx, frame)?; for (ty, _) in struct_fields_types { - operand_stack.push_ty(ty.clone())?; + operand_stack.push_ty(*ty)?; } }, Bytecode::PackVariant(idx) => { @@ -638,125 +604,126 @@ impl RuntimeTypeCheck for FullRuntimeTypeCheck { .definition_struct_type .fields(Some(info.variant))? .iter() - .map(|(_, ty)| ty); - let output_ty = frame.create_struct_ty(&info.definition_struct_type); - verify_pack(operand_stack, info.field_count, field_tys, output_ty)?; + .map(|(_, ty)| ty_pool.instantiate_and_intern(ty, &[])); + let output_ty_type = frame.create_struct_ty(&info.definition_struct_type); + let output_ty = ty_pool.instantiate_and_intern(&output_ty_type, &[]); + verify_pack( + ty_pool, + operand_stack, + info.field_count, + field_tys, + output_ty, + )?; }, Bytecode::PackVariantGeneric(idx) => { let info = frame.get_struct_variant_instantiation_at(*idx); - let output_ty = ty_cache.get_struct_variant_type(*idx, frame)?.0.clone(); + let output_ty = ty_cache.get_struct_variant_type(*idx, frame)?.0; let args_ty = ty_cache.get_struct_variant_fields_types(*idx, frame)?; verify_pack( + ty_pool, operand_stack, info.field_count, - args_ty.iter().map(|(ty, _)| ty), + args_ty.iter().map(|(ty, _)| *ty), output_ty, )?; }, Bytecode::UnpackVariant(idx) => { let info = frame.get_struct_variant_at(*idx); - let expected_struct_ty = frame.create_struct_ty(&info.definition_struct_type); + let expected_struct_ty_type = frame.create_struct_ty(&info.definition_struct_type); + let expected_struct_ty = + ty_pool.instantiate_and_intern(&expected_struct_ty_type, &[]); let actual_struct_ty = operand_stack.pop_ty()?; - actual_struct_ty.paranoid_check_eq(&expected_struct_ty)?; + ty_pool.paranoid_check_eq(actual_struct_ty, expected_struct_ty)?; for (_name, ty) in info .definition_struct_type .fields(Some(info.variant))? .iter() { - operand_stack.push_ty(ty.clone())?; + let ty_id = ty_pool.instantiate_and_intern(ty, &[]); + operand_stack.push_ty(ty_id)?; } }, Bytecode::UnpackVariantGeneric(idx) => { let expected_struct_type = ty_cache.get_struct_variant_type(*idx, frame)?.0; let actual_struct_type = operand_stack.pop_ty()?; - actual_struct_type.paranoid_check_eq(expected_struct_type)?; + ty_pool.paranoid_check_eq(actual_struct_type, expected_struct_type)?; let struct_fields_types = ty_cache.get_struct_variant_fields_types(*idx, frame)?; for (ty, _) in struct_fields_types { - operand_stack.push_ty(ty.clone())?; + operand_stack.push_ty(*ty)?; } }, Bytecode::TestVariant(idx) => { let info = frame.get_struct_variant_at(*idx); - let expected_struct_ty = frame.create_struct_ty(&info.definition_struct_type); + let expected_struct_ty_type = frame.create_struct_ty(&info.definition_struct_type); + let expected_struct_ty = + ty_pool.instantiate_and_intern(&expected_struct_ty_type, &[]); let actual_struct_ty = operand_stack.pop_ty()?; - actual_struct_ty.paranoid_check_ref_eq(&expected_struct_ty, false)?; - operand_stack.push_ty(ty_builder.create_bool_ty())?; + ty_pool.paranoid_check_ref_eq(actual_struct_ty, expected_struct_ty, false)?; + operand_stack.push_ty(TypeId::BOOL)?; }, Bytecode::TestVariantGeneric(idx) => { let expected_struct_ty = ty_cache.get_struct_variant_type(*idx, frame)?.0; let actual_struct_ty = operand_stack.pop_ty()?; - actual_struct_ty.paranoid_check_ref_eq(expected_struct_ty, false)?; - operand_stack.push_ty(ty_builder.create_bool_ty())?; + ty_pool.paranoid_check_ref_eq(actual_struct_ty, expected_struct_ty, false)?; + operand_stack.push_ty(TypeId::BOOL)?; }, Bytecode::ReadRef => { let ref_ty = operand_stack.pop_ty()?; - let inner_ty = ref_ty.paranoid_read_ref()?; + let inner_ty = ty_pool.paranoid_read_ref(ref_ty)?; operand_stack.push_ty(inner_ty)?; }, Bytecode::WriteRef => { let mut_ref_ty = operand_stack.pop_ty()?; let val_ty = operand_stack.pop_ty()?; - mut_ref_ty.paranoid_write_ref(&val_ty)?; + ty_pool.paranoid_write_ref(mut_ref_ty, val_ty)?; }, Bytecode::CastU8 => { operand_stack.pop_ty()?; - let u8_ty = ty_builder.create_u8_ty(); - operand_stack.push_ty(u8_ty)?; + operand_stack.push_ty(TypeId::U8)?; }, Bytecode::CastU16 => { operand_stack.pop_ty()?; - let u16_ty = ty_builder.create_u16_ty(); - operand_stack.push_ty(u16_ty)?; + operand_stack.push_ty(TypeId::U16)?; }, Bytecode::CastU32 => { operand_stack.pop_ty()?; - let u32_ty = ty_builder.create_u32_ty(); - operand_stack.push_ty(u32_ty)?; + operand_stack.push_ty(TypeId::U32)?; }, Bytecode::CastU64 => { operand_stack.pop_ty()?; - let u64_ty = ty_builder.create_u64_ty(); - operand_stack.push_ty(u64_ty)?; + operand_stack.push_ty(TypeId::U64)?; }, Bytecode::CastU128 => { operand_stack.pop_ty()?; - let u128_ty = ty_builder.create_u128_ty(); - operand_stack.push_ty(u128_ty)?; + operand_stack.push_ty(TypeId::U128)?; }, Bytecode::CastU256 => { operand_stack.pop_ty()?; - let u256_ty = ty_builder.create_u256_ty(); - operand_stack.push_ty(u256_ty)?; + operand_stack.push_ty(TypeId::U256)?; }, Bytecode::CastI8 => { operand_stack.pop_ty()?; - let i8_ty = ty_builder.create_i8_ty(); - operand_stack.push_ty(i8_ty)?; + operand_stack.push_ty(TypeId::I8)?; }, Bytecode::CastI16 => { operand_stack.pop_ty()?; - let i16_ty = ty_builder.create_i16_ty(); - operand_stack.push_ty(i16_ty)?; + operand_stack.push_ty(TypeId::I16)?; }, Bytecode::CastI32 => { operand_stack.pop_ty()?; - let i32_ty = ty_builder.create_i32_ty(); - operand_stack.push_ty(i32_ty)?; + operand_stack.push_ty(TypeId::I32)?; }, Bytecode::CastI64 => { operand_stack.pop_ty()?; - let i64_ty = ty_builder.create_i64_ty(); - operand_stack.push_ty(i64_ty)?; + operand_stack.push_ty(TypeId::I64)?; }, Bytecode::CastI128 => { operand_stack.pop_ty()?; - let i128_ty = ty_builder.create_i128_ty(); - operand_stack.push_ty(i128_ty)?; + operand_stack.push_ty(TypeId::I128)?; }, Bytecode::CastI256 => { operand_stack.pop_ty()?; - let i256_ty = ty_builder.create_i256_ty(); - operand_stack.push_ty(i256_ty)?; + operand_stack.push_ty(TypeId::I256)?; }, Bytecode::Add | Bytecode::Sub @@ -769,13 +736,13 @@ impl RuntimeTypeCheck for FullRuntimeTypeCheck { | Bytecode::Or | Bytecode::And => { let rhs_ty = operand_stack.pop_ty()?; - rhs_ty.paranoid_check_eq(operand_stack.top_ty()?)?; + ty_pool.paranoid_check_eq(rhs_ty, operand_stack.top_ty()?)?; // NO-OP, same as the two lines below when the types are indeed the same: // let lhs_ty = operand_stack.pop_ty()?; // operand_stack.push_ty(rhs_ty)?; }, Bytecode::Negate => { - operand_stack.top_ty()?.paranoid_check_is_sint_ty()?; + ty_pool.paranoid_check_is_sint_ty(operand_stack.top_ty()?)?; // NO-OP, leave stack as is }, Bytecode::Shl | Bytecode::Shr => { @@ -787,92 +754,86 @@ impl RuntimeTypeCheck for FullRuntimeTypeCheck { Bytecode::Lt | Bytecode::Le | Bytecode::Gt | Bytecode::Ge => { let rhs_ty = operand_stack.pop_ty()?; let lhs_ty = operand_stack.pop_ty()?; - rhs_ty.paranoid_check_eq(&lhs_ty)?; - - let bool_ty = ty_builder.create_bool_ty(); - operand_stack.push_ty(bool_ty)?; + ty_pool.paranoid_check_eq(rhs_ty, lhs_ty)?; + operand_stack.push_ty(TypeId::BOOL)?; }, Bytecode::Eq | Bytecode::Neq => { let rhs_ty = operand_stack.pop_ty()?; let lhs_ty = operand_stack.pop_ty()?; - rhs_ty.paranoid_check_eq(&lhs_ty)?; - rhs_ty.paranoid_check_has_ability(Ability::Drop)?; - - let bool_ty = ty_builder.create_bool_ty(); - operand_stack.push_ty(bool_ty)?; + ty_pool.paranoid_check_eq(rhs_ty, lhs_ty)?; + ty_pool.paranoid_check_has_ability(rhs_ty, Ability::Drop)?; + operand_stack.push_ty(TypeId::BOOL)?; }, Bytecode::MutBorrowGlobal(idx) => { - operand_stack.pop_ty()?.paranoid_check_is_address_ty()?; + ty_pool.paranoid_check_is_address_ty(operand_stack.pop_ty()?)?; let struct_ty = frame.get_struct_ty(*idx); - struct_ty.paranoid_check_has_ability(Ability::Key)?; + ty_pool.paranoid_check_has_ability(struct_ty, Ability::Key)?; - let struct_mut_ref_ty = ty_builder.create_ref_ty(&struct_ty, true)?; + let struct_mut_ref_ty = TypeId::ref_mut_of(struct_ty); operand_stack.push_ty(struct_mut_ref_ty)?; }, Bytecode::ImmBorrowGlobal(idx) => { - operand_stack.pop_ty()?.paranoid_check_is_address_ty()?; + ty_pool.paranoid_check_is_address_ty(operand_stack.pop_ty()?)?; let struct_ty = frame.get_struct_ty(*idx); - struct_ty.paranoid_check_has_ability(Ability::Key)?; + ty_pool.paranoid_check_has_ability(struct_ty, Ability::Key)?; - let struct_ref_ty = ty_builder.create_ref_ty(&struct_ty, false)?; + let struct_ref_ty = TypeId::ref_of(struct_ty); operand_stack.push_ty(struct_ref_ty)?; }, Bytecode::MutBorrowGlobalGeneric(idx) => { - operand_stack.pop_ty()?.paranoid_check_is_address_ty()?; + ty_pool.paranoid_check_is_address_ty(operand_stack.pop_ty()?)?; let struct_ty = ty_cache.get_struct_type(*idx, frame)?.0; - struct_ty.paranoid_check_has_ability(Ability::Key)?; + ty_pool.paranoid_check_has_ability(struct_ty, Ability::Key)?; - let struct_mut_ref_ty = ty_builder.create_ref_ty(struct_ty, true)?; + let struct_mut_ref_ty = TypeId::ref_mut_of(struct_ty); operand_stack.push_ty(struct_mut_ref_ty)?; }, Bytecode::ImmBorrowGlobalGeneric(idx) => { - operand_stack.pop_ty()?.paranoid_check_is_address_ty()?; + ty_pool.paranoid_check_is_address_ty(operand_stack.pop_ty()?)?; let struct_ty = ty_cache.get_struct_type(*idx, frame)?.0; - struct_ty.paranoid_check_has_ability(Ability::Key)?; + ty_pool.paranoid_check_has_ability(struct_ty, Ability::Key)?; - let struct_ref_ty = ty_builder.create_ref_ty(struct_ty, false)?; + let struct_ref_ty = TypeId::ref_of(struct_ty); operand_stack.push_ty(struct_ref_ty)?; }, Bytecode::Exists(_) | Bytecode::ExistsGeneric(_) => { - operand_stack.pop_ty()?.paranoid_check_is_address_ty()?; - - let bool_ty = ty_builder.create_bool_ty(); - operand_stack.push_ty(bool_ty)?; + ty_pool.paranoid_check_is_address_ty(operand_stack.pop_ty()?)?; + operand_stack.push_ty(TypeId::BOOL)?; }, Bytecode::MoveTo(idx) => { let ty = operand_stack.pop_ty()?; - operand_stack.pop_ty()?.paranoid_check_is_signer_ref_ty()?; - ty.paranoid_check_eq(&frame.get_struct_ty(*idx))?; - ty.paranoid_check_has_ability(Ability::Key)?; + ty_pool.paranoid_check_is_signer_ref_ty(operand_stack.pop_ty()?)?; + ty_pool.paranoid_check_eq(ty, frame.get_struct_ty(*idx))?; + ty_pool.paranoid_check_has_ability(ty, Ability::Key)?; }, Bytecode::MoveToGeneric(idx) => { let ty = operand_stack.pop_ty()?; - operand_stack.pop_ty()?.paranoid_check_is_signer_ref_ty()?; - ty.paranoid_check_eq(ty_cache.get_struct_type(*idx, frame)?.0)?; - ty.paranoid_check_has_ability(Ability::Key)?; + ty_pool.paranoid_check_is_signer_ref_ty(operand_stack.pop_ty()?)?; + ty_pool.paranoid_check_eq(ty, ty_cache.get_struct_type(*idx, frame)?.0)?; + ty_pool.paranoid_check_has_ability(ty, Ability::Key)?; }, Bytecode::MoveFrom(idx) => { - operand_stack.pop_ty()?.paranoid_check_is_address_ty()?; + ty_pool.paranoid_check_is_address_ty(operand_stack.pop_ty()?)?; let ty = frame.get_struct_ty(*idx); - ty.paranoid_check_has_ability(Ability::Key)?; + ty_pool.paranoid_check_has_ability(ty, Ability::Key)?; operand_stack.push_ty(ty)?; }, Bytecode::MoveFromGeneric(idx) => { - operand_stack.pop_ty()?.paranoid_check_is_address_ty()?; - let ty = ty_cache.get_struct_type(*idx, frame)?.0.clone(); - ty.paranoid_check_has_ability(Ability::Key)?; + ty_pool.paranoid_check_is_address_ty(operand_stack.pop_ty()?)?; + let ty = ty_cache.get_struct_type(*idx, frame)?.0; + ty_pool.paranoid_check_has_ability(ty, Ability::Key)?; operand_stack.push_ty(ty)?; }, Bytecode::FreezeRef => { let mut_ref_ty = operand_stack.pop_ty()?; - let ref_ty = mut_ref_ty.paranoid_freeze_ref_ty()?; + let ref_ty = ty_pool.paranoid_freeze_ref_ty(mut_ref_ty)?; operand_stack.push_ty(ref_ty)?; }, Bytecode::Nop => (), Bytecode::Not => { - operand_stack.top_ty()?.paranoid_check_is_bool_ty()?; + ty_pool.paranoid_check_is_bool_ty(operand_stack.top_ty()?)?; // NO-OP, same as the two lines below: - // let bool_ty = ty_builder.create_bool_ty(); + // let bool_ty = ty_pool.bool_ty(); // operand_stack.push_ty(bool_ty)?; }, Bytecode::VecPack(si, num) => { @@ -880,68 +841,57 @@ impl RuntimeTypeCheck for FullRuntimeTypeCheck { let elem_tys = operand_stack.popn_tys(*num as u16)?; for elem_ty in elem_tys.iter() { // For vector element types, use assignability - elem_ty.paranoid_check_assignable(ty)?; + ty_pool.paranoid_check_assignable(*elem_ty, ty)?; } - let vec_ty = ty_builder.create_vec_ty(ty)?; + let vec_ty = ty_pool.vec_of(ty); operand_stack.push_ty(vec_ty)?; }, Bytecode::VecLen(si) => { let (ty, _) = ty_cache.get_signature_index_type(*si, frame)?; - operand_stack - .pop_ty()? - .paranoid_check_is_vec_ref_ty::(ty)?; - - let u64_ty = ty_builder.create_u64_ty(); - operand_stack.push_ty(u64_ty)?; + ty_pool.paranoid_check_is_vec_ref_ty::(operand_stack.pop_ty()?, ty)?; + operand_stack.push_ty(TypeId::U64)?; }, Bytecode::VecImmBorrow(si) => { let (ty, _) = ty_cache.get_signature_index_type(*si, frame)?; - operand_stack.pop_ty()?.paranoid_check_is_u64_ty()?; - let elem_ref_ty = operand_stack - .pop_ty()? - .paranoid_check_and_get_vec_elem_ref_ty::(ty)?; + ty_pool.paranoid_check_is_u64_ty(operand_stack.pop_ty()?)?; + let elem_ref_ty = ty_pool + .paranoid_check_and_get_vec_elem_ref_ty::(operand_stack.pop_ty()?, ty)?; operand_stack.push_ty(elem_ref_ty)?; }, Bytecode::VecMutBorrow(si) => { let (ty, _) = ty_cache.get_signature_index_type(*si, frame)?; - operand_stack.pop_ty()?.paranoid_check_is_u64_ty()?; - let elem_ref_ty = operand_stack - .pop_ty()? - .paranoid_check_and_get_vec_elem_ref_ty::(ty)?; + ty_pool.paranoid_check_is_u64_ty(operand_stack.pop_ty()?)?; + let elem_ref_ty = ty_pool + .paranoid_check_and_get_vec_elem_ref_ty::(operand_stack.pop_ty()?, ty)?; operand_stack.push_ty(elem_ref_ty)?; }, Bytecode::VecPushBack(si) => { let (ty, _) = ty_cache.get_signature_index_type(*si, frame)?; // For pushing an element to a vector, use assignability - operand_stack.pop_ty()?.paranoid_check_assignable(ty)?; - operand_stack - .pop_ty()? - .paranoid_check_is_vec_ref_ty::(ty)?; + ty_pool.paranoid_check_assignable(operand_stack.pop_ty()?, ty)?; + ty_pool.paranoid_check_is_vec_ref_ty::(operand_stack.pop_ty()?, ty)?; }, Bytecode::VecPopBack(si) => { let (ty, _) = ty_cache.get_signature_index_type(*si, frame)?; - let elem_ty = operand_stack - .pop_ty()? - .paranoid_check_and_get_vec_elem_ty::(ty)?; + let elem_ty = ty_pool + .paranoid_check_and_get_vec_elem_ty::(operand_stack.pop_ty()?, ty)?; operand_stack.push_ty(elem_ty)?; }, Bytecode::VecUnpack(si, num) => { let (expected_elem_ty, _) = ty_cache.get_signature_index_type(*si, frame)?; let vec_ty = operand_stack.pop_ty()?; - vec_ty.paranoid_check_is_vec_ty(expected_elem_ty)?; + ty_pool.paranoid_check_is_vec_ty(vec_ty, expected_elem_ty)?; for _ in 0..*num { - operand_stack.push_ty(expected_elem_ty.clone())?; + operand_stack.push_ty(expected_elem_ty)?; } }, Bytecode::VecSwap(si) => { let (ty, _) = ty_cache.get_signature_index_type(*si, frame)?; - operand_stack.pop_ty()?.paranoid_check_is_u64_ty()?; - operand_stack.pop_ty()?.paranoid_check_is_u64_ty()?; - operand_stack - .pop_ty()? - .paranoid_check_is_vec_ref_ty::(ty)?; + ty_pool.paranoid_check_is_u64_ty(operand_stack.pop_ty()?)?; + ty_pool.paranoid_check_is_u64_ty(operand_stack.pop_ty()?)?; + ty_pool.paranoid_check_is_vec_ref_ty::(operand_stack.pop_ty()?, ty)?; }, } Ok(()) diff --git a/third_party/move/move-vm/runtime/src/storage/environment.rs b/third_party/move/move-vm/runtime/src/storage/environment.rs index de2a940b43e32..95a5cd63131c7 100644 --- a/third_party/move/move-vm/runtime/src/storage/environment.rs +++ b/third_party/move/move-vm/runtime/src/storage/environment.rs @@ -33,7 +33,7 @@ use move_vm_types::loaded_data::{ use move_vm_types::{ loaded_data::{runtime_types::Type, struct_name_indexing::StructNameIndexMap}, module_id_interner::InternedModuleIdPool, - ty_interner::InternedTypePool, + ty_interner::{InternedTypePool, TypeId}, }; use std::sync::Arc; @@ -128,6 +128,10 @@ impl RuntimeEnvironment { &self.interned_module_id_pool } + pub fn ty_pool_arced(&self) -> Arc { + self.interned_ty_pool.clone() + } + /// Enables delayed field optimization for this environment. pub fn enable_delayed_field_optimization(&mut self) { self.vm_config.delayed_field_optimization_enabled = true; @@ -314,7 +318,7 @@ impl RuntimeEnvironment { /// Returns the type tag for the given type. Construction of the tag can fail if it is too /// "complex": i.e., too deeply nested, or has large struct identifiers. - pub fn ty_to_ty_tag(&self, ty: &Type) -> PartialVMResult { + pub fn ty_to_ty_tag(&self, ty: TypeId) -> PartialVMResult { let ty_tag_builder = TypeTagConverter::new(self); ty_tag_builder.ty_to_ty_tag(ty) } diff --git a/third_party/move/move-vm/runtime/src/storage/layout_cache.rs b/third_party/move/move-vm/runtime/src/storage/layout_cache.rs index d511ebf76d644..b996eeec0a19a 100644 --- a/third_party/move/move-vm/runtime/src/storage/layout_cache.rs +++ b/third_party/move/move-vm/runtime/src/storage/layout_cache.rs @@ -18,7 +18,10 @@ use crate::LayoutWithDelayedFields; use move_binary_format::errors::PartialVMResult; use move_core_types::language_storage::ModuleId; -use move_vm_types::{loaded_data::struct_name_indexing::StructNameIndex, ty_interner::TypeVecId}; +use move_vm_types::{ + loaded_data::struct_name_indexing::StructNameIndex, + ty_interner::{TypeId, TypeVecId}, +}; use std::collections::HashSet; use triomphe::Arc as TriompheArc; @@ -87,10 +90,10 @@ pub trait LayoutCache { /// If layout root is cached, returns the cached entry (with the modules that were used to /// construct it). The reader must ensure to read the module-set for gas charging of validation /// purposes. - fn get_struct_layout(&self, key: &StructKey) -> Option; + fn get_struct_layout(&self, key: TypeId) -> Option; /// Stores layout into cache. If layout already exists (e.g., concurrent insertion) - a no-op. - fn store_struct_layout(&self, key: &StructKey, entry: LayoutCacheEntry) -> PartialVMResult<()>; + fn store_struct_layout(&self, key: TypeId, entry: LayoutCacheEntry) -> PartialVMResult<()>; } /// Marker for no-op layout caches. @@ -100,15 +103,11 @@ impl LayoutCache for T where T: NoOpLayoutCache, { - fn get_struct_layout(&self, _key: &StructKey) -> Option { + fn get_struct_layout(&self, _key: TypeId) -> Option { None } - fn store_struct_layout( - &self, - _key: &StructKey, - _entry: LayoutCacheEntry, - ) -> PartialVMResult<()> { + fn store_struct_layout(&self, _key: TypeId, _entry: LayoutCacheEntry) -> PartialVMResult<()> { Ok(()) } } diff --git a/third_party/move/move-vm/runtime/src/storage/loader/lazy.rs b/third_party/move/move-vm/runtime/src/storage/loader/lazy.rs index 0f01a19d8ba3a..a49843133cba9 100644 --- a/third_party/move/move-vm/runtime/src/storage/loader/lazy.rs +++ b/third_party/move/move-vm/runtime/src/storage/loader/lazy.rs @@ -9,7 +9,7 @@ use crate::{ StructDefinitionLoader, }, Function, LayoutCacheEntry, LayoutWithDelayedFields, LoadedFunction, Module, ModuleStorage, - RuntimeEnvironment, Script, StructKey, WithRuntimeEnvironment, + RuntimeEnvironment, Script, WithRuntimeEnvironment, }; use move_binary_format::{ access::ScriptAccess, @@ -30,6 +30,7 @@ use move_vm_types::{ struct_name_indexing::StructNameIndex, }, sha3_256, + ty_interner::TypeId, }; use std::sync::Arc; @@ -204,7 +205,7 @@ where &self, gas_meter: &mut impl DependencyGasMeter, traversal_context: &mut TraversalContext, - key: &StructKey, + key: TypeId, ) -> Option> { let entry = self.module_storage.get_struct_layout(key)?; let (layout, modules) = entry.unpack(); @@ -220,11 +221,7 @@ where Some(Ok(layout)) } - fn store_layout_to_cache( - &self, - key: &StructKey, - entry: LayoutCacheEntry, - ) -> PartialVMResult<()> { + fn store_layout_to_cache(&self, key: TypeId, entry: LayoutCacheEntry) -> PartialVMResult<()> { self.module_storage.store_struct_layout(key, entry) } } diff --git a/third_party/move/move-vm/runtime/src/storage/loader/test_utils.rs b/third_party/move/move-vm/runtime/src/storage/loader/test_utils.rs index a797e46de578a..9da0c0f8ffcc4 100644 --- a/third_party/move/move-vm/runtime/src/storage/loader/test_utils.rs +++ b/third_party/move/move-vm/runtime/src/storage/loader/test_utils.rs @@ -76,6 +76,7 @@ pub(crate) struct MockStructDefinitionLoader { } impl MockStructDefinitionLoader { + #[allow(dead_code)] pub(crate) fn new_with_config(config: VMConfig) -> Self { Self { runtime_environment: RuntimeEnvironment::new_with_config(vec![], config), diff --git a/third_party/move/move-vm/runtime/src/storage/loader/traits.rs b/third_party/move/move-vm/runtime/src/storage/loader/traits.rs index ceb5c7773f329..009fb34ad29ce 100644 --- a/third_party/move/move-vm/runtime/src/storage/loader/traits.rs +++ b/third_party/move/move-vm/runtime/src/storage/loader/traits.rs @@ -3,8 +3,7 @@ use crate::{ module_traversal::TraversalContext, Function, LayoutCacheEntry, LayoutWithDelayedFields, - LoadedFunction, LoadedFunctionOwner, Module, ModuleStorage, Script, StructKey, - WithRuntimeEnvironment, + LoadedFunction, LoadedFunctionOwner, Module, ModuleStorage, Script, WithRuntimeEnvironment, }; use move_binary_format::errors::{Location, PartialVMResult, VMResult}; use move_core_types::{ @@ -19,6 +18,7 @@ use move_vm_types::{ runtime_types::{StructType, Type}, struct_name_indexing::StructNameIndex, }, + ty_interner::TypeId, }; use std::{rc::Rc, sync::Arc}; @@ -44,17 +44,13 @@ pub trait StructDefinitionLoader: WithRuntimeEnvironment { &self, _gas_meter: &mut impl DependencyGasMeter, _traversal_context: &mut TraversalContext, - _key: &StructKey, + _key: TypeId, ) -> Option> { None } /// Stores computed layout to the layout cache. - fn store_layout_to_cache( - &self, - _key: &StructKey, - _entry: LayoutCacheEntry, - ) -> PartialVMResult<()> { + fn store_layout_to_cache(&self, _key: TypeId, _entry: LayoutCacheEntry) -> PartialVMResult<()> { // Default as no-op. Ok(()) } @@ -155,10 +151,9 @@ pub(crate) trait InstantiatedFunctionLoaderHelper: WithRuntimeEnvironment { Type::verify_ty_arg_abilities(function.ty_param_abilities(), &ty_args) .map_err(|e| e.finish(Location::Module(module.self_id().clone())))?; - let ty_args_id = self - .runtime_environment() - .ty_pool() - .intern_ty_args(&ty_args); + let pool = self.runtime_environment().ty_pool(); + let ty_args_id = pool.intern_ty_args(&ty_args); + let ty_args = pool.get_type_vec(ty_args_id).to_vec(); Ok(LoadedFunction { owner: LoadedFunctionOwner::Module(module), @@ -185,10 +180,9 @@ pub(crate) trait InstantiatedFunctionLoaderHelper: WithRuntimeEnvironment { let main = script.entry_point(); Type::verify_ty_arg_abilities(main.ty_param_abilities(), &ty_args) .map_err(|err| err.finish(Location::Script))?; - let ty_args_id = self - .runtime_environment() - .ty_pool() - .intern_ty_args(&ty_args); + let pool = self.runtime_environment().ty_pool(); + let ty_args_id = pool.intern_ty_args(&ty_args); + let ty_args = pool.get_type_vec(ty_args_id).to_vec(); Ok(LoadedFunction { owner: LoadedFunctionOwner::Script(script), diff --git a/third_party/move/move-vm/runtime/src/storage/ty_depth_checker.rs b/third_party/move/move-vm/runtime/src/storage/ty_depth_checker.rs index 186cc4764256d..66a5fc01e8db9 100644 --- a/third_party/move/move-vm/runtime/src/storage/ty_depth_checker.rs +++ b/third_party/move/move-vm/runtime/src/storage/ty_depth_checker.rs @@ -70,6 +70,7 @@ where /// must be non-generic, i.e., all type substitutions must be performed. If needed, the check /// traverses multiple modules where inner structs and their fields are defined. #[cfg_attr(feature = "force-inline", inline(always))] + #[allow(dead_code)] pub(crate) fn check_depth_of_type( &self, gas_meter: &mut impl DependencyGasMeter, diff --git a/third_party/move/move-vm/runtime/src/storage/ty_layout_converter.rs b/third_party/move/move-vm/runtime/src/storage/ty_layout_converter.rs index c6bab0a39c83b..1ef500bd8e99e 100644 --- a/third_party/move/move-vm/runtime/src/storage/ty_layout_converter.rs +++ b/third_party/move/move-vm/runtime/src/storage/ty_layout_converter.rs @@ -8,7 +8,7 @@ use crate::{ layout_cache::DefiningModules, loader::traits::StructDefinitionLoader, ty_tag_converter::TypeTagConverter, }, - LayoutCacheEntry, RuntimeEnvironment, StructKey, + LayoutCacheEntry, RuntimeEnvironment, }; use move_binary_format::errors::{PartialVMError, PartialVMResult}; use move_core_types::{ @@ -25,6 +25,7 @@ use move_vm_types::{ runtime_types::{StructIdentifier, StructLayout, Type}, struct_name_indexing::StructNameIndex, }, + ty_interner::{TypeId, TypeRepr}, }; use std::sync::Arc; use triomphe::Arc as TriompheArc; @@ -82,52 +83,31 @@ where &self, gas_meter: &mut impl DependencyGasMeter, traversal_context: &mut TraversalContext, - ty: &Type, + ty: TypeId, check_option_type: bool, ) -> PartialVMResult { - let ty_pool = self.runtime_environment().ty_pool(); - if self.vm_config().enable_layout_caches { - let key = match ty { - Type::Struct { idx, .. } => { - let ty_args_id = ty_pool.intern_ty_args(&[]); - Some(StructKey { - idx: *idx, - ty_args_id, - }) - }, - Type::StructInstantiation { idx, ty_args, .. } => { - let ty_args_id = ty_pool.intern_ty_args(ty_args); - Some(StructKey { - idx: *idx, - ty_args_id, - }) - }, - _ => None, - }; - - if let Some(key) = key { - if let Some(result) = self.struct_definition_loader.load_layout_from_cache( - gas_meter, - traversal_context, - &key, - ) { - return result; - } - - // Otherwise a cache miss, compute the result and store it. - let mut modules = DefiningModules::new(); - let layout = self.type_to_type_layout_with_delayed_fields_impl::( - gas_meter, - traversal_context, - &mut modules, - ty, - check_option_type, - )?; - let cache_entry = LayoutCacheEntry::new(layout.clone(), modules); - self.struct_definition_loader - .store_layout_to_cache(&key, cache_entry)?; - return Ok(layout); + if self.vm_config().enable_layout_caches && ty >= TypeId::SIGNER { + if let Some(result) = self.struct_definition_loader.load_layout_from_cache( + gas_meter, + traversal_context, + ty, + ) { + return result; } + + // Otherwise a cache miss, compute the result and store it. + let mut modules = DefiningModules::new(); + let layout = self.type_to_type_layout_with_delayed_fields_impl::( + gas_meter, + traversal_context, + &mut modules, + ty, + check_option_type, + )?; + let cache_entry = LayoutCacheEntry::new(layout.clone(), modules); + self.struct_definition_loader + .store_layout_to_cache(ty, cache_entry)?; + return Ok(layout); } self.type_to_type_layout_with_delayed_fields_impl::( @@ -146,7 +126,7 @@ where &self, gas_meter: &mut impl DependencyGasMeter, traversal_context: &mut TraversalContext, - ty: &Type, + ty: TypeId, ) -> PartialVMResult { self.type_to_type_layout_with_delayed_fields_impl::( gas_meter, @@ -227,7 +207,7 @@ where gas_meter: &mut impl DependencyGasMeter, traversal_context: &mut TraversalContext, modules: &mut DefiningModules, - ty: &Type, + ty: TypeId, check_option_type: bool, ) -> PartialVMResult { let _timer = VM_TIMER.timer_with_label("type_to_type_layout_with_delayed_fields"); @@ -248,7 +228,7 @@ where }) } - /// Converts [Type] to [MoveTypeLayout]. Fails if there is not enough gas to account for module + /// Converts [TypeId] to [MoveTypeLayout]. Fails if there is not enough gas to account for module /// loading, the layout is too deep / too large, or some other miscellaneous failures, e.g. if /// struct definition is not found. fn type_to_type_layout_impl( @@ -256,70 +236,67 @@ where gas_meter: &mut impl DependencyGasMeter, traversal_context: &mut TraversalContext, modules: &mut DefiningModules, - ty: &Type, + ty: TypeId, count: &mut u64, depth: u64, check_option_type: bool, ) -> PartialVMResult<(MoveTypeLayout, bool)> { self.check_depth_and_increment_count(count, depth)?; - Ok(match ty { - Type::Bool => (MoveTypeLayout::Bool, false), - Type::U8 => (MoveTypeLayout::U8, false), - Type::U16 => (MoveTypeLayout::U16, false), - Type::U32 => (MoveTypeLayout::U32, false), - Type::U64 => (MoveTypeLayout::U64, false), - Type::U128 => (MoveTypeLayout::U128, false), - Type::U256 => (MoveTypeLayout::U256, false), - Type::I8 => (MoveTypeLayout::I8, false), - Type::I16 => (MoveTypeLayout::I16, false), - Type::I32 => (MoveTypeLayout::I32, false), - Type::I64 => (MoveTypeLayout::I64, false), - Type::I128 => (MoveTypeLayout::I128, false), - Type::I256 => (MoveTypeLayout::I256, false), - Type::Address => (MoveTypeLayout::Address, false), - Type::Signer => (MoveTypeLayout::Signer, false), - Type::Function { .. } => (MoveTypeLayout::Function, false), - Type::Vector(ty) => self - .type_to_type_layout_impl::( - gas_meter, - traversal_context, - modules, - ty, - count, - depth + 1, - check_option_type, - ) - .map(|(elem_layout, contains_delayed_fields)| { - let vec_layout = MoveTypeLayout::Vector(Box::new(elem_layout)); - (vec_layout, contains_delayed_fields) - })?, - Type::Struct { idx, .. } => self.struct_to_type_layout::( - gas_meter, - traversal_context, - modules, - idx, - &[], - count, - depth + 1, - check_option_type, - )?, - Type::StructInstantiation { idx, ty_args, .. } => self - .struct_to_type_layout::( - gas_meter, - traversal_context, - modules, - idx, - ty_args, - count, - depth + 1, - check_option_type, - )?, - Type::Reference(_) | Type::MutableReference(_) | Type::TyParam(_) => { - return Err( - PartialVMError::new(StatusCode::UNKNOWN_INVARIANT_VIOLATION_ERROR) - .with_message(format!("No type layout for {:?}", ty)), - ); + TypeId::BOOL => (MoveTypeLayout::Bool, false), + TypeId::U8 => (MoveTypeLayout::U8, false), + TypeId::U16 => (MoveTypeLayout::U16, false), + TypeId::U32 => (MoveTypeLayout::U32, false), + TypeId::U64 => (MoveTypeLayout::U64, false), + TypeId::U128 => (MoveTypeLayout::U128, false), + TypeId::U256 => (MoveTypeLayout::U256, false), + TypeId::I8 => (MoveTypeLayout::I8, false), + TypeId::I16 => (MoveTypeLayout::I16, false), + TypeId::I32 => (MoveTypeLayout::I32, false), + TypeId::I64 => (MoveTypeLayout::I64, false), + TypeId::I128 => (MoveTypeLayout::I128, false), + TypeId::I256 => (MoveTypeLayout::I256, false), + TypeId::ADDRESS => (MoveTypeLayout::Address, false), + TypeId::SIGNER => (MoveTypeLayout::Signer, false), + ty => { + let ty_pool = self.runtime_environment().ty_pool(); + match ty_pool.type_repr(ty) { + TypeRepr::Function { .. } => (MoveTypeLayout::Function, false), + TypeRepr::Vector(elem) => self + .type_to_type_layout_impl::( + gas_meter, + traversal_context, + modules, + elem, + count, + depth + 1, + check_option_type, + ) + .map(|(elem_layout, contains_delayed_fields)| { + let vec_layout = MoveTypeLayout::Vector(Box::new(elem_layout)); + (vec_layout, contains_delayed_fields) + })?, + TypeRepr::Struct { idx, ty_args } => { + let ty_args_vec = ty_pool.get_type_vec(ty_args); + self.struct_to_type_layout::( + gas_meter, + traversal_context, + modules, + &idx, + &ty_args_vec, + count, + depth + 1, + check_option_type, + )? + }, + TypeRepr::Reference(_) | TypeRepr::MutableReference(_) => { + return Err(PartialVMError::new( + StatusCode::UNKNOWN_INVARIANT_VIOLATION_ERROR, + ) + .with_message(format!("No type layout for TypeId {:?}", ty))); + }, + _ => unreachable!(), + } }, }) } @@ -331,7 +308,7 @@ where gas_meter: &mut impl DependencyGasMeter, traversal_context: &mut TraversalContext, modules: &mut DefiningModules, - tys: &[Type], + tys: &[TypeId], count: &mut u64, depth: u64, check_option_type: bool, @@ -339,7 +316,7 @@ where let mut contains_delayed_fields = false; let layouts = tys .iter() - .map(|ty| { + .map(|&ty| { let (layout, ty_contains_delayed_fields) = self .type_to_type_layout_impl::( gas_meter, @@ -371,7 +348,7 @@ where traversal_context: &mut TraversalContext, modules: &mut DefiningModules, idx: &StructNameIndex, - ty_args: &[Type], + ty_args: &[TypeId], count: &mut u64, depth: u64, check_option_type: bool, @@ -413,14 +390,16 @@ where ty_tag_converter.struct_name_idx_to_struct_tag(idx, ty_args)?; if struct_tag.is_option() { let field_name = ident_str!(LEGACY_OPTION_VEC).to_owned(); - let ty_builder = &self.vm_config().ty_builder; if variants.len() < 2 || variants[1].1.is_empty() { return Err(PartialVMError::new( StatusCode::UNKNOWN_INVARIANT_VIOLATION_ERROR, )); } - let field_type = - ty_builder.create_ty_with_subst(&variants[1].1[0].1, ty_args)?; + let field_type = self + .struct_definition_loader + .runtime_environment() + .ty_pool() + .instantiate_and_intern(&variants[1].1[0].1, ty_args); let (mut field_layout, delayed_fields) = self .types_to_type_layouts::( gas_meter, @@ -572,399 +551,403 @@ where fn apply_subst_for_field_tys( &self, field_tys: &[(Identifier, Type)], - ty_args: &[Type], - ) -> PartialVMResult> { - let ty_builder = &self.vm_config().ty_builder; + ty_args: &[TypeId], + ) -> PartialVMResult> { + let ty_pool = self.runtime_environment().ty_pool(); field_tys .iter() - .map(|(_, ty)| ty_builder.create_ty_with_subst(ty, ty_args)) + .map(|(_, ty)| { + // Use instantiate_and_intern which handles substitution with TypeId args + Ok(ty_pool.instantiate_and_intern(ty, ty_args)) + }) .collect::>>() } } -#[cfg(test)] -mod tests { - use super::*; - use crate::{ - module_traversal::{TraversalContext, TraversalStorage}, - storage::loader::test_utils::{generic_struct_ty, struct_ty, MockStructDefinitionLoader}, - }; - use claims::{assert_err, assert_ok, assert_some}; - use move_core_types::{ - ability::AbilitySet, account_address::AccountAddress, language_storage::StructTag, - }; - use move_vm_types::gas::UnmeteredGasMeter; - use std::str::FromStr; - use test_case::test_case; - - /// Constructs layout (without any metering) for the given type. - fn construct_layout_for_test( - layout_converter: &LayoutConverter, - ty: &Type, - annotated: bool, - ) -> PartialVMResult { - let mut gas_meter = UnmeteredGasMeter; - let traversal_storage = TraversalStorage::new(); - let mut traversal_context = TraversalContext::new(&traversal_storage); - - if annotated { - layout_converter.type_to_annotated_type_layout_with_delayed_fields( - &mut gas_meter, - &mut traversal_context, - ty, - ) - } else { - layout_converter.type_to_type_layout_with_delayed_fields( - &mut gas_meter, - &mut traversal_context, - ty, - false, - ) - } - } - - #[test_case(true)] - #[test_case(false)] - fn test_layout_with_delayed_fields(contains_delayed_fields: bool) { - let layout = LayoutWithDelayedFields { - // Dummy layout. - layout: TriompheArc::new(MoveTypeLayout::U8), - contains_delayed_fields, - }; - assert_eq!( - layout.layout_when_contains_delayed_fields().is_some(), - contains_delayed_fields - ); - assert_eq!( - layout.into_layout_when_has_no_delayed_fields().is_some(), - !contains_delayed_fields - ); - } - - #[test_case(true)] - #[test_case(false)] - fn test_simple_tys_to_layouts(annotated: bool) { - let loader = MockStructDefinitionLoader::default(); - let layout_converter = LayoutConverter::new(&loader); - - let test_cases = [ - (Type::Bool, MoveTypeLayout::Bool), - (Type::U8, MoveTypeLayout::U8), - (Type::U16, MoveTypeLayout::U16), - (Type::U32, MoveTypeLayout::U32), - (Type::U64, MoveTypeLayout::U64), - (Type::U128, MoveTypeLayout::U128), - (Type::U256, MoveTypeLayout::U256), - (Type::Address, MoveTypeLayout::Address), - (Type::Signer, MoveTypeLayout::Signer), - ( - Type::Vector(triomphe::Arc::new(Type::U8)), - MoveTypeLayout::Vector(Box::new(MoveTypeLayout::U8)), - ), - ( - Type::Function { - args: vec![Type::U8], - results: vec![Type::U256], - abilities: AbilitySet::EMPTY, - }, - MoveTypeLayout::Function, - ), - ]; - - for (ty, expected_layout) in test_cases { - let result = construct_layout_for_test(&layout_converter, &ty, annotated); - let layout = assert_ok!(result); - - assert!(!layout.contains_delayed_fields); - assert_eq!(layout.layout.as_ref(), &expected_layout); - } - } - - #[test_case(true, true)] - #[test_case(true, false)] - #[test_case(false, true)] - #[test_case(false, false)] - fn test_layout_too_large(enable_lazy_loading: bool, annotated: bool) { - let vm_config = VMConfig { - enable_lazy_loading, - layout_max_size: 2, - ..VMConfig::default() - }; - let loader = MockStructDefinitionLoader::new_with_config(vm_config); - let layout_converter = LayoutConverter::new(&loader); - - let vec_u8_ty = Type::Vector(triomphe::Arc::new(Type::U8)); - assert_ok!(construct_layout_for_test( - &layout_converter, - &vec_u8_ty, - annotated - )); - - let vec_vec_u8_ty = Type::Vector(triomphe::Arc::new(vec_u8_ty)); - let result = construct_layout_for_test(&layout_converter, &vec_vec_u8_ty, annotated); - if enable_lazy_loading { - let err = assert_err!(result); - assert_eq!(err.major_status(), StatusCode::TOO_MANY_TYPE_NODES); - } else { - assert_ok!(result); - } - - let vec_vec_vec_u8_ty = Type::Vector(triomphe::Arc::new(vec_vec_u8_ty)); - let err = assert_err!(construct_layout_for_test( - &layout_converter, - &vec_vec_vec_u8_ty, - annotated - )); - assert_eq!(err.major_status(), StatusCode::TOO_MANY_TYPE_NODES); - } - - #[test_case(true)] - #[test_case(false)] - fn test_layout_too_deep(annotated: bool) { - let vm_config = VMConfig { - layout_max_depth: 2, - ..VMConfig::default() - }; - let loader = MockStructDefinitionLoader::new_with_config(vm_config); - let layout_converter = LayoutConverter::new(&loader); - - let vec_u8_ty = Type::Vector(triomphe::Arc::new(Type::U8)); - assert_ok!(construct_layout_for_test( - &layout_converter, - &vec_u8_ty, - annotated - )); - - let vec_vec_u8_ty = Type::Vector(triomphe::Arc::new(vec_u8_ty)); - let err = assert_err!(construct_layout_for_test( - &layout_converter, - &vec_vec_u8_ty, - annotated - )); - assert_eq!(err.major_status(), StatusCode::VM_MAX_VALUE_DEPTH_REACHED); - } - - #[test] - fn test_struct_layouts() { - let loader = MockStructDefinitionLoader::default(); - - let a = loader.get_struct_identifier("A"); - let b = loader.get_struct_identifier("B"); - let c = loader.get_struct_identifier("C"); - loader.add_struct("A", vec![]); - loader.add_struct("B", vec![("c", struct_ty(c))]); - loader.add_struct("C", vec![]); - - let layout_converter = LayoutConverter::new(&loader); - - let runtime_layout = |fields| MoveTypeLayout::Struct(MoveStructLayout::Runtime(fields)); - let annotated_layout = |name: &str, fields| { - MoveTypeLayout::Struct(MoveStructLayout::with_types( - StructTag { - address: AccountAddress::ONE, - module: Identifier::from_str("foo").unwrap(), - name: Identifier::from_str(name).unwrap(), - type_args: vec![], - }, - fields, - )) - }; - - for (i, name) in [(a, "A"), (c, "C")] { - let layout = assert_ok!(construct_layout_for_test( - &layout_converter, - &struct_ty(i), - false - )); - let layout = assert_some!(layout.into_layout_when_has_no_delayed_fields()); - assert_eq!(layout.as_ref(), &runtime_layout(vec![])); - - let layout = assert_ok!(construct_layout_for_test( - &layout_converter, - &struct_ty(i), - true - )); - let layout = assert_some!(layout.into_layout_when_has_no_delayed_fields()); - assert_eq!(layout.as_ref(), &annotated_layout(name, vec![])); - } - - let layout = assert_ok!(construct_layout_for_test( - &layout_converter, - &struct_ty(b), - false - )); - let layout = assert_some!(layout.into_layout_when_has_no_delayed_fields()); - assert_eq!( - layout.as_ref(), - &runtime_layout(vec![runtime_layout(vec![])]) - ); - - let layout = assert_ok!(construct_layout_for_test( - &layout_converter, - &struct_ty(b), - true - )); - let layout = assert_some!(layout.into_layout_when_has_no_delayed_fields()); - assert_eq!( - layout.as_ref(), - &annotated_layout("B", vec![MoveFieldLayout::new( - Identifier::from_str("c").unwrap(), - annotated_layout("C", vec![]) - )]) - ); - } - - #[test_case(true)] - #[test_case(false)] - fn test_runtime_cyclic_module_dependency(annotated: bool) { - let loader = MockStructDefinitionLoader::default(); - - // No cycles (structs and enums): - // - // struct A {} - // enum B { - // V1 { x: bool, }, - // V2 { a: A, }, - // } - let a = loader.get_struct_identifier("A"); - let b = loader.get_struct_identifier("B"); - loader.add_struct("A", vec![]); - loader.add_enum("B", vec![ - ("V1", vec![("x", Type::Bool)]), - ("V2", vec![("a", struct_ty(a))]), - ]); - - // Cycles between structs C and D, and between E and itself: - // - // struct C { d: D, } - // struct D { c: C, } - // struct E { e: E, } - let c = loader.get_struct_identifier("C"); - let d = loader.get_struct_identifier("D"); - let e = loader.get_struct_identifier("E"); - loader.add_struct("C", vec![("d", struct_ty(d))]); - loader.add_struct("D", vec![("c", struct_ty(c))]); - loader.add_struct("E", vec![("e", struct_ty(e))]); - - // Cycles between enums F and G. - // - // enum F { - // V0 { g: G, }, - // } - // enum G { - // V0 { fs: vector, }, - // } - let f = loader.get_struct_identifier("F"); - let g = loader.get_struct_identifier("G"); - loader.add_enum("F", vec![("V0", vec![("g", struct_ty(g))])]); - loader.add_enum("G", vec![("V0", vec![( - "fs", - Type::Vector(triomphe::Arc::new(struct_ty(f))), - )])]); - - let layout_converter = LayoutConverter::new(&loader); - for idx in [a, b] { - assert_ok!(construct_layout_for_test( - &layout_converter, - &struct_ty(idx), - annotated - )); - } - - for idx in [c, d, e, f, g] { - let err = assert_err!(construct_layout_for_test( - &layout_converter, - &struct_ty(idx), - annotated - )); - assert_eq!(err.major_status(), StatusCode::VM_MAX_VALUE_DEPTH_REACHED); - } - } - - #[test_case(true)] - #[test_case(false)] - fn test_nested_generic_no_runtime_cyclic_module_dependency(annotated: bool) { - let loader = MockStructDefinitionLoader::default(); - - // struct A { x: T } - let a = loader.get_struct_identifier("A"); - loader.add_struct("A", vec![("x", Type::TyParam(0))]); - - // struct B { x: T } - let b = loader.get_struct_identifier("B"); - loader.add_struct("B", vec![("x", Type::TyParam(0))]); - - // struct C { - // x: B, - // } - let c = loader.get_struct_identifier("C"); - loader.add_struct("C", vec![("x", generic_struct_ty(b, vec![Type::U8]))]); - - // Type for A>> - should not have cycles! - let a_u8 = generic_struct_ty(a, vec![Type::U8]); - let a_a_u8 = generic_struct_ty(a, vec![a_u8]); - let a_a_a_u8 = generic_struct_ty(a, vec![a_a_u8]); - - // Type for B>> - should not have cycles! - let b_u8 = generic_struct_ty(b, vec![Type::U8]); - let a_b_u8 = generic_struct_ty(a, vec![b_u8]); - let b_a_b_u8 = generic_struct_ty(b, vec![a_b_u8]); - - // B does not create cycles because instantiations are different: C contains B. - let b_c = generic_struct_ty(b, vec![struct_ty(c)]); - - for ty in [a_a_a_u8, b_a_b_u8, b_c] { - let layout_converter = LayoutConverter::new(&loader); - assert_ok!(construct_layout_for_test(&layout_converter, &ty, annotated)); - } - } - - #[test_case(true)] - #[test_case(false)] - fn test_runtime_cyclic_module_dependency_generic(annotated: bool) { - let loader = MockStructDefinitionLoader::default(); - - // Cycle between generic struct B and C: - // - // struct B { c: C } - // struct C { x: T, b: B } - let b = loader.get_struct_identifier("B"); - let c = loader.get_struct_identifier("C"); - loader.add_struct("B", vec![( - "c", - generic_struct_ty(c, vec![Type::TyParam(0)]), - )]); - loader.add_struct("C", vec![ - ("x", Type::TyParam(0)), - ("b", generic_struct_ty(b, vec![Type::TyParam(0)])), - ]); - - // Cycle between generic enum and generic struct: - // - // struct D { x: T, e: E, } - // enum E { - // V0 { ds: vector>, }, - // } - let d = loader.get_struct_identifier("D"); - let e = loader.get_struct_identifier("E"); - loader.add_struct("D", vec![ - ("x", Type::TyParam(0)), - ("e", generic_struct_ty(e, vec![Type::U8])), - ]); - loader.add_enum("E", vec![("V0", vec![( - "ds", - Type::Vector(triomphe::Arc::new(generic_struct_ty(d, vec![Type::U8]))), - )])]); - - let layout_converter = LayoutConverter::new(&loader); - - for idx in [b, c, d, e] { - let err = assert_err!(construct_layout_for_test( - &layout_converter, - &generic_struct_ty(idx, vec![Type::Bool]), - annotated - )); - assert_eq!(err.major_status(), StatusCode::VM_MAX_VALUE_DEPTH_REACHED); - } - } -} +// #[cfg(test)] +// mod tests { +// use super::*; +// use crate::{ +// module_traversal::{TraversalContext, TraversalStorage}, +// storage::loader::test_utils::{generic_struct_ty, struct_ty, MockStructDefinitionLoader}, +// }; +// use claims::{assert_err, assert_ok, assert_some}; +// use move_core_types::{ +// ability::AbilitySet, account_address::AccountAddress, language_storage::StructTag, +// }; +// use move_vm_types::gas::UnmeteredGasMeter; +// use std::str::FromStr; +// use test_case::test_case; +// +// /// Constructs layout (without any metering) for the given type. +// fn construct_layout_for_test( +// layout_converter: &LayoutConverter, +// ty: &Type, +// annotated: bool, +// ) -> PartialVMResult { +// let _gas_meter = UnmeteredGasMeter; +// let traversal_storage = TraversalStorage::new(); +// let _traversal_context = TraversalContext::new(&traversal_storage); +// +// unreachable!() +// // if annotated { +// // layout_converter.type_to_annotated_type_layout_with_delayed_fields( +// // &mut gas_meter, +// // &mut traversal_context, +// // ty, +// // ) +// // } else { +// // layout_converter.type_to_type_layout_with_delayed_fields( +// // &mut gas_meter, +// // &mut traversal_context, +// // ty, +// // false, +// // ) +// // } +// } +// +// #[test_case(true)] +// #[test_case(false)] +// fn test_layout_with_delayed_fields(contains_delayed_fields: bool) { +// let layout = LayoutWithDelayedFields { +// // Dummy layout. +// layout: TriompheArc::new(MoveTypeLayout::U8), +// contains_delayed_fields, +// }; +// assert_eq!( +// layout.layout_when_contains_delayed_fields().is_some(), +// contains_delayed_fields +// ); +// assert_eq!( +// layout.into_layout_when_has_no_delayed_fields().is_some(), +// !contains_delayed_fields +// ); +// } +// +// #[test_case(true)] +// #[test_case(false)] +// fn test_simple_tys_to_layouts(annotated: bool) { +// let loader = MockStructDefinitionLoader::default(); +// let layout_converter = LayoutConverter::new(&loader); +// +// let test_cases = [ +// (Type::Bool, MoveTypeLayout::Bool), +// (Type::U8, MoveTypeLayout::U8), +// (Type::U16, MoveTypeLayout::U16), +// (Type::U32, MoveTypeLayout::U32), +// (Type::U64, MoveTypeLayout::U64), +// (Type::U128, MoveTypeLayout::U128), +// (Type::U256, MoveTypeLayout::U256), +// (Type::Address, MoveTypeLayout::Address), +// (Type::Signer, MoveTypeLayout::Signer), +// ( +// Type::Vector(triomphe::Arc::new(Type::U8)), +// MoveTypeLayout::Vector(Box::new(MoveTypeLayout::U8)), +// ), +// ( +// Type::Function { +// args: vec![Type::U8], +// results: vec![Type::U256], +// abilities: AbilitySet::EMPTY, +// }, +// MoveTypeLayout::Function, +// ), +// ]; +// +// for (ty, expected_layout) in test_cases { +// let result = construct_layout_for_test(&layout_converter, &ty, annotated); +// let layout = assert_ok!(result); +// +// assert!(!layout.contains_delayed_fields); +// assert_eq!(layout.layout.as_ref(), &expected_layout); +// } +// } +// +// #[test_case(true, true)] +// #[test_case(true, false)] +// #[test_case(false, true)] +// #[test_case(false, false)] +// fn test_layout_too_large(enable_lazy_loading: bool, annotated: bool) { +// let vm_config = VMConfig { +// enable_lazy_loading, +// layout_max_size: 2, +// ..VMConfig::default() +// }; +// let loader = MockStructDefinitionLoader::new_with_config(vm_config); +// let layout_converter = LayoutConverter::new(&loader); +// +// let vec_u8_ty = Type::Vector(triomphe::Arc::new(Type::U8)); +// assert_ok!(construct_layout_for_test( +// &layout_converter, +// &vec_u8_ty, +// annotated +// )); +// +// let vec_vec_u8_ty = Type::Vector(triomphe::Arc::new(vec_u8_ty)); +// let result = construct_layout_for_test(&layout_converter, &vec_vec_u8_ty, annotated); +// if enable_lazy_loading { +// let err = assert_err!(result); +// assert_eq!(err.major_status(), StatusCode::TOO_MANY_TYPE_NODES); +// } else { +// assert_ok!(result); +// } +// +// let vec_vec_vec_u8_ty = Type::Vector(triomphe::Arc::new(vec_vec_u8_ty)); +// let err = assert_err!(construct_layout_for_test( +// &layout_converter, +// &vec_vec_vec_u8_ty, +// annotated +// )); +// assert_eq!(err.major_status(), StatusCode::TOO_MANY_TYPE_NODES); +// } +// +// #[test_case(true)] +// #[test_case(false)] +// fn test_layout_too_deep(annotated: bool) { +// let vm_config = VMConfig { +// layout_max_depth: 2, +// ..VMConfig::default() +// }; +// let loader = MockStructDefinitionLoader::new_with_config(vm_config); +// let layout_converter = LayoutConverter::new(&loader); +// +// let vec_u8_ty = Type::Vector(triomphe::Arc::new(Type::U8)); +// assert_ok!(construct_layout_for_test( +// &layout_converter, +// &vec_u8_ty, +// annotated +// )); +// +// let vec_vec_u8_ty = Type::Vector(triomphe::Arc::new(vec_u8_ty)); +// let err = assert_err!(construct_layout_for_test( +// &layout_converter, +// &vec_vec_u8_ty, +// annotated +// )); +// assert_eq!(err.major_status(), StatusCode::VM_MAX_VALUE_DEPTH_REACHED); +// } +// +// #[test] +// fn test_struct_layouts() { +// let loader = MockStructDefinitionLoader::default(); +// +// let a = loader.get_struct_identifier("A"); +// let b = loader.get_struct_identifier("B"); +// let c = loader.get_struct_identifier("C"); +// loader.add_struct("A", vec![]); +// loader.add_struct("B", vec![("c", struct_ty(c))]); +// loader.add_struct("C", vec![]); +// +// let layout_converter = LayoutConverter::new(&loader); +// +// let runtime_layout = |fields| MoveTypeLayout::Struct(MoveStructLayout::Runtime(fields)); +// let annotated_layout = |name: &str, fields| { +// MoveTypeLayout::Struct(MoveStructLayout::with_types( +// StructTag { +// address: AccountAddress::ONE, +// module: Identifier::from_str("foo").unwrap(), +// name: Identifier::from_str(name).unwrap(), +// type_args: vec![], +// }, +// fields, +// )) +// }; +// +// for (i, name) in [(a, "A"), (c, "C")] { +// let layout = assert_ok!(construct_layout_for_test( +// &layout_converter, +// &struct_ty(i), +// false +// )); +// let layout = assert_some!(layout.into_layout_when_has_no_delayed_fields()); +// assert_eq!(layout.as_ref(), &runtime_layout(vec![])); +// +// let layout = assert_ok!(construct_layout_for_test( +// &layout_converter, +// &struct_ty(i), +// true +// )); +// let layout = assert_some!(layout.into_layout_when_has_no_delayed_fields()); +// assert_eq!(layout.as_ref(), &annotated_layout(name, vec![])); +// } +// +// let layout = assert_ok!(construct_layout_for_test( +// &layout_converter, +// &struct_ty(b), +// false +// )); +// let layout = assert_some!(layout.into_layout_when_has_no_delayed_fields()); +// assert_eq!( +// layout.as_ref(), +// &runtime_layout(vec![runtime_layout(vec![])]) +// ); +// +// let layout = assert_ok!(construct_layout_for_test( +// &layout_converter, +// &struct_ty(b), +// true +// )); +// let layout = assert_some!(layout.into_layout_when_has_no_delayed_fields()); +// assert_eq!( +// layout.as_ref(), +// &annotated_layout("B", vec![MoveFieldLayout::new( +// Identifier::from_str("c").unwrap(), +// annotated_layout("C", vec![]) +// )]) +// ); +// } +// +// #[test_case(true)] +// #[test_case(false)] +// fn test_runtime_cyclic_module_dependency(annotated: bool) { +// let loader = MockStructDefinitionLoader::default(); +// +// // No cycles (structs and enums): +// // +// // struct A {} +// // enum B { +// // V1 { x: bool, }, +// // V2 { a: A, }, +// // } +// let a = loader.get_struct_identifier("A"); +// let b = loader.get_struct_identifier("B"); +// loader.add_struct("A", vec![]); +// loader.add_enum("B", vec![ +// ("V1", vec![("x", Type::Bool)]), +// ("V2", vec![("a", struct_ty(a))]), +// ]); +// +// // Cycles between structs C and D, and between E and itself: +// // +// // struct C { d: D, } +// // struct D { c: C, } +// // struct E { e: E, } +// let c = loader.get_struct_identifier("C"); +// let d = loader.get_struct_identifier("D"); +// let e = loader.get_struct_identifier("E"); +// loader.add_struct("C", vec![("d", struct_ty(d))]); +// loader.add_struct("D", vec![("c", struct_ty(c))]); +// loader.add_struct("E", vec![("e", struct_ty(e))]); +// +// // Cycles between enums F and G. +// // +// // enum F { +// // V0 { g: G, }, +// // } +// // enum G { +// // V0 { fs: vector, }, +// // } +// let f = loader.get_struct_identifier("F"); +// let g = loader.get_struct_identifier("G"); +// loader.add_enum("F", vec![("V0", vec![("g", struct_ty(g))])]); +// loader.add_enum("G", vec![("V0", vec![( +// "fs", +// Type::Vector(triomphe::Arc::new(struct_ty(f))), +// )])]); +// +// let layout_converter = LayoutConverter::new(&loader); +// for idx in [a, b] { +// assert_ok!(construct_layout_for_test( +// &layout_converter, +// &struct_ty(idx), +// annotated +// )); +// } +// +// for idx in [c, d, e, f, g] { +// let err = assert_err!(construct_layout_for_test( +// &layout_converter, +// &struct_ty(idx), +// annotated +// )); +// assert_eq!(err.major_status(), StatusCode::VM_MAX_VALUE_DEPTH_REACHED); +// } +// } +// +// #[test_case(true)] +// #[test_case(false)] +// fn test_nested_generic_no_runtime_cyclic_module_dependency(annotated: bool) { +// let loader = MockStructDefinitionLoader::default(); +// +// // struct A { x: T } +// let a = loader.get_struct_identifier("A"); +// loader.add_struct("A", vec![("x", Type::TyParam(0))]); +// +// // struct B { x: T } +// let b = loader.get_struct_identifier("B"); +// loader.add_struct("B", vec![("x", Type::TyParam(0))]); +// +// // struct C { +// // x: B, +// // } +// let c = loader.get_struct_identifier("C"); +// loader.add_struct("C", vec![("x", generic_struct_ty(b, vec![Type::U8]))]); +// +// // Type for A>> - should not have cycles! +// let a_u8 = generic_struct_ty(a, vec![Type::U8]); +// let a_a_u8 = generic_struct_ty(a, vec![a_u8]); +// let a_a_a_u8 = generic_struct_ty(a, vec![a_a_u8]); +// +// // Type for B>> - should not have cycles! +// let b_u8 = generic_struct_ty(b, vec![Type::U8]); +// let a_b_u8 = generic_struct_ty(a, vec![b_u8]); +// let b_a_b_u8 = generic_struct_ty(b, vec![a_b_u8]); +// +// // B does not create cycles because instantiations are different: C contains B. +// let b_c = generic_struct_ty(b, vec![struct_ty(c)]); +// +// for ty in [a_a_a_u8, b_a_b_u8, b_c] { +// let layout_converter = LayoutConverter::new(&loader); +// assert_ok!(construct_layout_for_test(&layout_converter, &ty, annotated)); +// } +// } +// +// #[test_case(true)] +// #[test_case(false)] +// fn test_runtime_cyclic_module_dependency_generic(annotated: bool) { +// let loader = MockStructDefinitionLoader::default(); +// +// // Cycle between generic struct B and C: +// // +// // struct B { c: C } +// // struct C { x: T, b: B } +// let b = loader.get_struct_identifier("B"); +// let c = loader.get_struct_identifier("C"); +// loader.add_struct("B", vec![( +// "c", +// generic_struct_ty(c, vec![Type::TyParam(0)]), +// )]); +// loader.add_struct("C", vec![ +// ("x", Type::TyParam(0)), +// ("b", generic_struct_ty(b, vec![Type::TyParam(0)])), +// ]); +// +// // Cycle between generic enum and generic struct: +// // +// // struct D { x: T, e: E, } +// // enum E { +// // V0 { ds: vector>, }, +// // } +// let d = loader.get_struct_identifier("D"); +// let e = loader.get_struct_identifier("E"); +// loader.add_struct("D", vec![ +// ("x", Type::TyParam(0)), +// ("e", generic_struct_ty(e, vec![Type::U8])), +// ]); +// loader.add_enum("E", vec![("V0", vec![( +// "ds", +// Type::Vector(triomphe::Arc::new(generic_struct_ty(d, vec![Type::U8]))), +// )])]); +// +// let layout_converter = LayoutConverter::new(&loader); +// +// for idx in [b, c, d, e] { +// let err = assert_err!(construct_layout_for_test( +// &layout_converter, +// &generic_struct_ty(idx, vec![Type::Bool]), +// annotated +// )); +// assert_eq!(err.major_status(), StatusCode::VM_MAX_VALUE_DEPTH_REACHED); +// } +// } +// } diff --git a/third_party/move/move-vm/runtime/src/storage/ty_tag_converter.rs b/third_party/move/move-vm/runtime/src/storage/ty_tag_converter.rs index 0a1ab84112025..52d791495fb3f 100644 --- a/third_party/move/move-vm/runtime/src/storage/ty_tag_converter.rs +++ b/third_party/move/move-vm/runtime/src/storage/ty_tag_converter.rs @@ -8,9 +8,11 @@ use move_core_types::{ language_storage::{FunctionParamOrReturnTag, FunctionTag, StructTag, TypeTag}, vm_status::StatusCode, }; -use move_vm_types::loaded_data::{runtime_types::Type, struct_name_indexing::StructNameIndex}; +use move_vm_types::{ + loaded_data::struct_name_indexing::StructNameIndex, + ty_interner::{TypeId, TypeRepr}, +}; use parking_lot::RwLock; -use std::hash::{Hash, Hasher}; struct PseudoGasContext { // Parameters for metering type tag construction: @@ -62,63 +64,13 @@ impl PseudoGasContext { } } -/// Key type for [TypeTagCache] that corresponds to a fully-instantiated struct. -#[derive(Clone, Eq, PartialEq)] -struct StructKey { - idx: StructNameIndex, - ty_args: Vec, -} - -#[derive(Eq, PartialEq)] -struct StructKeyRef<'a> { - idx: &'a StructNameIndex, - ty_args: &'a [Type], -} - -impl StructKey { - #[cfg(test)] - fn as_ref(&self) -> StructKeyRef<'_> { - StructKeyRef { - idx: &self.idx, - ty_args: self.ty_args.as_slice(), - } - } -} - -impl<'a> hashbrown::Equivalent> for StructKey { - fn equivalent(&self, other: &StructKeyRef<'a>) -> bool { - &self.idx == other.idx && self.ty_args.as_slice() == other.ty_args - } -} - -impl hashbrown::Equivalent for StructKeyRef<'_> { - fn equivalent(&self, other: &StructKey) -> bool { - self.idx == &other.idx && self.ty_args == other.ty_args.as_slice() - } -} - -// Ensure hash is the same as for StructKeyRef. -impl Hash for StructKey { - fn hash(&self, state: &mut H) { - self.idx.hash(state); - self.ty_args.hash(state); - } -} - -// Ensure hash is the same as for StructKey. -impl Hash for StructKeyRef<'_> { - fn hash(&self, state: &mut H) { - self.idx.hash(state); - self.ty_args.hash(state); - } -} - /// An entry in [TypeTagCache] that also stores a "cost" of the tag. The cost is proportional to /// the size of the tag, which includes the number of inner nodes and the sum of the sizes in bytes /// of addresses and identifiers. #[derive(Debug, Clone)] pub(crate) struct PricedStructTag { pub(crate) struct_tag: StructTag, + #[allow(dead_code)] pub(crate) pseudo_gas_cost: u64, } @@ -148,7 +100,7 @@ pub(crate) struct PricedStructTag { /// If thread 3 reads the tag of this enum, the read result is always **deterministic** for the /// fixed type parameters used by thread 3. pub(crate) struct TypeTagCache { - cache: RwLock>, + cache: RwLock>, } impl TypeTagCache { @@ -165,44 +117,30 @@ impl TypeTagCache { } /// Returns cached struct tag and its pseudo-gas cost if it exists, and [None] otherwise. - pub(crate) fn get_struct_tag( - &self, - idx: &StructNameIndex, - ty_args: &[Type], - ) -> Option { - self.cache - .read() - .get(&StructKeyRef { idx, ty_args }) - .cloned() + #[allow(dead_code)] + pub(crate) fn get_struct_tag(&self, ty: TypeId) -> Option { + self.cache.read().get(&ty).cloned() } /// Inserts the struct tag and its pseudo-gas cost ([PricedStructTag]) into the cache. Returns /// true if the tag was not cached before, and false otherwise. + #[allow(dead_code)] pub(crate) fn insert_struct_tag( &self, - idx: &StructNameIndex, - ty_args: &[Type], + ty: TypeId, priced_struct_tag: &PricedStructTag, ) -> bool { // Check if already cached. - if self - .cache - .read() - .contains_key(&StructKeyRef { idx, ty_args }) - { + if self.cache.read().contains_key(&ty) { return false; } - let key = StructKey { - idx: *idx, - ty_args: ty_args.to_vec(), - }; let priced_struct_tag = priced_struct_tag.clone(); // Otherwise, we need to insert. We did the clones outside the lock, and also avoid the // double insertion. let mut cache = self.cache.write(); - if let Entry::Vacant(entry) = cache.entry(key) { + if let Entry::Vacant(entry) = cache.entry(ty) { entry.insert(priced_struct_tag); true } else { @@ -228,7 +166,7 @@ impl<'a> TypeTagConverter<'a> { /// Converts a runtime type into a type tag. If the type is too complex (e.g., struct name size /// too large, or type too deeply nested), an error is returned. - pub(crate) fn ty_to_ty_tag(&self, ty: &Type) -> PartialVMResult { + pub(crate) fn ty_to_ty_tag(&self, ty: TypeId) -> PartialVMResult { let mut gas_context = PseudoGasContext::new(self.runtime_environment.vm_config()); self.ty_to_ty_tag_impl(ty, &mut gas_context) } @@ -239,15 +177,18 @@ impl<'a> TypeTagConverter<'a> { pub(crate) fn struct_name_idx_to_struct_tag( &self, struct_name_idx: &StructNameIndex, - ty_args: &[Type], + ty_args: &[TypeId], ) -> PartialVMResult { + // TODO: caches? let mut gas_context = PseudoGasContext::new(self.runtime_environment.vm_config()); - self.struct_name_idx_to_struct_tag_impl(struct_name_idx, ty_args, &mut gas_context) + let priced_tag = + self.struct_name_idx_to_struct_tag_impl(struct_name_idx, ty_args, &mut gas_context)?; + Ok(priced_tag.struct_tag) } fn ty_to_ty_tag_impl( &self, - ty: &Type, + ty: TypeId, gas_context: &mut PseudoGasContext, ) -> PartialVMResult { // Charge base cost at the start. @@ -255,80 +196,95 @@ impl<'a> TypeTagConverter<'a> { Ok(match ty { // Primitive types. - Type::Bool => TypeTag::Bool, - Type::U8 => TypeTag::U8, - Type::U16 => TypeTag::U16, - Type::U32 => TypeTag::U32, - Type::U64 => TypeTag::U64, - Type::U128 => TypeTag::U128, - Type::U256 => TypeTag::U256, - Type::I8 => TypeTag::I8, - Type::I16 => TypeTag::I16, - Type::I32 => TypeTag::I32, - Type::I64 => TypeTag::I64, - Type::I128 => TypeTag::I128, - Type::I256 => TypeTag::I256, - Type::Address => TypeTag::Address, - Type::Signer => TypeTag::Signer, - - // Vector types: recurse. - Type::Vector(elem_ty) => { - let elem_ty_tag = self.ty_to_ty_tag_impl(elem_ty, gas_context)?; - TypeTag::Vector(Box::new(elem_ty_tag)) - }, + TypeId::BOOL => TypeTag::Bool, + TypeId::U8 => TypeTag::U8, + TypeId::U16 => TypeTag::U16, + TypeId::U32 => TypeTag::U32, + TypeId::U64 => TypeTag::U64, + TypeId::U128 => TypeTag::U128, + TypeId::U256 => TypeTag::U256, + TypeId::I8 => TypeTag::I8, + TypeId::I16 => TypeTag::I16, + TypeId::I32 => TypeTag::I32, + TypeId::I64 => TypeTag::I64, + TypeId::I128 => TypeTag::I128, + TypeId::I256 => TypeTag::I256, + TypeId::ADDRESS => TypeTag::Address, + TypeId::SIGNER => TypeTag::Signer, + ty => { + let ty_pool = self.runtime_environment.ty_pool(); + match ty_pool.type_repr(ty) { + TypeRepr::Vector(elem) => { + let elem_ty_tag = self.ty_to_ty_tag_impl(elem, gas_context)?; + TypeTag::Vector(Box::new(elem_ty_tag)) + }, - // Structs: we need to convert indices to names, possibly caching struct tags. - Type::Struct { idx, .. } => { - let struct_tag = self.struct_name_idx_to_struct_tag_impl(idx, &[], gas_context)?; - TypeTag::Struct(Box::new(struct_tag)) - }, - Type::StructInstantiation { idx, ty_args, .. } => { - let struct_tag = - self.struct_name_idx_to_struct_tag_impl(idx, ty_args, gas_context)?; - TypeTag::Struct(Box::new(struct_tag)) - }, + // Structs: we need to convert indices to names, possibly caching struct tags. + TypeRepr::Struct { idx, ty_args } => { + let ty_tag_cache = self.runtime_environment.ty_tag_cache(); + // If cached, charge pseudo-gas cost and return. + if let Some(priced_tag) = ty_tag_cache.get_struct_tag(ty) { + gas_context.charge(priced_tag.pseudo_gas_cost)?; + return Ok(TypeTag::Struct(Box::new(priced_tag.struct_tag))); + } + + let ty_args_vec = ty_pool.get_type_vec(ty_args); + let priced_tag = self.struct_name_idx_to_struct_tag_impl( + &idx, + &ty_args_vec, + gas_context, + )?; + ty_tag_cache.insert_struct_tag(ty, &priced_tag); + TypeTag::Struct(Box::new(priced_tag.struct_tag)) + }, - // Functions: recursively construct tags for argument and return types. Note that these - // can be references, unlike regular tags. - Type::Function { - args, - results, - abilities, - } => { - let to_vec = |ts: &[Type], - gas_ctx: &mut PseudoGasContext| - -> PartialVMResult> { - ts.iter() - .map(|t| { - Ok(match t { - Type::Reference(t) => FunctionParamOrReturnTag::Reference( - self.ty_to_ty_tag_impl(t, gas_ctx)?, - ), - Type::MutableReference(t) => { - FunctionParamOrReturnTag::MutableReference( - self.ty_to_ty_tag_impl(t, gas_ctx)?, - ) - }, - t => FunctionParamOrReturnTag::Value( - self.ty_to_ty_tag_impl(t, gas_ctx)?, - ), - }) - }) - .collect() - }; - TypeTag::Function(Box::new(FunctionTag { - args: to_vec(args, gas_context)?, - results: to_vec(results, gas_context)?, - abilities: *abilities, - })) - }, + // Functions: recursively construct tags for argument and return types. Note that these + // can be references, unlike regular tags. + TypeRepr::Function { + args, + results, + abilities, + } => { + let args_vec = ty_pool.get_type_vec(args); + let results_vec = ty_pool.get_type_vec(results); + + let to_vec = |ts: &[TypeId], + gas_ctx: &mut PseudoGasContext| + -> PartialVMResult> { + ts.iter() + .map(|&t| { + Ok(match ty_pool.type_repr(t) { + TypeRepr::Reference(inner) => FunctionParamOrReturnTag::Reference( + self.ty_to_ty_tag_impl(inner, gas_ctx)?, + ), + TypeRepr::MutableReference(inner) => { + FunctionParamOrReturnTag::MutableReference( + self.ty_to_ty_tag_impl(inner, gas_ctx)?, + ) + }, + _ => FunctionParamOrReturnTag::Value( + self.ty_to_ty_tag_impl(t, gas_ctx)?, + ), + }) + }) + .collect() + }; + TypeTag::Function(Box::new(FunctionTag { + args: to_vec(&args_vec, gas_context)?, + results: to_vec(&results_vec, gas_context)?, + abilities, + })) + }, - // References and type parameters cannot be converted to tags. - Type::Reference(_) | Type::MutableReference(_) | Type::TyParam(_) => { - return Err( - PartialVMError::new(StatusCode::UNKNOWN_INVARIANT_VIOLATION_ERROR) - .with_message(format!("No type tag for {:?}", ty)), - ); + // References cannot be converted to tags. + TypeRepr::Reference(_) | TypeRepr::MutableReference(_) => { + return Err(PartialVMError::new( + StatusCode::UNKNOWN_INVARIANT_VIOLATION_ERROR, + ) + .with_message(format!("No type tag for TypeId {:?}", ty))); + }, + _ => unreachable!(), + } }, }) } @@ -336,23 +292,15 @@ impl<'a> TypeTagConverter<'a> { fn struct_name_idx_to_struct_tag_impl( &self, struct_name_idx: &StructNameIndex, - ty_args: &[Type], + ty_args: &[TypeId], gas_context: &mut PseudoGasContext, - ) -> PartialVMResult { - let ty_tag_cache = self.runtime_environment.ty_tag_cache(); - - // If cached, charge pseudo-gas cost and return. - if let Some(priced_tag) = ty_tag_cache.get_struct_tag(struct_name_idx, ty_args) { - gas_context.charge(priced_tag.pseudo_gas_cost)?; - return Ok(priced_tag.struct_tag); - } - + ) -> PartialVMResult { // If not cached, record the current cost and construct tags for type arguments. let cur_cost = gas_context.current_cost(); let type_args = ty_args .iter() - .map(|ty| self.ty_to_ty_tag_impl(ty, gas_context)) + .map(|&ty| self.ty_to_ty_tag_impl(ty, gas_context)) .collect::>>()?; // Construct the struct tag as well. @@ -361,294 +309,9 @@ impl<'a> TypeTagConverter<'a> { gas_context.charge_struct_tag(&struct_tag)?; // Cache the struct tag. Record its gas cost as well. - let priced_tag = PricedStructTag { + Ok(PricedStructTag { struct_tag, pseudo_gas_cost: gas_context.current_cost() - cur_cost, - }; - ty_tag_cache.insert_struct_tag(struct_name_idx, ty_args, &priced_tag); - - Ok(priced_tag.struct_tag) - } -} - -#[cfg(test)] -mod tests { - use super::*; - use crate::config::VMConfig; - use claims::{assert_err, assert_none, assert_ok, assert_ok_eq, assert_some}; - use hashbrown::Equivalent; - use move_binary_format::file_format::StructTypeParameter; - use move_core_types::{ - ability::{Ability, AbilitySet}, - account_address::AccountAddress, - identifier::Identifier, - language_storage::ModuleId, - }; - use move_vm_types::loaded_data::runtime_types::{ - AbilityInfo, StructIdentifier, StructLayout, StructType, TypeBuilder, - }; - use smallbitvec::SmallBitVec; - use std::{collections::hash_map::DefaultHasher, str::FromStr}; - use triomphe::Arc; - - fn calculate_hash(t: &T) -> u64 { - let mut s = DefaultHasher::new(); - t.hash(&mut s); - s.finish() - } - - #[test] - fn test_struct_key_equivalence_and_hash() { - let struct_keys = [ - StructKey { - idx: StructNameIndex::new(0), - ty_args: vec![], - }, - StructKey { - idx: StructNameIndex::new(1), - ty_args: vec![Type::U8], - }, - StructKey { - idx: StructNameIndex::new(2), - ty_args: vec![Type::Bool, Type::Vector(Arc::new(Type::Bool))], - }, - StructKey { - idx: StructNameIndex::new(3), - ty_args: vec![ - Type::Struct { - idx: StructNameIndex::new(0), - ability: AbilityInfo::struct_(AbilitySet::singleton(Ability::Key)), - }, - Type::StructInstantiation { - idx: StructNameIndex::new(1), - ty_args: Arc::new(vec![Type::Address, Type::Struct { - idx: StructNameIndex::new(2), - ability: AbilityInfo::struct_(AbilitySet::singleton(Ability::Copy)), - }]), - ability: AbilityInfo::generic_struct( - AbilitySet::singleton(Ability::Drop), - SmallBitVec::new(), - ), - }, - ], - }, - ]; - - for struct_key in struct_keys { - let struct_key_ref = struct_key.as_ref(); - assert!(struct_key.equivalent(&struct_key_ref)); - assert!(struct_key_ref.equivalent(&struct_key)); - assert_eq!(calculate_hash(&struct_key), calculate_hash(&struct_key_ref)); - } - } - - #[test] - fn test_type_tag_cache() { - let cache = TypeTagCache::empty(); - assert!(cache.cache.read().is_empty()); - assert!(cache - .get_struct_tag(&StructNameIndex::new(0), &[]) - .is_none()); - - let tag = PricedStructTag { - struct_tag: StructTag::from_str("0x1::foo::Foo").unwrap(), - pseudo_gas_cost: 10, - }; - assert!(cache.insert_struct_tag(&StructNameIndex::new(0), &[], &tag)); - - let tag = PricedStructTag { - struct_tag: StructTag::from_str("0x1::foo::Foo").unwrap(), - // Set different cost to check. - pseudo_gas_cost: 100, - }; - assert!(!cache.insert_struct_tag(&StructNameIndex::new(0), &[], &tag)); - - assert_eq!(cache.cache.read().len(), 1); - let cost = cache - .get_struct_tag(&StructNameIndex::new(0), &[]) - .unwrap() - .pseudo_gas_cost; - assert_eq!(cost, 10); - } - - #[test] - fn test_ty_to_ty_tag() { - let ty_builder = TypeBuilder::with_limits(10, 10); - - let runtime_environment = RuntimeEnvironment::new(vec![]); - let ty_tag_converter = TypeTagConverter::new(&runtime_environment); - - let disallowed_tys = [ - Type::TyParam(0), - ty_builder - .create_ref_ty(&ty_builder.create_u8_ty(), true) - .unwrap(), - ty_builder - .create_ref_ty(&ty_builder.create_u8_ty(), false) - .unwrap(), - ]; - for ty in disallowed_tys { - assert_err!(ty_tag_converter.ty_to_ty_tag(&ty)); - } - - let allowed_primitive_tys = [ - (ty_builder.create_bool_ty(), TypeTag::Bool), - (ty_builder.create_u8_ty(), TypeTag::U8), - (ty_builder.create_u16_ty(), TypeTag::U16), - (ty_builder.create_u32_ty(), TypeTag::U32), - (ty_builder.create_u64_ty(), TypeTag::U64), - (ty_builder.create_u128_ty(), TypeTag::U128), - (ty_builder.create_u256_ty(), TypeTag::U256), - (ty_builder.create_address_ty(), TypeTag::Address), - (ty_builder.create_signer_ty(), TypeTag::Signer), - ]; - for (ty, expected_tag) in allowed_primitive_tys { - let actual_tag = assert_ok!(ty_tag_converter.ty_to_ty_tag(&ty)); - assert_eq!(actual_tag, expected_tag); - } - - // Vectors. - let bool_vec_ty = ty_builder - .create_vec_ty(&ty_builder.create_bool_ty()) - .unwrap(); - let bool_vec_tag = TypeTag::Vector(Box::new(TypeTag::Bool)); - assert_ok_eq!( - ty_tag_converter.ty_to_ty_tag(&bool_vec_ty), - bool_vec_tag.clone() - ); - - // Structs. - let module_id = ModuleId::new(AccountAddress::ONE, Identifier::new("foo").unwrap()); - let bar_idx = runtime_environment - .struct_name_index_map() - .struct_name_to_idx(&StructIdentifier::new( - runtime_environment.module_id_pool(), - module_id, - Identifier::new("Bar").unwrap(), - )) - .unwrap(); - let module_id = ModuleId::new(AccountAddress::TWO, Identifier::new("foo").unwrap()); - let foo_idx = runtime_environment - .struct_name_index_map() - .struct_name_to_idx(&StructIdentifier::new( - runtime_environment.module_id_pool(), - module_id, - Identifier::new("Foo").unwrap(), - )) - .unwrap(); - - let struct_ty = - ty_builder.create_struct_ty(bar_idx, AbilityInfo::struct_(AbilitySet::EMPTY)); - let struct_tag = StructTag::from_str("0x1::foo::Bar").unwrap(); - assert_ok_eq!( - ty_tag_converter.ty_to_ty_tag(&struct_ty), - TypeTag::Struct(Box::new(struct_tag)) - ); - - let struct_ty = StructType { - idx: foo_idx, - layout: StructLayout::Single(vec![( - Identifier::new("field").unwrap(), - Type::TyParam(0), - )]), - phantom_ty_params_mask: Default::default(), - abilities: AbilitySet::EMPTY, - ty_params: vec![StructTypeParameter { - constraints: AbilitySet::EMPTY, - is_phantom: false, - }], - }; - let generic_struct_ty = ty_builder - .create_struct_instantiation_ty(&struct_ty, &[Type::TyParam(0)], &[bool_vec_ty]) - .unwrap(); - let struct_tag = StructTag::from_str("0x2::foo::Foo>").unwrap(); - assert_ok_eq!( - ty_tag_converter.ty_to_ty_tag(&generic_struct_ty), - TypeTag::Struct(Box::new(struct_tag)) - ); - } - - #[test] - fn test_ty_to_ty_tag_too_complex() { - let ty_builder = TypeBuilder::with_limits(10, 10); - - let vm_config = VMConfig { - type_base_cost: 1, - type_max_cost: 2, - ..Default::default() - }; - let runtime_environment = RuntimeEnvironment::new_with_config(vec![], vm_config); - let ty_tag_converter = TypeTagConverter::new(&runtime_environment); - - let bool_ty = ty_builder.create_bool_ty(); - assert_ok_eq!(ty_tag_converter.ty_to_ty_tag(&bool_ty), TypeTag::Bool); - - let vec_ty = ty_builder.create_vec_ty(&bool_ty).unwrap(); - assert_ok_eq!( - ty_tag_converter.ty_to_ty_tag(&vec_ty), - TypeTag::Vector(Box::new(TypeTag::Bool)) - ); - - let vec_ty = ty_builder.create_vec_ty(&vec_ty).unwrap(); - let err = assert_err!(ty_tag_converter.ty_to_ty_tag(&vec_ty)); - assert_eq!(err.major_status(), StatusCode::TYPE_TAG_LIMIT_EXCEEDED); - } - - #[test] - fn test_ty_to_ty_tag_struct_metering() { - let type_max_cost = 76; - let vm_config = VMConfig { - type_base_cost: 1, - type_byte_cost: 2, - type_max_cost, - ..Default::default() - }; - let runtime_environment = RuntimeEnvironment::new_with_config(vec![], vm_config); - let ty_tag_converter = TypeTagConverter::new(&runtime_environment); - - let module_id = ModuleId::new(AccountAddress::ONE, Identifier::new("foo").unwrap()); - let id = StructIdentifier::new( - runtime_environment.module_id_pool(), - module_id, - Identifier::new("Foo").unwrap(), - ); - let idx = runtime_environment - .struct_name_index_map() - .struct_name_to_idx(&id) - .unwrap(); - let struct_tag = StructTag::from_str("0x1::foo::Foo").unwrap(); - - let mut gas_context = PseudoGasContext::new(runtime_environment.vm_config()); - assert_ok_eq!( - ty_tag_converter.struct_name_idx_to_struct_tag_impl(&idx, &[], &mut gas_context), - struct_tag.clone() - ); - - // Address size, plus module name and struct name each taking 3 characters. - let expected_cost = 2 * (32 + 3 + 3); - assert_eq!(gas_context.current_cost(), expected_cost); - - let priced_tag = assert_some!(runtime_environment.ty_tag_cache().get_struct_tag(&idx, &[])); - assert_eq!(priced_tag.pseudo_gas_cost, expected_cost); - assert_eq!(priced_tag.struct_tag, struct_tag); - - // Now - let vm_config = VMConfig { - type_base_cost: 1, - type_byte_cost: 2, - // Use smaller limit, to test metering. - type_max_cost: type_max_cost - 1, - ..Default::default() - }; - let runtime_environment = RuntimeEnvironment::new_with_config(vec![], vm_config); - let mut gas_context = PseudoGasContext::new(runtime_environment.vm_config()); - - let err = assert_err!(ty_tag_converter.struct_name_idx_to_struct_tag_impl( - &idx, - &[], - &mut gas_context - )); - assert_eq!(err.major_status(), StatusCode::TYPE_TAG_LIMIT_EXCEEDED); - assert_none!(runtime_environment.ty_tag_cache().get_struct_tag(&idx, &[])); + }) } } diff --git a/third_party/move/move-vm/types/Cargo.toml b/third_party/move/move-vm/types/Cargo.toml index 8b8cb0e0b47cf..350c387205891 100644 --- a/third_party/move/move-vm/types/Cargo.toml +++ b/third_party/move/move-vm/types/Cargo.toml @@ -11,6 +11,7 @@ edition = { workspace = true } [dependencies] ambassador = { workspace = true } +arc-swap = { workspace = true } bcs = { workspace = true } better_any = { workspace = true } bytes = { workspace = true } diff --git a/third_party/move/move-vm/types/src/loaded_data/runtime_types.rs b/third_party/move/move-vm/types/src/loaded_data/runtime_types.rs index 16caa4bdbf2e3..cf8d8cd940f6a 100644 --- a/third_party/move/move-vm/types/src/loaded_data/runtime_types.rs +++ b/third_party/move/move-vm/types/src/loaded_data/runtime_types.rs @@ -7,6 +7,7 @@ use crate::{ loaded_data::struct_name_indexing::StructNameIndex, module_id_interner::{InternedModuleId, InternedModuleIdPool}, + ty_interner::{InternedTypePool, TypeId, TypeRepr}, }; use derivative::Derivative; use itertools::Itertools; @@ -261,9 +262,9 @@ impl StructType { #[derive(Debug, Clone, Eq, Hash, Ord, PartialEq, PartialOrd)] pub struct StructIdentifier { - module: ModuleId, + pub module: ModuleId, interned_module_id: InternedModuleId, - name: Identifier, + pub name: Identifier, } impl StructIdentifier { @@ -394,7 +395,7 @@ pub struct AbilityInfo { Ord = "ignore", PartialOrd = "ignore" )] - base_ability_set: AbilitySet, + pub base_ability_set: AbilitySet, #[derivative( PartialEq = "ignore", @@ -402,7 +403,7 @@ pub struct AbilityInfo { Ord = "ignore", PartialOrd = "ignore" )] - phantom_ty_args_mask: SmallBitVec, + pub phantom_ty_args_mask: SmallBitVec, } impl AbilityInfo { @@ -1529,14 +1530,14 @@ impl TypeBuilder { /// constructor functions, e.g., when an empty vector can be treated as None via option::none() /// function, which return type can be matched against the intended type of the argument. #[derive(Default)] -pub struct TypeParamMap<'a> { - map: BTreeMap, +pub struct TypeParamMap { + map: BTreeMap, } -impl<'a> TypeParamMap<'a> { +impl TypeParamMap { /// Returns the type from parameter map if it exists, and [None] otherwise. - pub fn get_ty_param(&self, idx: u16) -> Option { - self.map.get(&idx).map(|ty| (*ty).clone()) + pub fn get_ty_param(&self, idx: u16) -> Option { + self.map.get(&idx).copied() } /// Matches the actual type to the expected type, binding any type args to the necessary type @@ -1545,90 +1546,74 @@ impl<'a> TypeParamMap<'a> { /// Returns true if a successful match is made. // TODO: is this really needed in presence of paranoid mode? This does a deep structural // comparison and is expensive. - pub fn match_ty(&mut self, ty: &Type, expected_ty: &'a Type) -> bool { + pub fn match_ty(&mut self, pool: &InternedTypePool, ty: &Type, expected_ty: TypeId) -> bool { + if let Type::TyParam(idx) = ty { + use btree_map::Entry::*; + return match self.map.entry(*idx) { + Occupied(occupied_entry) => *occupied_entry.get() == expected_ty, + Vacant(vacant_entry) => { + vacant_entry.insert(expected_ty); + true + }, + }; + } + + let expected_ty = pool.type_repr(expected_ty); match (ty, expected_ty) { - // The important case, deduce the type params. - (Type::TyParam(idx), _) => { - use btree_map::Entry::*; - match self.map.entry(*idx) { - Occupied(occupied_entry) => *occupied_entry.get() == expected_ty, - Vacant(vacant_entry) => { - vacant_entry.insert(expected_ty); - true - }, - } - }, + // checked above + (Type::TyParam(_), _) => unreachable!(), // Recursive types we need to recurse the matching types. - (Type::Reference(inner), Type::Reference(expected_inner)) - | (Type::MutableReference(inner), Type::MutableReference(expected_inner)) => { - self.match_ty(inner, expected_inner) + (Type::Reference(inner), TypeRepr::Reference(expected_inner)) + | (Type::MutableReference(inner), TypeRepr::MutableReference(expected_inner)) => { + self.match_ty(pool, inner, expected_inner) }, - (Type::Vector(inner), Type::Vector(expected_inner)) => { - self.match_ty(inner, expected_inner) + (Type::Vector(inner), TypeRepr::Vector(expected_inner)) => { + self.match_ty(pool, inner, expected_inner) }, // Function types, the expected abilities need to be equal to the provided ones, // and recursively argument and result types need to match. - ( - Type::Function { - args, - results, - abilities, - }, - Type::Function { - args: exp_args, - results: exp_results, - abilities: exp_abilities, - }, - ) if abilities == exp_abilities - && args.len() == exp_args.len() - && results.len() == exp_results.len() => - { - args.iter().zip(exp_args).all(|(t, e)| self.match_ty(t, e)) - && results - .iter() - .zip(exp_results) - .all(|(t, e)| self.match_ty(t, e)) - }, + (Type::Function { .. }, TypeRepr::Function { .. }) => false, // TODO: fine for now // Abilities should not contribute to the equality check as they just serve for caching // computations. For structs the both need to be the same struct. ( Type::Struct { idx, .. }, - Type::Struct { + TypeRepr::Struct { idx: expected_idx, .. }, - ) => *idx == *expected_idx, + ) => *idx == expected_idx, // For struct instantiations we need to additionally match all type arguments. ( Type::StructInstantiation { idx, ty_args, .. }, - Type::StructInstantiation { + TypeRepr::Struct { idx: expected_idx, ty_args: expected_ty_args, .. }, ) => { - *idx == *expected_idx + let expected_ty_args = pool.get_type_vec(expected_ty_args); + *idx == expected_idx && ty_args.len() == expected_ty_args.len() && ty_args .iter() .zip(expected_ty_args.iter()) - .all(|types| self.match_ty(types.0, types.1)) + .all(|(t, e)| self.match_ty(pool, t, *e)) }, // For primitive types we need to assure the types match. - (Type::U8, Type::U8) - | (Type::U16, Type::U16) - | (Type::U32, Type::U32) - | (Type::U64, Type::U64) - | (Type::U128, Type::U128) - | (Type::U256, Type::U256) - | (Type::I8, Type::I8) - | (Type::I16, Type::I16) - | (Type::I32, Type::I32) - | (Type::I64, Type::I64) - | (Type::I128, Type::I128) - | (Type::I256, Type::I256) - | (Type::Bool, Type::Bool) - | (Type::Address, Type::Address) - | (Type::Signer, Type::Signer) => true, + (Type::U8, TypeRepr::U8) + | (Type::U16, TypeRepr::U16) + | (Type::U32, TypeRepr::U32) + | (Type::U64, TypeRepr::U64) + | (Type::U128, TypeRepr::U128) + | (Type::U256, TypeRepr::U256) + | (Type::I8, TypeRepr::I8) + | (Type::I16, TypeRepr::I16) + | (Type::I32, TypeRepr::I32) + | (Type::I64, TypeRepr::I64) + | (Type::I128, TypeRepr::I128) + | (Type::I256, TypeRepr::I256) + | (Type::Bool, TypeRepr::Bool) + | (Type::Address, TypeRepr::Address) + | (Type::Signer, TypeRepr::Signer) => true, // Otherwise the types do not match, and we can't match return type to the expected type. // Note we don't use the _ pattern but spell out all cases, so that the compiler will // bark when a case is missed upon future updates to the types. diff --git a/third_party/move/move-vm/types/src/loaded_data/struct_name_indexing.rs b/third_party/move/move-vm/types/src/loaded_data/struct_name_indexing.rs index 291de7366721e..c9af7cacb8564 100644 --- a/third_party/move/move-vm/types/src/loaded_data/struct_name_indexing.rs +++ b/third_party/move/move-vm/types/src/loaded_data/struct_name_indexing.rs @@ -20,7 +20,7 @@ macro_rules! panic_error { /// Represents a unique identifier for the struct name. Note that this index has no public /// constructor - the only way to construct it is via [StructNameIndexMap]. #[derive(Debug, Copy, Clone, Eq, Hash, Ord, PartialEq, PartialOrd)] -pub struct StructNameIndex(u32); +pub struct StructNameIndex(pub(crate) u32); impl StructNameIndex { /// Creates a new index for testing purposes only. For production, indices must always be diff --git a/third_party/move/move-vm/types/src/natives/function.rs b/third_party/move/move-vm/types/src/natives/function.rs index 5373dff0eca37..d564f27766391 100644 --- a/third_party/move/move-vm/types/src/natives/function.rs +++ b/third_party/move/move-vm/types/src/natives/function.rs @@ -17,7 +17,7 @@ //! This module contains the declarations and utilities to implement a native //! function. -use crate::{loaded_data::runtime_types::Type, values::Value}; +use crate::{ty_interner::TypeId, values::Value}; pub use move_binary_format::errors::{PartialVMError, PartialVMResult}; pub use move_core_types::{gas_algebra::InternalGas, vm_status::StatusCode}; use move_core_types::{identifier::Identifier, language_storage::ModuleId}; @@ -55,7 +55,7 @@ pub enum NativeResult { cost: InternalGas, module_name: ModuleId, func_name: Identifier, - ty_args: Vec, + ty_args: Vec, args: SmallVec<[Value; 1]>, }, /// Instruct the VM to load up a module into the loader and charge dependency for such operation. diff --git a/third_party/move/move-vm/types/src/ty_interner.rs b/third_party/move/move-vm/types/src/ty_interner.rs index 67e2253998856..5080e7207a641 100644 --- a/third_party/move/move-vm/types/src/ty_interner.rs +++ b/third_party/move/move-vm/types/src/ty_interner.rs @@ -4,16 +4,99 @@ //! Data structures and caches for interning types as unique compact identifiers. The lifetime of //! these caches is tied to the code cache, and is managed externally. -use crate::loaded_data::{runtime_types::Type, struct_name_indexing::StructNameIndex}; -use parking_lot::RwLock; -use std::collections::HashMap; -use triomphe::Arc; +use crate::loaded_data::{ + runtime_types::{StructType, Type, TypeBuilder}, + struct_name_indexing::StructNameIndex, +}; +use arc_swap::ArcSwap; +use crossbeam::utils::CachePadded; +use dashmap::{DashMap, Entry}; +use move_binary_format::{ + binary_views::BinaryIndexedView, + errors::{PartialVMError, PartialVMResult}, + file_format::SignatureToken, +}; +use move_core_types::{ + ability::{Ability, AbilitySet}, + vm_status::sub_status::unknown_invariant_violation::EPARANOID_FAILURE, +}; +use parking_lot::Mutex; +use std::sync::{ + atomic::{AtomicU64, AtomicUsize, Ordering}, + Arc, OnceLock, +}; + +const INITIAL_CAPACITY: usize = 4096 * 8; /// Compactly represents a loaded type. #[repr(transparent)] -#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)] +#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug)] pub struct TypeId(u32); +#[rustfmt::skip] +impl TypeId { + pub const BOOL: TypeId = TypeId(0); + pub const U8: TypeId = TypeId(1); + pub const U16: TypeId = TypeId(2); + pub const U32: TypeId = TypeId(3); + pub const U64: TypeId = TypeId(4); + pub const U128: TypeId = TypeId(5); + pub const U256: TypeId = TypeId(6); + pub const I8: TypeId = TypeId(7); + pub const I16: TypeId = TypeId(8); + pub const I32: TypeId = TypeId(9); + pub const I64: TypeId = TypeId(10); + pub const I128: TypeId = TypeId(11); + pub const I256: TypeId = TypeId(12); + pub const ADDRESS: TypeId = TypeId(13); + pub const SIGNER: TypeId = TypeId(14); +} + +impl TypeId { + const TAG_BASE: u32 = 0 << Self::TAG_SHIFT; + const TAG_MASK: u32 = 0b11 << Self::TAG_SHIFT; + const TAG_MUT_REF: u32 = 2 << Self::TAG_SHIFT; + const TAG_REF: u32 = 1 << Self::TAG_SHIFT; + const TAG_SHIFT: u32 = 30; + + #[inline(always)] + fn tag(self) -> u32 { + self.0 & Self::TAG_MASK + } + + #[inline] + pub fn payload(self) -> TypeId { + TypeId(self.0 & !Self::TAG_MASK) + } + + #[inline] + pub fn ref_of(inner: TypeId) -> TypeId { + assert_eq!(inner.tag(), Self::TAG_BASE); + TypeId(inner.0 | Self::TAG_REF) + } + + #[inline] + pub fn ref_mut_of(inner: TypeId) -> TypeId { + assert_eq!(inner.tag(), Self::TAG_BASE); + TypeId(inner.0 | Self::TAG_MUT_REF) + } + + #[inline] + pub fn is_ref(self) -> bool { + self.tag() == Self::TAG_REF + } + + #[inline] + pub fn is_mut_ref(self) -> bool { + self.tag() == Self::TAG_MUT_REF + } + + #[inline] + pub fn is_any_ref(self) -> bool { + self.is_ref() || self.is_mut_ref() + } +} + /// Compactly represents a vector of types. #[repr(transparent)] #[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)] @@ -21,7 +104,7 @@ pub struct TypeVecId(u32); /// Partially-interned representation containing top-level information. #[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)] -enum TypeRepr { +pub enum TypeRepr { Bool, U8, U16, @@ -47,111 +130,419 @@ enum TypeRepr { Function { args: TypeVecId, results: TypeVecId, + abilities: AbilitySet, }, } -struct InternMap { - interned: HashMap, - data: Vec, +impl TypeInterner { + fn clear(&self) { + self.rev.clear(); + self.fwd.clear_and_reset(); + } + + fn intern_vector(&self, elem: TypeId, abilities: AbilitySet) -> TypeId { + let repr = TypeRepr::Vector(elem); + if let Some(id) = self.rev.get(&repr) { + return *id; + } + + // TODO: we might grow under dashmap lock :/ + match self.rev.entry(repr) { + Entry::Occupied(entry) => *entry.get(), + Entry::Vacant(entry) => { + let idx = self.fwd.append_row(|snap, idx| { + let m0 = pack_meta0(RowKind::Vector, abilities, elem.0); + snap.metadata_0[idx as usize].store(m0, Ordering::Release); + }); + let id = TypeId(idx); + let _ = entry.insert(id); + id + }, + } + } + + fn intern_struct( + &self, + name_idx: StructNameIndex, + ty_args: TypeVecId, + abilities: AbilitySet, + ) -> TypeId { + let repr = TypeRepr::Struct { + idx: name_idx, + ty_args, + }; + if let Some(id) = self.rev.get(&repr) { + return *id; + } + + // TODO: we might grow under dashmap lock :/ + match self.rev.entry(repr) { + Entry::Occupied(entry) => *entry.get(), + Entry::Vacant(entry) => { + let idx = self.fwd.append_row(|snap, idx| { + snap.metadata_1[idx as usize].store(pack_meta1(ty_args.0), Ordering::Release); + let m0 = pack_meta0(RowKind::Struct, abilities, name_idx.0); + snap.metadata_0[idx as usize].store(m0, Ordering::Release); + }); + let id = TypeId(idx); + let _ = entry.insert(id); + id + }, + } + } + + fn intern_function( + &self, + args: TypeVecId, + results: TypeVecId, + abilities: AbilitySet, + ) -> TypeId { + let repr = TypeRepr::Function { + args, + results, + abilities, + }; + if let Some(id) = self.rev.get(&repr) { + return *id; + } + + // TODO: we might grow under dashmap lock :/ + match self.rev.entry(repr) { + Entry::Occupied(entry) => *entry.get(), + Entry::Vacant(entry) => { + let idx = self.fwd.append_row(|snap, idx| { + snap.metadata_1[idx as usize].store(pack_meta1(results.0), Ordering::Release); + let m0 = pack_meta0(RowKind::Function, abilities, args.0); + snap.metadata_0[idx as usize].store(m0, Ordering::Release); + }); + let id = TypeId(idx); + let _ = entry.insert(id); + id + }, + } + } } -impl Default for InternMap { - fn default() -> Self { +#[repr(u8)] +#[derive(Copy, Clone, Debug, PartialEq, Eq)] +enum RowKind { + Primitive = 0, + Vector = 1, + Struct = 2, + Function = 3, +} + +impl From for RowKind { + fn from(v: u8) -> Self { + match v { + 0 => RowKind::Primitive, + 1 => RowKind::Vector, + 2 => RowKind::Struct, + 3 => RowKind::Function, + _ => panic!("invalid row kind discriminant: {}", v), + } + } +} + +#[inline] +fn pack_meta0(kind: RowKind, abilities: AbilitySet, payload0_u32: u32) -> u64 { + let abilities = abilities.into_u8() & 0xF; + ((kind as u64) & 0b11) + | (((abilities as u64) & 0xF) << 2) + | (((payload0_u32 as u64) & 0xFFFF_FFFF) << 6) +} + +#[inline] +fn unpack_kind_from_meta0(meta0: u64) -> RowKind { + RowKind::from((meta0 & 0b11) as u8) +} + +#[inline(always)] +fn abilities_from_meta0(meta0: u64) -> AbilitySet { + AbilitySet::from_u8(((meta0 >> 2) & 0xF) as u8).expect("Ability bits should always be valid") +} + +#[inline] +fn unpack_payload_from_meta0(meta0: u64) -> u32 { + ((meta0 >> 6) & 0xFFFF_FFFF) as u32 +} + +#[inline] +fn pack_meta1(payload1_u32: u32) -> u64 { + (payload1_u32 as u64) & 0xFFFF_FFFF +} + +#[inline] +fn unpack_payload1(meta1: u64) -> u32 { + (meta1 & 0xFFFF_FFFF) as u32 +} + +struct ForwardSnapshot { + capacity: usize, + used: CachePadded, + // Stores type kind, abilities, and 32-bit payload for primitive and vector types. For structs + // also stores the struct name index. + metadata_0: Vec, + // Stores additional payload. + // - for structs types: type arguments. + // - for function types: arguments and results. + metadata_1: Vec, +} + +impl ForwardSnapshot { + fn with_capacity(capacity: usize) -> Self { + let init = || (0..capacity).map(|_| AtomicU64::new(0)).collect::>(); Self { - interned: HashMap::new(), - data: Vec::with_capacity(16), + capacity, + used: CachePadded::new(AtomicUsize::new(0)), + metadata_0: init(), + metadata_1: init(), + } + } + + #[allow(dead_code)] + fn copy_from(old: &Self, capacity: usize) -> Self { + let new = ForwardSnapshot::with_capacity(capacity); + let used = old.used.load(Ordering::Acquire); + + #[allow(clippy::needless_range_loop)] + for i in 0..used { + let m0 = old.metadata_0[i].load(Ordering::Acquire); + let m1 = old.metadata_1[i].load(Ordering::Acquire); + new.metadata_0[i].store(m0, Ordering::Release); + new.metadata_1[i].store(m1, Ordering::Release); } + new.used.store(used, Ordering::Release); + new } } -impl InternMap { - fn clear(&mut self) { - self.interned.clear(); - self.data.clear(); +struct ForwardTables { + snapshot: ArcSwap, + grow_lock: Mutex<()>, +} + +impl ForwardTables { + fn new(capacity: usize) -> Self { + let snapshot = ForwardSnapshot::with_capacity(capacity); + + // Warm-up for primitive types. + let num_warmed_up = (TypeId::SIGNER.0 + 1) as usize; + for i in 0..num_warmed_up { + let m0 = pack_meta0(RowKind::Primitive, AbilitySet::PRIMITIVES, 0); + snapshot.metadata_0[i].store(m0, Ordering::Relaxed); + } + snapshot.used.store(num_warmed_up, Ordering::Release); + + Self { + snapshot: ArcSwap::from_pointee(snapshot), + grow_lock: Mutex::new(()), + } + } + + fn append_row(&self, write_row: F) -> u32 + where + F: FnOnce(&ForwardSnapshot, u32), + { + // let _g = self.grow_lock.lock(); + + let snapshot = self.snapshot.load(); + let idx = snapshot.used.load(Ordering::Acquire) as u32; + + if (idx as usize) >= snapshot.capacity { + panic!( + "DEBUG-ONLY: idx is larger than capacity: {} > {}", + idx, snapshot.capacity + ); + // let capacity = snapshot.capacity.saturating_mul(2); + // self.snapshot + // .store(Arc::new(ForwardSnapshot::copy_from(&snapshot, capacity))); + // snapshot = self.snapshot.load(); + // idx = snapshot.used.load(Ordering::Acquire) as u32; + } + + write_row(&snapshot, idx); + snapshot.used.fetch_add(1, Ordering::Release); + idx + } + + fn clear_and_reset(&self) { + let _g = self.grow_lock.lock(); + + let snapshot = ForwardSnapshot::with_capacity(INITIAL_CAPACITY); + let num_warmed_up = (TypeId::SIGNER.0 + 1) as usize; + for i in 0..num_warmed_up { + let m0 = pack_meta0(RowKind::Primitive, AbilitySet::PRIMITIVES, 0); + snapshot.metadata_0[i].store(m0, Ordering::Relaxed); + } + snapshot.used.store(num_warmed_up, Ordering::Release); + self.snapshot.store(Arc::new(snapshot)); } } -/// Interns single types. struct TypeInterner { - inner: RwLock>, + rev: DashMap, + fwd: ForwardTables, } impl Default for TypeInterner { fn default() -> Self { Self { - inner: RwLock::new(InternMap::default()), + rev: DashMap::with_capacity(INITIAL_CAPACITY), + fwd: ForwardTables::new(INITIAL_CAPACITY), } } } -impl TypeInterner { - fn intern(&self, repr: TypeRepr) -> TypeId { - if let Some(id) = self.inner.read().interned.get(&repr) { - return *id; +struct TypeVecForwardSnapshot { + capacity: usize, + used: CachePadded, + values: Vec>>, +} + +impl TypeVecForwardSnapshot { + fn with_capacity(capacity: usize) -> Self { + Self { + capacity, + used: CachePadded::new(AtomicUsize::new(0)), + values: (0..capacity).map(|_| OnceLock::new()).collect(), } + } - let mut inner = self.inner.write(); - if let Some(id) = inner.interned.get(&repr) { - return *id; + #[allow(dead_code)] + fn copy_from(old: &Self, capacity: usize) -> Self { + let used = old.used.load(Ordering::Acquire); + let values = (0..capacity).map(|_| OnceLock::new()).collect::>(); + #[allow(clippy::needless_range_loop)] + for i in 0..used { + let v = old.values[i] + .get() + .expect("Type vector row is not initialized in old snapshot") + .clone(); + let _ = values[i].set(v); } + Self { + capacity, + used: CachePadded::new(AtomicUsize::new(used)), + values, + } + } +} - let id = TypeId(inner.data.len() as u32); - inner.data.push(repr); - inner.interned.insert(repr, id); - id +struct TypeVecForwardTables { + snapshot: ArcSwap, + grow_lock: Mutex<()>, +} + +impl TypeVecForwardTables { + fn new(capacity: usize) -> Self { + let snap = TypeVecForwardSnapshot::with_capacity(capacity); + Self { + snapshot: ArcSwap::from_pointee(snap), + grow_lock: Mutex::new(()), + } + } + + fn append_row(&self, payload: Arc<[TypeId]>) -> u32 { + // let _g = self.grow_lock.lock(); + + let cur = self.snapshot.load(); + let idx = cur.used.load(Ordering::Acquire) as u32; + + if (idx as usize) >= cur.capacity { + panic!( + "DEBUG-ONLY: idx is larger than capacity: {} > {}", + idx, cur.capacity + ); + // let new_cap = cur.capacity.saturating_mul(2); + // let next = TypeVecForwardSnapshot::copy_from(&cur, new_cap); + // self.snapshot.store(Arc::new(next)); + // cur = self.snapshot.load(); + // idx = cur.used.load(Ordering::Acquire) as u32; + } + + let cell = &cur.values[idx as usize]; + if cell.set(payload).is_ok() { + cur.used.fetch_add(1, Ordering::Release); + } + idx + } + + fn clear_and_reset(&self) { + let _g = self.grow_lock.lock(); + self.snapshot + .store(Arc::new(TypeVecForwardSnapshot::with_capacity( + INITIAL_CAPACITY, + ))); } } /// Interns vector of types (e.g., list of type arguments). struct TypeVecInterner { - inner: RwLock, TypeVecId>>, + rev: DashMap, TypeVecId>, + fwd: TypeVecForwardTables, } impl Default for TypeVecInterner { fn default() -> Self { Self { - inner: RwLock::new(InternMap::default()), + rev: DashMap::with_capacity(INITIAL_CAPACITY), + fwd: TypeVecForwardTables::new(INITIAL_CAPACITY), } } } impl TypeVecInterner { + fn clear(&self) { + self.rev.clear(); + self.fwd.clear_and_reset(); + } + fn intern(&self, tys: &[TypeId]) -> TypeVecId { - if let Some(id) = self.inner.read().interned.get(tys) { + if let Some(id) = self.rev.get(tys) { return *id; } - let tys_arced: Arc<[TypeId]> = Arc::from(tys); - let tys_arced_key = tys_arced.clone(); - - let mut inner = self.inner.write(); - if let Some(id) = inner.interned.get(tys) { - return *id; + let arc: Arc<[TypeId]> = Arc::from(tys); + match self.rev.entry(arc.clone()) { + Entry::Occupied(e) => *e.get(), + Entry::Vacant(v) => { + // TODO: fime, we still hold the dashmap lock... + let idx = self.fwd.append_row(arc); + let id = TypeVecId(idx); + v.insert(id); + id + }, } - - let id = TypeVecId(inner.data.len() as u32); - inner.data.push(tys_arced); - inner.interned.insert(tys_arced_key, id); - id } fn intern_vec(&self, tys: Vec) -> TypeVecId { - if let Some(id) = self.inner.read().interned.get(tys.as_slice()) { + if let Some(id) = self.rev.get(tys.as_slice()) { return *id; } - let tys: Arc<[TypeId]> = tys.into(); - let tys_key = tys.clone(); - - let mut inner = self.inner.write(); - if let Some(id) = inner.interned.get(&tys) { - return *id; + let arc: Arc<[TypeId]> = Arc::from(tys.into_boxed_slice()); + match self.rev.entry(arc.clone()) { + Entry::Occupied(e) => *e.get(), + Entry::Vacant(v) => { + // TODO: fime, we still hold the dashmap lock... + let idx = self.fwd.append_row(arc); + let id = TypeVecId(idx); + v.insert(id); + id + }, } + } - let id = TypeVecId(inner.data.len() as u32); - inner.data.push(tys); - inner.interned.insert(tys_key, id); - id + fn get_vec_arc(&self, id: TypeVecId) -> Arc<[TypeId]> { + let snap = self.fwd.snapshot.load(); + let idx = id.0 as usize; + let used = snap.used.load(Ordering::Acquire); + assert!(idx < used, "Invalid type vector index: {} >= {}", idx, used); + snap.values[idx] + .get() + .expect("Type vector row must be initialized") + .clone() } } @@ -180,12 +571,22 @@ impl InternedTypePool { /// Returns how many distinct types are instantiated. pub fn num_interned_tys(&self) -> usize { - self.ty_interner.inner.read().data.len() + self.ty_interner + .fwd + .snapshot + .load() + .used + .load(Ordering::Acquire) } /// Returns how many distinct vectors of types are instantiated. pub fn num_interned_ty_vecs(&self) -> usize { - self.ty_vec_interner.inner.read().data.len() + self.ty_vec_interner + .fwd + .snapshot + .load() + .used + .load(Ordering::Acquire) } /// Clears all interned data, and then warm-ups the cache for common types. Should be called if @@ -197,397 +598,735 @@ impl InternedTypePool { /// Flushes all cached data without warming up the cache. fn flush_impl(&self) { - let mut ty_interner = self.ty_interner.inner.write(); - ty_interner.clear(); - drop(ty_interner); - - let mut ty_vec_interner = self.ty_vec_interner.inner.write(); - ty_vec_interner.clear(); - drop(ty_vec_interner); + self.ty_interner.clear(); + self.ty_vec_interner.clear(); } /// Interns common type representations. fn warmup(&self) { - self.ty_interner.intern(TypeRepr::Bool); - let u8_id = self.ty_interner.intern(TypeRepr::U8); - self.ty_interner.intern(TypeRepr::U16); - self.ty_interner.intern(TypeRepr::U32); - let u64_id = self.ty_interner.intern(TypeRepr::U64); - self.ty_interner.intern(TypeRepr::U128); - self.ty_interner.intern(TypeRepr::U256); - self.ty_interner.intern(TypeRepr::I8); - self.ty_interner.intern(TypeRepr::I16); - self.ty_interner.intern(TypeRepr::I32); - self.ty_interner.intern(TypeRepr::I64); - self.ty_interner.intern(TypeRepr::I128); - self.ty_interner.intern(TypeRepr::I256); - self.ty_interner.intern(TypeRepr::Address); - self.ty_interner.intern(TypeRepr::Signer); - self.ty_vec_interner.intern(&[]); - self.ty_vec_interner.intern(&[u8_id]); - self.ty_vec_interner.intern(&[u64_id]); + self.ty_vec_interner.intern(&[TypeId::U8]); + self.ty_vec_interner.intern(&[TypeId::U64]); } - /// Given a vector if fully-instantiated type arguments, returns the corresponding [TypeVecId]. + /// Converts a slice of fully-instantiated type arguments to a vector of [TypeId]s. Does not + /// intern the vector itself. /// /// Panics if there are non-instantiated type arguments. - pub fn intern_ty_args(&self, ty_args: &[Type]) -> TypeVecId { - let ty_args = ty_args + pub fn ty_args_to_ty_ids(&self, ty_args: &[Type]) -> Vec { + ty_args .iter() .map(|t| self.instantiate_and_intern(t, &[])) - .collect::>(); - self.ty_vec_interner.intern_vec(ty_args) + .collect() + } + + /// Given a vector if fully-instantiated type arguments, returns the corresponding [TypeVecId]. + /// + /// Panics if there are non-instantiated type arguments. + pub fn intern_ty_args(&self, ty_args: &[Type]) -> TypeVecId { + let ty_arg_ids = self.ty_args_to_ty_ids(ty_args); + self.ty_vec_interner.intern_vec(ty_arg_ids) + } + + pub fn intern_ty_slice(&self, tys: &[TypeId]) -> TypeVecId { + self.ty_vec_interner.intern(tys) } - /// Given a type containing type parameters, and a fully-interned type arguments, performs - /// type substitution with interning. + // TODO: check bound at load-time (to bound type / constant size). + pub fn create_constant_ty(&self, constant_tok: &SignatureToken) -> TypeId { + use SignatureToken as S; + + match constant_tok { + S::Bool => TypeId::BOOL, + S::U8 => TypeId::U8, + S::U16 => TypeId::U16, + S::U32 => TypeId::U32, + S::U64 => TypeId::U64, + S::U128 => TypeId::U128, + S::U256 => TypeId::U256, + S::I8 => TypeId::I8, + S::I16 => TypeId::I16, + S::I32 => TypeId::I32, + S::I64 => TypeId::I64, + S::I128 => TypeId::I128, + S::I256 => TypeId::I256, + S::Address => TypeId::ADDRESS, + S::Vector(elem_tok) => { + // TODO: optimize + let elem_ty = TypeBuilder::with_limits(100, 100) + .create_constant_ty(elem_tok) + .unwrap(); + let elem = self.instantiate_and_intern(&elem_ty, &[]); + let abilities = + AbilitySet::polymorphic_abilities(AbilitySet::VECTOR, vec![false], vec![ + self.abilities(elem) + ]) + .expect("Vector ability computation should not fail"); + self.ty_interner.intern_vector(elem, abilities) + }, + S::Signer + | S::Struct(_) + | S::StructInstantiation(_, _) + | S::Function(..) + | S::Reference(_) + | S::MutableReference(_) + | S::TypeParameter(_) => unreachable!("Must be verified at load-time."), + } + } + + // TODO: add counts + return a result pub fn instantiate_and_intern(&self, ty: &Type, subst: &[TypeId]) -> TypeId { use Type::*; match ty { - Bool => self.ty_interner.intern(TypeRepr::Bool), - U8 => self.ty_interner.intern(TypeRepr::U8), - U16 => self.ty_interner.intern(TypeRepr::U16), - U32 => self.ty_interner.intern(TypeRepr::U32), - U64 => self.ty_interner.intern(TypeRepr::U64), - U128 => self.ty_interner.intern(TypeRepr::U128), - U256 => self.ty_interner.intern(TypeRepr::U256), - I8 => self.ty_interner.intern(TypeRepr::I8), - I16 => self.ty_interner.intern(TypeRepr::I16), - I32 => self.ty_interner.intern(TypeRepr::I32), - I64 => self.ty_interner.intern(TypeRepr::I64), - I128 => self.ty_interner.intern(TypeRepr::I128), - I256 => self.ty_interner.intern(TypeRepr::I256), - Address => self.ty_interner.intern(TypeRepr::Address), - Signer => self.ty_interner.intern(TypeRepr::Signer), + Bool => TypeId::BOOL, + U8 => TypeId::U8, + U16 => TypeId::U16, + U32 => TypeId::U32, + U64 => TypeId::U64, + U128 => TypeId::U128, + U256 => TypeId::U256, + I8 => TypeId::I8, + I16 => TypeId::I16, + I32 => TypeId::I32, + I64 => TypeId::I64, + I128 => TypeId::I128, + I256 => TypeId::I256, + Address => TypeId::ADDRESS, + Signer => TypeId::SIGNER, TyParam(idx) => subst[*idx as usize], Vector(elem_ty) => { - let id = self.instantiate_and_intern(elem_ty, subst); - self.vec_of(id) + let elem_id = self.instantiate_and_intern(elem_ty, subst); + let elem_abilities = self.abilities(elem_id); + let abilities = + AbilitySet::polymorphic_abilities(AbilitySet::VECTOR, vec![false], vec![ + elem_abilities, + ]) + .expect("Vector ability computation should not fail"); + self.ty_interner.intern_vector(elem_id, abilities) }, Reference(inner_ty) => { - let id = self.instantiate_and_intern(inner_ty, subst); - self.ref_of(id) + let inner_id = self.instantiate_and_intern(inner_ty, subst); + TypeId::ref_of(inner_id) }, MutableReference(inner_ty) => { - let id = self.instantiate_and_intern(inner_ty, subst); - self.ref_mut_of(id) + let inner_id = self.instantiate_and_intern(inner_ty, subst); + TypeId::ref_mut_of(inner_id) }, - Struct { idx, .. } => self.struct_of(*idx), - StructInstantiation { idx, ty_args, .. } => { - let ty_args = ty_args + Struct { idx, ability } => { + let abilities = ability.base_ability_set; + self.ty_interner + .intern_struct(*idx, self.ty_vec_interner.intern(&[]), abilities) + }, + StructInstantiation { + idx, + ty_args, + ability, + } => { + let ty_arg_ids = ty_args .iter() .map(|t| self.instantiate_and_intern(t, subst)) .collect::>(); - self.instantiated_struct_of(*idx, ty_args) + let type_argument_abilities = ty_arg_ids + .iter() + .map(|&ty_id| self.abilities(ty_id)) + .collect::>(); + let abilities = AbilitySet::polymorphic_abilities( + ability.base_ability_set, + ability.phantom_ty_args_mask.iter(), + type_argument_abilities, + ) + .expect("StructInstantiation ability computation should not fail"); + self.ty_interner.intern_struct( + *idx, + self.ty_vec_interner.intern_vec(ty_arg_ids), + abilities, + ) }, - Function { args, results, .. } => { - let args = args + Function { + args, + results, + abilities, + } => { + let arg_ids = args .iter() .map(|t| self.instantiate_and_intern(t, subst)) .collect::>(); - let results = results + let result_ids = results .iter() .map(|t| self.instantiate_and_intern(t, subst)) .collect::>(); - self.ty_interner.intern(TypeRepr::Function { - args: self.ty_vec_interner.intern_vec(args), - results: self.ty_vec_interner.intern_vec(results), - }) + let args_id = self.ty_vec_interner.intern_vec(arg_ids); + let results_id = self.ty_vec_interner.intern_vec(result_ids); + self.ty_interner + .intern_function(args_id, results_id, *abilities) }, } } - fn ref_of(&self, t: TypeId) -> TypeId { - self.ty_interner.intern(TypeRepr::Reference(t)) - } + // TODO: remove this? + pub fn intern_struct_instantiation( + &self, + struct_ty: &StructType, + ty_params: &[Type], + ty_args: &[TypeId], + ) -> TypeId { + let ty_arg_ids = ty_params + .iter() + .map(|ty| self.instantiate_and_intern(ty, ty_args)) + .collect::>(); - fn ref_mut_of(&self, t: TypeId) -> TypeId { - self.ty_interner.intern(TypeRepr::MutableReference(t)) - } + let type_argument_abilities = ty_arg_ids + .iter() + .map(|&ty_id| self.abilities(ty_id)) + .collect::>(); - fn vec_of(&self, t: TypeId) -> TypeId { - self.ty_interner.intern(TypeRepr::Vector(t)) + let abilities = AbilitySet::polymorphic_abilities( + struct_ty.abilities, + struct_ty.phantom_ty_params_mask.iter(), + type_argument_abilities, + ) + .expect("StructInstantiation ability computation should not fail"); + self.ty_interner.intern_struct( + struct_ty.idx, + self.ty_vec_interner.intern_vec(ty_arg_ids), + abilities, + ) } - fn struct_of(&self, idx: StructNameIndex) -> TypeId { - self.ty_interner.intern(TypeRepr::Struct { - idx, - ty_args: self.ty_vec_interner.intern(&[]), - }) + #[allow(dead_code)] + pub(crate) fn instantiate_and_intern_tok( + &self, + view: &BinaryIndexedView, + interned_struct_names: &[StructNameIndex], + ty: &SignatureToken, + subst: &[TypeId], + ) -> TypeId { + use SignatureToken::*; + match ty { + Bool => TypeId::BOOL, + U8 => TypeId::U8, + U16 => TypeId::U16, + U32 => TypeId::U32, + U64 => TypeId::U64, + U128 => TypeId::U128, + U256 => TypeId::U256, + I8 => TypeId::I8, + I16 => TypeId::I16, + I32 => TypeId::I32, + I64 => TypeId::I64, + I128 => TypeId::I128, + I256 => TypeId::I256, + Address => TypeId::ADDRESS, + Signer => TypeId::SIGNER, + TypeParameter(idx) => subst[*idx as usize], + Vector(elem_ty) => { + let elem_id = + self.instantiate_and_intern_tok(view, interned_struct_names, elem_ty, subst); + let elem_abilities = self.abilities(elem_id); + let abilities = + AbilitySet::polymorphic_abilities(AbilitySet::VECTOR, vec![false], vec![ + elem_abilities, + ]) + .expect("Vector ability computation should not fail"); + self.ty_interner.intern_vector(elem_id, abilities) + }, + Reference(inner_ty) => { + let inner_id = + self.instantiate_and_intern_tok(view, interned_struct_names, inner_ty, subst); + TypeId::ref_of(inner_id) + }, + MutableReference(inner_ty) => { + let inner_id = + self.instantiate_and_intern_tok(view, interned_struct_names, inner_ty, subst); + TypeId::ref_mut_of(inner_id) + }, + Struct(idx) => { + let struct_handle = view.struct_handle_at(*idx); + let abilities = struct_handle.abilities; + self.ty_interner.intern_struct( + interned_struct_names[idx.0 as usize], + self.ty_vec_interner.intern(&[]), + abilities, + ) + }, + StructInstantiation(idx, ty_args) => { + let ty_arg_ids = ty_args + .iter() + .map(|t| self.instantiate_and_intern_tok(view, interned_struct_names, t, subst)) + .collect::>(); + let ty_arg_abilities = ty_arg_ids + .iter() + .map(|&ty_id| self.abilities(ty_id)) + .collect::>(); + + let struct_handle = view.struct_handle_at(*idx); + let abilities = AbilitySet::polymorphic_abilities( + struct_handle.abilities, + struct_handle.type_parameters.iter().map(|ty| ty.is_phantom), + ty_arg_abilities, + ) + .expect("TODO: should propagate error"); + self.ty_interner.intern_struct( + interned_struct_names[idx.0 as usize], + self.ty_vec_interner.intern_vec(ty_arg_ids), + abilities, + ) + }, + Function(args, results, abilities) => { + let arg_ids = args + .iter() + .map(|t| self.instantiate_and_intern_tok(view, interned_struct_names, t, subst)) + .collect::>(); + let result_ids = results + .iter() + .map(|t| self.instantiate_and_intern_tok(view, interned_struct_names, t, subst)) + .collect::>(); + let args_id = self.ty_vec_interner.intern_vec(arg_ids); + let results_id = self.ty_vec_interner.intern_vec(result_ids); + self.ty_interner + .intern_function(args_id, results_id, *abilities) + }, + } } - fn instantiated_struct_of(&self, idx: StructNameIndex, ty_args: Vec) -> TypeId { - let ty_args = self.ty_vec_interner.intern_vec(ty_args); - self.ty_interner.intern(TypeRepr::Struct { idx, ty_args }) + #[inline] + pub fn vec_of(&self, elem: TypeId) -> TypeId { + let elem_abilities = self.abilities(elem); + let abilities = AbilitySet::polymorphic_abilities(AbilitySet::VECTOR, vec![false], vec![ + elem_abilities, + ]) + .expect("Vector ability computation should not fail"); + self.ty_interner.intern_vector(elem, abilities) } -} -#[cfg(test)] -mod test { - use super::*; - use crate::loaded_data::{runtime_types::AbilityInfo, struct_name_indexing::StructNameIndex}; - use move_core_types::ability::AbilitySet; - use std::{collections::HashSet, thread}; - - #[test] - fn test_primitive_types() { - let ctx = InternedTypePool::new(); - - let tys = [ - Type::Bool, - Type::U8, - Type::U16, - Type::U32, - Type::U64, - Type::U128, - Type::U256, - Type::I8, - Type::I16, - Type::I32, - Type::I64, - Type::I128, - Type::I256, - Type::Address, - Type::Signer, - ]; - - for ty in &tys { - let id1 = ctx.instantiate_and_intern(ty, &[]); - let id2 = ctx.instantiate_and_intern(ty, &[]); - assert_eq!(id1, id2); - } - } - - #[test] - fn test_vector_types() { - let ctx = InternedTypePool::new(); - - let vec_u8 = Type::Vector(Arc::new(Type::U8)); - let vec_u64 = Type::Vector(Arc::new(Type::U64)); - - let u8_id = ctx.instantiate_and_intern(&Type::U8, &[]); - let vec_u8_id1 = ctx.instantiate_and_intern(&vec_u8, &[]); - let vec_u8_id2 = ctx.instantiate_and_intern(&vec_u8, &[]); - let vec_u64_id = ctx.instantiate_and_intern(&vec_u64, &[]); - - assert_eq!(vec_u8_id1, vec_u8_id2); - assert_ne!(vec_u8_id1, vec_u64_id); - assert_ne!(vec_u8_id1, u8_id); - } - - #[test] - fn test_reference_types() { - let ctx = InternedTypePool::new(); - - let u64_ref = Type::Reference(Box::new(Type::U64)); - let u64_mut_ref = Type::MutableReference(Box::new(Type::U64)); - let u8_ref = Type::Reference(Box::new(Type::U8)); - - let u64_ref_id1 = ctx.instantiate_and_intern(&u64_ref, &[]); - let u64_ref_id2 = ctx.instantiate_and_intern(&u64_ref, &[]); - let u64_mut_ref_id = ctx.instantiate_and_intern(&u64_mut_ref, &[]); - let u8_ref_id = ctx.instantiate_and_intern(&u8_ref, &[]); - - assert_eq!(u64_ref_id1, u64_ref_id2); - assert_ne!(u64_ref_id1, u64_mut_ref_id); - assert_ne!(u64_ref_id1, u8_ref_id); - } - - #[test] - fn test_struct_types() { - let ctx = InternedTypePool::new(); - - let struct_type = Type::Struct { - idx: StructNameIndex::new(0), - ability: AbilityInfo::struct_(AbilitySet::EMPTY), - }; + #[inline] + pub fn type_repr(&self, ty: TypeId) -> TypeRepr { + if ty.is_ref() { + return TypeRepr::Reference(ty.payload()); + } + if ty.is_mut_ref() { + return TypeRepr::MutableReference(ty.payload()); + } - let id1 = ctx.instantiate_and_intern(&struct_type, &[]); - let id2 = ctx.instantiate_and_intern(&struct_type, &[]); + match ty { + TypeId::BOOL => TypeRepr::Bool, + TypeId::U8 => TypeRepr::U8, + TypeId::U16 => TypeRepr::U16, + TypeId::U32 => TypeRepr::U32, + TypeId::U64 => TypeRepr::U64, + TypeId::U128 => TypeRepr::U128, + TypeId::U256 => TypeRepr::U256, + TypeId::I8 => TypeRepr::I8, + TypeId::I16 => TypeRepr::I16, + TypeId::I32 => TypeRepr::I32, + TypeId::I64 => TypeRepr::I64, + TypeId::I128 => TypeRepr::I128, + TypeId::I256 => TypeRepr::I256, + TypeId::ADDRESS => TypeRepr::Address, + TypeId::SIGNER => TypeRepr::Signer, + _ => { + let snap = self.ty_interner.fwd.snapshot.load(); + let idx = ty.0 as usize; + let used = snap.used.load(Ordering::Acquire); + assert!(idx < used, "invalid TypeId payload {}", idx); + + let m0 = snap.metadata_0[idx].load(Ordering::Relaxed); + match unpack_kind_from_meta0(m0) { + RowKind::Primitive => unreachable!("composite ids should not be primitive"), + RowKind::Vector => { + let elem = TypeId(unpack_payload_from_meta0(m0)); + TypeRepr::Vector(elem) + }, + RowKind::Struct => { + let sidx = StructNameIndex(unpack_payload_from_meta0(m0)); + let m1 = snap.metadata_1[idx].load(Ordering::Relaxed); + let args = TypeVecId(unpack_payload1(m1)); + TypeRepr::Struct { + idx: sidx, + ty_args: args, + } + }, + RowKind::Function => { + let args = TypeVecId(unpack_payload_from_meta0(m0)); + let m1 = snap.metadata_1[idx].load(Ordering::Relaxed); + let results = TypeVecId(unpack_payload1(m1)); + TypeRepr::Function { + args, + results, + abilities: abilities_from_meta0(m0), + } + }, + } + }, + } + } - assert_eq!(id1, id2); + #[inline] + pub fn get_vec_elem_ty(&self, ty: TypeId) -> Option { + match self.type_repr(ty) { + TypeRepr::Vector(elem) => Some(elem), + _ => None, + } } - #[test] - fn test_structs() { - let ctx = InternedTypePool::new(); + #[inline] + pub fn get_type_vec(&self, id: TypeVecId) -> Arc<[TypeId]> { + self.ty_vec_interner.get_vec_arc(id) + } - let struct_ty = Type::StructInstantiation { - idx: StructNameIndex::new(0), - ty_args: Arc::new(vec![Type::U64, Type::Bool]), - // Irrelevant for tests. - ability: AbilityInfo::struct_(AbilitySet::EMPTY), - }; + #[inline] + pub fn abilities(&self, ty: TypeId) -> AbilitySet { + if ty >= TypeId::BOOL && ty <= TypeId::ADDRESS { + return AbilitySet::PRIMITIVES; + } + if ty == TypeId::SIGNER { + return AbilitySet::SIGNER; + } + if ty.is_ref() || ty.is_mut_ref() { + return AbilitySet::REFERENCES; + } - let id1 = ctx.instantiate_and_intern(&struct_ty, &[]); - let id2 = ctx.instantiate_and_intern(&struct_ty, &[]); - assert_eq!(id1, id2); + let snap = self.ty_interner.fwd.snapshot.load(); + let idx = ty.0 as usize; + let used = snap.used.load(Ordering::Acquire); + assert!( + idx < used, + "invalid TypeId payload {} when fetching abilities", + idx + ); + let m0 = snap.metadata_0[idx].load(Ordering::Relaxed); + abilities_from_meta0(m0) + } - let struct_inst2 = Type::StructInstantiation { - idx: StructNameIndex::new(0), - ty_args: Arc::new(vec![Type::Bool, Type::U64]), - // Irrelevant for tests. - ability: AbilityInfo::struct_(AbilitySet::EMPTY), - }; + #[inline] + pub fn has_ability(&self, ty: TypeId, ability: Ability) -> bool { + self.abilities(ty).has_ability(ability) + } - let id3 = ctx.instantiate_and_intern(&struct_inst2, &[]); - assert_ne!(id1, id3); + #[inline] + pub fn function_of( + &self, + args: &[TypeId], + results: &[TypeId], + abilities: AbilitySet, + ) -> TypeId { + let args_id = self.ty_vec_interner.intern(args); + let results_id = self.ty_vec_interner.intern(results); + self.ty_interner + .intern_function(args_id, results_id, abilities) } - #[test] - fn test_function_types() { - let ctx = InternedTypePool::new(); + #[inline] + pub fn function_of_vec( + &self, + args: Vec, + results: Vec, + abilities: AbilitySet, + ) -> TypeId { + let args_id = self.ty_vec_interner.intern_vec(args); + let results_id = self.ty_vec_interner.intern_vec(results); + self.ty_interner + .intern_function(args_id, results_id, abilities) + } - let func_ty = Type::Function { - args: vec![Type::U64, Type::Bool], - results: vec![Type::U8], - abilities: AbilitySet::EMPTY, - }; + #[inline] + pub fn paranoid_check_has_ability(&self, ty: TypeId, ability: Ability) -> PartialVMResult<()> { + if !self.has_ability(ty, ability) { + return Err(PartialVMError::new_invariant_violation(format!( + "Paranoid mode: type {:?} missing required ability {:?}", + self.type_repr(ty), + ability + )) + .with_sub_status(EPARANOID_FAILURE)); + } + Ok(()) + } - let id1 = ctx.instantiate_and_intern(&func_ty, &[]); - let id2 = ctx.instantiate_and_intern(&func_ty, &[]); + #[inline] + pub fn paranoid_check_abilities( + &self, + ty: TypeId, + required: AbilitySet, + ) -> PartialVMResult<()> { + let ty_abilities = self.abilities(ty); + if !required.is_subset(ty_abilities) { + return Err(PartialVMError::new_invariant_violation(format!( + "Paranoid mode: type {:?} missing required abilities {:?}", + self.type_repr(ty), + required + )) + .with_sub_status(EPARANOID_FAILURE)); + } + Ok(()) + } - assert_eq!(id1, id2); + #[inline] + pub fn paranoid_check_eq(&self, ty: TypeId, expected: TypeId) -> PartialVMResult<()> { + if ty != expected { + return Err(PartialVMError::new_invariant_violation(format!( + "Paranoid mode: type mismatch, expected {:?} but got {:?}", + expected, ty + )) + .with_sub_status(EPARANOID_FAILURE)); + } + Ok(()) + } - let func_ty = Type::Function { - args: vec![Type::U64], - results: vec![Type::U8], - abilities: AbilitySet::EMPTY, + #[inline] + pub fn paranoid_check_assignable( + &self, + given: TypeId, + expected: TypeId, + ) -> PartialVMResult<()> { + let ok = match (self.type_repr(expected), self.type_repr(given)) { + ( + TypeRepr::Function { + args: expected_args, + results: expected_results, + abilities: expected_abilities, + }, + TypeRepr::Function { + args: given_args, + results: given_results, + abilities: given_abilities, + }, + ) => { + expected_args == given_args + && expected_results == given_results + && expected_abilities.is_subset(given_abilities) + }, + (TypeRepr::Reference(expected_inner), TypeRepr::Reference(given_inner)) => { + self.paranoid_check_assignable(given_inner, expected_inner)?; + true + }, + _ => expected == given, }; - let id3 = ctx.instantiate_and_intern(&func_ty, &[]); - assert_ne!(id1, id3); - - let func_ty = Type::Function { - args: vec![Type::U64], - results: vec![Type::U8], - abilities: AbilitySet::ALL, - }; - let id4 = ctx.instantiate_and_intern(&func_ty, &[]); - assert_eq!(id3, id4); + if !ok { + return Err(PartialVMError::new_invariant_violation(format!( + "Paranoid mode: type mismatch, expected {:?} but got {:?}", + self.type_repr(expected), + self.type_repr(given) + )) + .with_sub_status(EPARANOID_FAILURE)); + } + Ok(()) } - #[test] - fn test_deeply_nested_type() { - let ctx = InternedTypePool::new(); - - let mut ty = Type::U64; - for _ in 0..10 { - ty = Type::Vector(Arc::new(ty)); + #[inline] + pub fn paranoid_check_ref_eq( + &self, + ty: TypeId, + expected_inner_ty: TypeId, + is_mut: bool, + ) -> PartialVMResult<()> { + match self.type_repr(ty) { + TypeRepr::MutableReference(inner) => { + self.paranoid_check_eq(inner, expected_inner_ty)?; + Ok(()) + }, + TypeRepr::Reference(inner) if !is_mut => { + self.paranoid_check_eq(inner, expected_inner_ty)?; + Ok(()) + }, + _ => Err(PartialVMError::new_invariant_violation(format!( + "Paranoid mode: expected a (mutable: {}) reference type, got {:?}", + is_mut, + self.type_repr(ty) + )) + .with_sub_status(EPARANOID_FAILURE)), } - - let id1 = ctx.instantiate_and_intern(&ty, &[]); - let id2 = ctx.instantiate_and_intern(&ty, &[]); - assert_eq!(id1, id2); } - #[test] - fn test_type_parameter_substitution() { - let ctx = InternedTypePool::new(); - - let u64_id = ctx.instantiate_and_intern(&Type::U64, &[]); - let substituted_id = ctx.instantiate_and_intern(&Type::TyParam(0), &[u64_id]); - assert_eq!(substituted_id, u64_id); + #[inline] + pub fn paranoid_check_is_no_ref(&self, ty: TypeId, msg: &str) -> PartialVMResult<()> { + match self.type_repr(ty) { + TypeRepr::Reference(_) | TypeRepr::MutableReference(_) => Err( + PartialVMError::new_invariant_violation(format!("{}: type is a reference", msg)) + .with_sub_status(EPARANOID_FAILURE), + ), + _ => Ok(()), + } } - #[test] - fn test_empty_type_vectors() { - let ctx = InternedTypePool::new(); - let id1 = ctx.intern_ty_args(&[]); - let id2 = ctx.intern_ty_args(&[]); - assert_eq!(id1, id2); + #[inline] + pub fn paranoid_check_is_bool_ty(&self, ty: TypeId) -> PartialVMResult<()> { + if ty != TypeId::BOOL { + return Err(PartialVMError::new_invariant_violation(format!( + "Paranoid mode: expected bool type, got {:?}", + self.type_repr(ty) + )) + .with_sub_status(EPARANOID_FAILURE)); + } + Ok(()) } - #[test] - fn test_type_vector_consistency() { - let ctx = InternedTypePool::new(); - - let u64_ty = Type::U64; - let bool_ty = Type::Bool; + #[inline] + pub fn paranoid_check_is_sint_ty(&self, ty: TypeId) -> PartialVMResult<()> { + if ty < TypeId::I8 || ty > TypeId::I256 { + return Err(PartialVMError::new_invariant_violation(format!( + "Paranoid mode: expected signed integer type, got {:?}", + self.type_repr(ty) + )) + .with_sub_status(EPARANOID_FAILURE)); + } + Ok(()) + } - let mut tys = vec![u64_ty, bool_ty]; - let id1 = ctx.intern_ty_args(&tys); - let id2 = ctx.intern_ty_args(&tys); - assert_eq!(id1, id2); + #[inline] + pub fn paranoid_check_is_u64_ty(&self, ty: TypeId) -> PartialVMResult<()> { + if ty != TypeId::U64 { + return Err(PartialVMError::new_invariant_violation(format!( + "Paranoid mode: expected u64 type, got {:?}", + self.type_repr(ty) + )) + .with_sub_status(EPARANOID_FAILURE)); + } + Ok(()) + } - tys.reverse(); - let id3 = ctx.intern_ty_args(&tys); - assert_ne!(id1, id3); + #[inline] + pub fn paranoid_check_is_address_ty(&self, ty: TypeId) -> PartialVMResult<()> { + if ty != TypeId::ADDRESS { + return Err(PartialVMError::new_invariant_violation(format!( + "Paranoid mode: expected address type, got {:?}", + self.type_repr(ty) + )) + .with_sub_status(EPARANOID_FAILURE)); + } + Ok(()) } - #[test] - fn test_flush_clears_cache() { - let ctx = InternedTypePool::new(); + #[inline] + pub fn paranoid_check_is_signer_ref_ty(&self, ty: TypeId) -> PartialVMResult<()> { + match self.type_repr(ty) { + TypeRepr::Reference(inner) if inner == TypeId::SIGNER => Ok(()), + _ => Err(PartialVMError::new_invariant_violation(format!( + "Paranoid mode: expected signer reference type, got {:?}", + ty + )) + .with_sub_status(EPARANOID_FAILURE)), + } + } - ctx.intern_ty_args(&[Type::U64]); - ctx.instantiate_and_intern(&Type::U64, &[]); + #[inline] + pub fn paranoid_check_is_vec_ty( + &self, + ty: TypeId, + expected_elem: TypeId, + ) -> PartialVMResult<()> { + let snap = self.ty_interner.fwd.snapshot.load(); + let idx = ty.0 as usize; + let used = snap.used.load(Ordering::Acquire); + assert!( + idx < used, + "invalid TypeId payload {} in paranoid_check_is_vec_ty", + idx + ); + + let m0 = snap.metadata_0[idx].load(Ordering::Relaxed); + if unpack_kind_from_meta0(m0) == RowKind::Vector { + let elem = unpack_payload_from_meta0(m0); + if elem == expected_elem.0 { + return Ok(()); + } + } - let initial_ty_count = ctx.num_interned_tys(); - let initial_ty_vec_count = ctx.num_interned_ty_vecs(); + Err(PartialVMError::new_invariant_violation(format!( + "Paranoid mode: expected vector<{:?}> type, got {:?}", + self.type_repr(expected_elem), + self.type_repr(ty) + )) + .with_sub_status(EPARANOID_FAILURE)) + } - assert!(initial_ty_count > 0); - assert!(initial_ty_vec_count > 0); + #[inline] + pub fn paranoid_check_is_vec_ref_ty( + &self, + ty: TypeId, + expected_elem: TypeId, + ) -> PartialVMResult<()> { + if ty.is_mut_ref() { + return self.paranoid_check_is_vec_ty(ty.payload(), expected_elem); + } - ctx.flush_impl(); + if ty.is_ref() { + if !IS_MUT { + return self.paranoid_check_is_vec_ty(ty.payload(), expected_elem); + } + } - assert_eq!(ctx.num_interned_tys(), 0); - assert_eq!(ctx.num_interned_ty_vecs(), 0); + Err(PartialVMError::new_invariant_violation(format!( + "Paranoid mode: expected a (mutable: {}) vector reference, got {:?}", + IS_MUT, + self.type_repr(ty) + )) + .with_sub_status(EPARANOID_FAILURE)) } - #[test] - fn test_concurrent_interning_same_type() { - let ctx = Arc::new(InternedTypePool::new()); - - let mut handles = Vec::new(); - for _ in 0..10 { - let ctx = Arc::clone(&ctx); - let handle = thread::spawn(move || ctx.instantiate_and_intern(&Type::U64, &[])); - handles.push(handle); + #[inline] + pub fn paranoid_read_ref(&self, ty: TypeId) -> PartialVMResult { + if ty.is_any_ref() { + self.paranoid_check_has_ability(ty.payload(), Ability::Copy)?; + Ok(ty.payload()) + } else { + Err(PartialVMError::new_invariant_violation(format!( + "Paranoid mode: expected reference type for ReadRef, got {:?}", + self.type_repr(ty) + )) + .with_sub_status(EPARANOID_FAILURE)) } + } - let mut ids = HashSet::new(); - for handle in handles { - let id = handle.join().unwrap(); - ids.insert(id); + #[inline] + pub fn paranoid_write_ref(&self, ty: TypeId, val_ty: TypeId) -> PartialVMResult<()> { + if ty.is_mut_ref() { + self.paranoid_check_assignable(val_ty, ty.payload())?; + self.paranoid_check_has_ability(ty.payload(), Ability::Drop)?; + Ok(()) + } else { + Err(PartialVMError::new_invariant_violation(format!( + "Paranoid mode: expected mutable reference type for WriteRef, got {:?}", + self.type_repr(ty) + )) + .with_sub_status(EPARANOID_FAILURE)) } - assert_eq!(ids.len(), 1); } - #[test] - fn test_concurrent_interning_different_types() { - let ctx = Arc::new(InternedTypePool::new()); - let tys = Arc::new(vec![ - Type::Bool, - Type::U8, - Type::U16, - Type::U32, - Type::U64, - Type::U128, - Type::U256, - Type::I8, - Type::I16, - Type::I32, - Type::I64, - Type::I128, - Type::I256, - Type::Address, - Type::Signer, - ]); - - let mut handles = Vec::new(); - for i in 0..tys.len() { - let tys = Arc::clone(&tys); - let ctx = Arc::clone(&ctx); - let handle = thread::spawn(move || ctx.instantiate_and_intern(&tys[i], &[])); - handles.push(handle); + #[inline] + pub fn paranoid_freeze_ref_ty(&self, ty: TypeId) -> PartialVMResult { + if ty.is_mut_ref() { + Ok(TypeId::ref_of(ty.payload())) + } else { + Err(PartialVMError::new_invariant_violation(format!( + "Paranoid mode: expected mutable reference type for FreezeRef, got {:?}", + self.type_repr(ty) + )) + .with_sub_status(EPARANOID_FAILURE)) } + } - let mut ids = HashSet::new(); - for handle in handles { - let id = handle.join().unwrap(); - ids.insert(id); + #[inline] + pub fn paranoid_check_and_get_vec_elem_ref_ty( + &self, + vec_ref_ty: TypeId, + expected_elem: TypeId, + ) -> PartialVMResult { + self.paranoid_check_is_vec_ref_ty::(vec_ref_ty, expected_elem)?; + if IS_MUT { + Ok(TypeId::ref_mut_of(expected_elem)) + } else { + Ok(TypeId::ref_of(expected_elem)) } - assert_eq!(ids.len(), tys.len()); + } + + #[inline] + pub fn paranoid_check_and_get_vec_elem_ty( + &self, + vec_ref_ty: TypeId, + expected_elem: TypeId, + ) -> PartialVMResult { + self.paranoid_check_is_vec_ref_ty::(vec_ref_ty, expected_elem)?; + Ok(expected_elem) } } diff --git a/third_party/move/move-vm/types/src/values/values_impl.rs b/third_party/move/move-vm/types/src/values/values_impl.rs index fb146051f01dd..c8f7cea3dffee 100644 --- a/third_party/move/move-vm/types/src/values/values_impl.rs +++ b/third_party/move/move-vm/types/src/values/values_impl.rs @@ -6,7 +6,7 @@ use crate::{ delayed_values::delayed_field_id::{DelayedFieldID, TryFromMoveValue, TryIntoMoveValue}, - loaded_data::runtime_types::Type, + ty_interner::TypeId, value_serde::ValueSerDeContext, values::function_values_impl::{AbstractFunction, Closure, ClosureVisitor}, views::{ValueView, ValueVisitor}, @@ -3416,61 +3416,41 @@ pub const VEC_UNPACK_PARITY_MISMATCH: u64 = NFE_VECTOR_ERROR_BASE + 3; // TODO: this check seems to be obsolete if paranoid mode is on, // and should either be removed or move over to runtime_type_checks? #[cfg_attr(feature = "force-inline", inline(always))] -fn check_elem_layout(ty: &Type, v: &Container) -> PartialVMResult<()> { +fn check_elem_layout(ty: TypeId, v: &Container) -> PartialVMResult<()> { match (ty, v) { - (Type::U8, Container::VecU8(_)) - | (Type::U64, Container::VecU64(_)) - | (Type::U16, Container::VecU16(_)) - | (Type::U32, Container::VecU32(_)) - | (Type::U128, Container::VecU128(_)) - | (Type::U256, Container::VecU256(_)) - | (Type::I8, Container::VecI8(_)) - | (Type::I64, Container::VecI64(_)) - | (Type::I16, Container::VecI16(_)) - | (Type::I32, Container::VecI32(_)) - | (Type::I128, Container::VecI128(_)) - | (Type::I256, Container::VecI256(_)) - | (Type::Bool, Container::VecBool(_)) - | (Type::Address, Container::VecAddress(_)) - | (Type::Signer, Container::Struct(_)) => Ok(()), - - (Type::Vector(_), Container::Vec(_)) => Ok(()), - - (Type::Struct { .. }, Container::Vec(_)) - | (Type::Signer, Container::Vec(_)) - | (Type::StructInstantiation { .. }, Container::Vec(_)) - | (Type::Function { .. }, Container::Vec(_)) => Ok(()), - - (Type::Reference(_), _) | (Type::MutableReference(_), _) | (Type::TyParam(_), _) => Err( - PartialVMError::new(StatusCode::UNKNOWN_INVARIANT_VIOLATION_ERROR) - .with_message(format!("invalid type param for vector: {:?}", ty)), + (TypeId::U8, Container::VecU8(_)) + | (TypeId::U64, Container::VecU64(_)) + | (TypeId::U16, Container::VecU16(_)) + | (TypeId::U32, Container::VecU32(_)) + | (TypeId::U128, Container::VecU128(_)) + | (TypeId::U256, Container::VecU256(_)) + | (TypeId::I8, Container::VecI8(_)) + | (TypeId::I64, Container::VecI64(_)) + | (TypeId::I16, Container::VecI16(_)) + | (TypeId::I32, Container::VecI32(_)) + | (TypeId::I128, Container::VecI128(_)) + | (TypeId::I256, Container::VecI256(_)) + | (TypeId::BOOL, Container::VecBool(_)) + | (TypeId::ADDRESS, Container::VecAddress(_)) + | (TypeId::SIGNER, Container::Struct(_)) => Ok(()), + (ty, Container::Vec(_)) => { + if ty.is_any_ref() { + Err( + PartialVMError::new(StatusCode::UNKNOWN_INVARIANT_VIOLATION_ERROR) + .with_message(format!("invalid type param for vector: {:?}", ty)), + ) + } else { + Ok(()) + } + }, + _ => Err( + PartialVMError::new(StatusCode::UNKNOWN_INVARIANT_VIOLATION_ERROR).with_message( + format!( + "vector elem layout mismatch, expected {:?}, got {:?}", + ty, v + ), + ), ), - - (Type::U8, _) - | (Type::U64, _) - | (Type::U16, _) - | (Type::U32, _) - | (Type::U128, _) - | (Type::U256, _) - | (Type::I8, _) - | (Type::I64, _) - | (Type::I16, _) - | (Type::I32, _) - | (Type::I128, _) - | (Type::I256, _) - | (Type::Bool, _) - | (Type::Address, _) - | (Type::Signer, _) - | (Type::Vector(_), _) - | (Type::Struct { .. }, _) - | (Type::StructInstantiation { .. }, _) - | (Type::Function { .. }, _) => Err(PartialVMError::new( - StatusCode::UNKNOWN_INVARIANT_VIOLATION_ERROR, - ) - .with_message(format!( - "vector elem layout mismatch, expected {:?}, got {:?}", - ty, v - ))), } } @@ -3682,7 +3662,7 @@ impl VectorRef { length: usize, to_self: &Self, insert_position: usize, - type_param: &Type, + type_param: TypeId, ) -> PartialVMResult<()> { let from_c = from_self.0.container(); let to_c = to_self.0.container(); @@ -3748,108 +3728,104 @@ impl VectorRef { impl Vector { // note(inline): LLVM won't inline it, even with #[inline(always)], and shouldn't, we don't want to bloat execute_code_impl - pub fn pack(type_param: &Type, elements: Vec) -> PartialVMResult { - let container = match type_param { - Type::U8 => Value::vector_u8( - elements - .into_iter() - .map(|v| v.value_as()) - .collect::>>()?, - ), - Type::U16 => Value::vector_u16( - elements - .into_iter() - .map(|v| v.value_as()) - .collect::>>()?, - ), - Type::U32 => Value::vector_u32( - elements - .into_iter() - .map(|v| v.value_as()) - .collect::>>()?, - ), - Type::U64 => Value::vector_u64( - elements - .into_iter() - .map(|v| v.value_as()) - .collect::>>()?, - ), - Type::U128 => Value::vector_u128( - elements - .into_iter() - .map(|v| v.value_as()) - .collect::>>()?, - ), - Type::U256 => Value::vector_u256( - elements - .into_iter() - .map(|v| v.value_as()) - .collect::>>()?, - ), - Type::I8 => Value::vector_i8( - elements - .into_iter() - .map(|v| v.value_as()) - .collect::>>()?, - ), - Type::I16 => Value::vector_i16( - elements - .into_iter() - .map(|v| v.value_as()) - .collect::>>()?, - ), - Type::I32 => Value::vector_i32( - elements - .into_iter() - .map(|v| v.value_as()) - .collect::>>()?, - ), - Type::I64 => Value::vector_i64( - elements - .into_iter() - .map(|v| v.value_as()) - .collect::>>()?, - ), - Type::I128 => Value::vector_i128( - elements - .into_iter() - .map(|v| v.value_as()) - .collect::>>()?, - ), - Type::I256 => Value::vector_i256( - elements - .into_iter() - .map(|v| v.value_as()) - .collect::>>()?, - ), - Type::Bool => Value::vector_bool( - elements - .into_iter() - .map(|v| v.value_as()) - .collect::>>()?, - ), - Type::Address => Value::vector_address( - elements - .into_iter() - .map(|v| v.value_as()) - .collect::>>()?, - ), - - Type::Signer - | Type::Vector(_) - | Type::Struct { .. } - | Type::StructInstantiation { .. } - | Type::Function { .. } => { - Value::Container(Container::Vec(Rc::new(RefCell::new(elements)))) - }, - - Type::Reference(_) | Type::MutableReference(_) | Type::TyParam(_) => { - return Err( - PartialVMError::new(StatusCode::UNKNOWN_INVARIANT_VIOLATION_ERROR) - .with_message(format!("invalid type param for vector: {:?}", type_param)), - ) - }, - }; + pub fn pack(type_param: TypeId, elements: Vec) -> PartialVMResult { + let container = + match type_param { + TypeId::U8 => Value::vector_u8( + elements + .into_iter() + .map(|v| v.value_as()) + .collect::>>()?, + ), + TypeId::U16 => Value::vector_u16( + elements + .into_iter() + .map(|v| v.value_as()) + .collect::>>()?, + ), + TypeId::U32 => Value::vector_u32( + elements + .into_iter() + .map(|v| v.value_as()) + .collect::>>()?, + ), + TypeId::U64 => Value::vector_u64( + elements + .into_iter() + .map(|v| v.value_as()) + .collect::>>()?, + ), + TypeId::U128 => Value::vector_u128( + elements + .into_iter() + .map(|v| v.value_as()) + .collect::>>()?, + ), + TypeId::U256 => Value::vector_u256( + elements + .into_iter() + .map(|v| v.value_as()) + .collect::>>()?, + ), + TypeId::I8 => Value::vector_i8( + elements + .into_iter() + .map(|v| v.value_as()) + .collect::>>()?, + ), + TypeId::I16 => Value::vector_i16( + elements + .into_iter() + .map(|v| v.value_as()) + .collect::>>()?, + ), + TypeId::I32 => Value::vector_i32( + elements + .into_iter() + .map(|v| v.value_as()) + .collect::>>()?, + ), + TypeId::I64 => Value::vector_i64( + elements + .into_iter() + .map(|v| v.value_as()) + .collect::>>()?, + ), + TypeId::I128 => Value::vector_i128( + elements + .into_iter() + .map(|v| v.value_as()) + .collect::>>()?, + ), + TypeId::I256 => Value::vector_i256( + elements + .into_iter() + .map(|v| v.value_as()) + .collect::>>()?, + ), + TypeId::BOOL => Value::vector_bool( + elements + .into_iter() + .map(|v| v.value_as()) + .collect::>>()?, + ), + TypeId::ADDRESS => Value::vector_address( + elements + .into_iter() + .map(|v| v.value_as()) + .collect::>>()?, + ), + ty => { + if ty.is_any_ref() { + return Err(PartialVMError::new( + StatusCode::UNKNOWN_INVARIANT_VIOLATION_ERROR, + ) + .with_message(format!("invalid type param for vector: {:?}", type_param))); + } else { + Value::Container(Container::Vec(Rc::new(RefCell::new(elements)))) + } + }, + }; Ok(container) } @@ -3933,7 +3909,7 @@ impl Vector { } pub fn to_vec_u8(self) -> PartialVMResult> { - check_elem_layout(&Type::U8, &self.0)?; + check_elem_layout(TypeId::U8, &self.0)?; if let Container::VecU8(r) = self.0 { Ok(take_unique_ownership(r)?.into_iter().collect()) } else {