diff --git a/core-backend/src/env.rs b/core-backend/src/env.rs index 1424106b841..d49dd496509 100644 --- a/core-backend/src/env.rs +++ b/core-backend/src/env.rs @@ -190,16 +190,12 @@ where builder.add_func(CreateProgram, wrap_syscall!(create_program)); builder.add_func(CreateProgramWGas, wrap_syscall!(create_program_wgas)); builder.add_func(Debug, wrap_syscall!(debug)); - builder.add_func(Panic, wrap_syscall!(panic)); - builder.add_func(OomPanic, wrap_syscall!(oom_panic)); - builder.add_func(Exit, wrap_syscall!(exit)); builder.add_func(ReplyCode, wrap_syscall!(reply_code)); builder.add_func(SignalCode, wrap_syscall!(signal_code)); builder.add_func(ReserveGas, wrap_syscall!(reserve_gas)); builder.add_func(ReplyDeposit, wrap_syscall!(reply_deposit)); builder.add_func(UnreserveGas, wrap_syscall!(unreserve_gas)); builder.add_func(GasAvailable, wrap_syscall!(gas_available)); - builder.add_func(Leave, wrap_syscall!(leave)); builder.add_func(MessageId, wrap_syscall!(message_id)); builder.add_func(PayProgramRent, wrap_syscall!(pay_program_rent)); builder.add_func(ProgramId, wrap_syscall!(program_id)); @@ -228,9 +224,6 @@ where builder.add_func(Source, wrap_syscall!(source)); builder.add_func(Value, wrap_syscall!(value)); builder.add_func(ValueAvailable, wrap_syscall!(value_available)); - builder.add_func(Wait, wrap_syscall!(wait)); - builder.add_func(WaitFor, wrap_syscall!(wait_for)); - builder.add_func(WaitUpTo, wrap_syscall!(wait_up_to)); builder.add_func(Wake, wrap_syscall!(wake)); builder.add_func(SystemReserveGas, wrap_syscall!(system_reserve_gas)); builder.add_func(ReservationReply, wrap_syscall!(reservation_reply)); @@ -238,6 +231,7 @@ where builder.add_func(ReservationSend, wrap_syscall!(reservation_send)); builder.add_func(ReservationSendCommit, wrap_syscall!(reservation_send_commit)); builder.add_func(SystemBreak, wrap_syscall!(system_break)); + builder.add_func(UserBreak, wrap_syscall!(user_break)); builder.add_func(Alloc, wrap_syscall!(alloc)); builder.add_func(Free, wrap_syscall!(free)); diff --git a/core-backend/src/funcs.rs b/core-backend/src/funcs.rs index d57477e0c2c..a66e4c025be 100644 --- a/core-backend/src/funcs.rs +++ b/core-backend/src/funcs.rs @@ -46,7 +46,7 @@ use gear_core::{ use gear_core_errors::{MessageError, ReplyCode, SignalCode}; use gear_sandbox::{default_executor::Caller, ReturnValue, Value}; use gear_sandbox_env::{HostError, WasmReturnValue}; -use gear_wasm_instrument::SystemBreakCode; +use gear_wasm_instrument::{syscalls::UserBreakKind, SystemBreakCode}; use gsys::{ BlockNumberWithHash, ErrorBytes, ErrorWithBlockNumberAndValue, ErrorWithGas, ErrorWithHandle, ErrorWithHash, ErrorWithReplyCode, ErrorWithSignalCode, ErrorWithTwoHashes, Gas, Hash, @@ -592,12 +592,13 @@ where }) } - pub fn exit(inheritor_id_ptr: u32) -> impl Syscall { - InfallibleSyscall::new(RuntimeCosts::Exit, move |ctx: &mut CallerWrap| { - let read_inheritor_id = ctx.manager.register_read_decoded(inheritor_id_ptr); - let inheritor_id = ctx.read_decoded(read_inheritor_id)?; - Err(ActorTerminationReason::Exit(inheritor_id).into()) - }) + pub fn exit( + ctx: &mut CallerWrap, + inheritor_id_ptr: u32, + ) -> Result<(), UndefinedTerminationReason> { + let read_inheritor_id = ctx.manager.register_read_decoded(inheritor_id_ptr); + let inheritor_id = ctx.read_decoded(read_inheritor_id)?; + Err(ActorTerminationReason::Exit(inheritor_id).into()) } pub fn reply_code() -> impl Syscall { @@ -1032,21 +1033,21 @@ where ) } - pub fn panic(data_ptr: u32, data_len: u32) -> impl Syscall { - InfallibleSyscall::new(RuntimeCosts::Null, move |ctx: &mut CallerWrap| { - let read_data = ctx.manager.register_read(data_ptr, data_len); - let data = ctx.read(read_data).unwrap_or_default(); + pub fn panic( + ctx: &mut CallerWrap, + data_ptr: u32, + data_len: u16, + ) -> Result<(), UndefinedTerminationReason> { + let read_data = ctx.manager.register_read(data_ptr, data_len as u32); + let data = ctx.read(read_data).unwrap_or_default(); - let s = String::from_utf8_lossy(&data).to_string(); + let s = String::from_utf8_lossy(&data).to_string(); - Err(ActorTerminationReason::Trap(TrapExplanation::Panic(s.into())).into()) - }) + Err(ActorTerminationReason::Trap(TrapExplanation::Panic(s.into())).into()) } - pub fn oom_panic() -> impl Syscall { - InfallibleSyscall::new(RuntimeCosts::Null, |_ctx: &mut CallerWrap| { - Err(ActorTerminationReason::Trap(TrapExplanation::ProgramAllocOutOfBounds).into()) - }) + pub fn oom_panic() -> Result<(), UndefinedTerminationReason> { + Err(ActorTerminationReason::Trap(TrapExplanation::ProgramAllocOutOfBounds).into()) } pub fn reserve_gas(gas_value: u64, duration: u32) -> impl Syscall { @@ -1183,35 +1184,33 @@ where ) } - pub fn leave() -> impl Syscall { - InfallibleSyscall::new(RuntimeCosts::Leave, move |_ctx: &mut CallerWrap| { - Err(ActorTerminationReason::Leave.into()) - }) + pub fn leave() -> Result<(), UndefinedTerminationReason> { + Err(ActorTerminationReason::Leave.into()) } - pub fn wait() -> impl Syscall { - InfallibleSyscall::new(RuntimeCosts::Wait, move |ctx: &mut CallerWrap| { - ctx.ext_mut().wait()?; - Err(ActorTerminationReason::Wait(None, MessageWaitedType::Wait).into()) - }) + pub fn wait(ctx: &mut CallerWrap) -> Result<(), UndefinedTerminationReason> { + ctx.ext_mut().wait()?; + Err(ActorTerminationReason::Wait(None, MessageWaitedType::Wait).into()) } - pub fn wait_for(duration: u32) -> impl Syscall { - InfallibleSyscall::new(RuntimeCosts::WaitFor, move |ctx: &mut CallerWrap| { - ctx.ext_mut().wait_for(duration)?; - Err(ActorTerminationReason::Wait(Some(duration), MessageWaitedType::WaitFor).into()) - }) + pub fn wait_for( + ctx: &mut CallerWrap, + duration: u32, + ) -> Result<(), UndefinedTerminationReason> { + ctx.ext_mut().wait_for(duration)?; + Err(ActorTerminationReason::Wait(Some(duration), MessageWaitedType::WaitFor).into()) } - pub fn wait_up_to(duration: u32) -> impl Syscall { - InfallibleSyscall::new(RuntimeCosts::WaitUpTo, move |ctx: &mut CallerWrap| { - let waited_type = if ctx.ext_mut().wait_up_to(duration)? { - MessageWaitedType::WaitUpToFull - } else { - MessageWaitedType::WaitUpTo - }; - Err(ActorTerminationReason::Wait(Some(duration), waited_type).into()) - }) + pub fn wait_up_to( + ctx: &mut CallerWrap, + duration: u32, + ) -> Result<(), UndefinedTerminationReason> { + let waited_type = if ctx.ext_mut().wait_up_to(duration)? { + MessageWaitedType::WaitUpToFull + } else { + MessageWaitedType::WaitUpTo + }; + Err(ActorTerminationReason::Wait(Some(duration), waited_type).into()) } pub fn wake(message_id_ptr: u32, delay: u32) -> impl Syscall { @@ -1350,4 +1349,28 @@ where Err(HostError) }) } + + pub fn user_break(data: u64) -> impl Syscall { + let raw_data = data.to_le_bytes(); + let break_kind = raw_data[0].try_into(); + // We do this instead of 2..6 since this gives a fixed length array + let data32 = u32::from_le_bytes([raw_data[2], raw_data[3], raw_data[4], raw_data[5]]); + let cost = break_kind.map(Into::into).unwrap_or(RuntimeCosts::Null); + InfallibleSyscall::new(cost, move |ctx: &mut CallerWrap| match break_kind { + Ok(UserBreakKind::Exit) => FuncsHandler::exit(ctx, data32), + Ok(UserBreakKind::Leave) => FuncsHandler::::leave(), + Ok(UserBreakKind::Wait) => FuncsHandler::wait(ctx), + Ok(UserBreakKind::WaitFor) => FuncsHandler::wait_for(ctx, data32), + Ok(UserBreakKind::WaitUpTo) => FuncsHandler::wait_up_to(ctx, data32), + Ok(UserBreakKind::Panic) => { + let data16 = u16::from_le_bytes([raw_data[6], raw_data[7]]); + FuncsHandler::panic(ctx, data32, data16) + } + Ok(UserBreakKind::OomPanic) => FuncsHandler::::oom_panic(), + _ => Err(ActorTerminationReason::Trap(TrapExplanation::Panic( + "Unknown user_break syscall codec".to_string().into(), + )) + .into()), + }) + } } diff --git a/core/src/costs.rs b/core/src/costs.rs index 9cbe724bfb4..7a318186ff0 100644 --- a/core/src/costs.rs +++ b/core/src/costs.rs @@ -20,6 +20,7 @@ use crate::{gas::Token, pages::PageU32Size}; use core::{fmt::Debug, marker::PhantomData}; +use gear_wasm_instrument::syscalls::UserBreakKind; use paste::paste; use scale_info::scale::{Decode, Encode}; @@ -549,3 +550,16 @@ impl RuntimeCosts { RuntimeToken { weight } } } + +impl From for RuntimeCosts { + fn from(value: UserBreakKind) -> Self { + match value { + UserBreakKind::Exit => RuntimeCosts::Exit, + UserBreakKind::Leave => RuntimeCosts::Leave, + UserBreakKind::Wait => RuntimeCosts::Wait, + UserBreakKind::WaitFor => RuntimeCosts::WaitFor, + UserBreakKind::WaitUpTo => RuntimeCosts::WaitUpTo, + _ => RuntimeCosts::Null, + } + } +} diff --git a/gcore/src/exec.rs b/gcore/src/exec.rs index a5abe82ce29..090f9e4e4eb 100644 --- a/gcore/src/exec.rs +++ b/gcore/src/exec.rs @@ -146,7 +146,13 @@ pub fn reply_deposit(message_id: MessageId, amount: u64) -> Result<()> { /// } /// ``` pub fn exit(inheritor_id: ActorId) -> ! { - unsafe { gsys::gr_exit(inheritor_id.as_ptr()) } + let mut data = [0u8; 8]; + let ptr = (inheritor_id.as_ptr() as u32).to_le_bytes(); + data[2] = ptr[0]; + data[3] = ptr[1]; + data[4] = ptr[2]; + data[5] = ptr[3]; + unsafe { gsys::gr_user_break(u64::from_le_bytes(data)) } } /// Reserve the `amount` of gas for further usage. @@ -282,7 +288,9 @@ pub fn gas_available() -> u64 { /// } /// ``` pub fn leave() -> ! { - unsafe { gsys::gr_leave() } + let mut data = [0u8; 8]; + data[0] = 1; + unsafe { gsys::gr_user_break(u64::from_le_bytes(data)) } } /// Get the total available value amount. @@ -332,7 +340,9 @@ pub fn value_available() -> u128 { /// } /// ``` pub fn wait() -> ! { - unsafe { gsys::gr_wait() } + let mut data = [0u8; 8]; + data[0] = 2; + unsafe { gsys::gr_user_break(u64::from_le_bytes(data)) } } /// Same as [`wait`], but delays handling for a specific number of blocks. @@ -341,13 +351,27 @@ pub fn wait() -> ! { /// /// Panics if it is impossible to pay the given `duration`. pub fn wait_for(duration: u32) -> ! { - unsafe { gsys::gr_wait_for(duration) } + let mut data = [0u8; 8]; + data[0] = 3; + let raw_duration = duration.to_le_bytes(); + data[2] = raw_duration[0]; + data[3] = raw_duration[1]; + data[4] = raw_duration[2]; + data[5] = raw_duration[3]; + unsafe { gsys::gr_user_break(u64::from_le_bytes(data)) } } /// Same as [`wait`], but delays handling for the maximum number of blocks that /// can be paid for and doesn't exceed the given `duration`. pub fn wait_up_to(duration: u32) -> ! { - unsafe { gsys::gr_wait_up_to(duration) } + let mut data = [0u8; 8]; + data[0] = 4; + let raw_duration = duration.to_le_bytes(); + data[2] = raw_duration[0]; + data[3] = raw_duration[1]; + data[4] = raw_duration[2]; + data[5] = raw_duration[3]; + unsafe { gsys::gr_user_break(u64::from_le_bytes(data)) } } /// Resume previously paused message handling. diff --git a/gcore/src/utils.rs b/gcore/src/utils.rs index 14e9b05cfa6..1bfc16d00cf 100644 --- a/gcore/src/utils.rs +++ b/gcore/src/utils.rs @@ -57,7 +57,17 @@ pub mod ext { /// } /// ``` pub fn panic(data: &str) -> ! { - unsafe { gsys::gr_panic(data.as_ptr(), data.len() as u32) } + let mut data = [0u8; 8]; + data[0] = 5; + let ptr = (data.as_ptr() as u32).to_le_bytes(); + data[2] = ptr[0]; + data[3] = ptr[1]; + data[4] = ptr[2]; + data[5] = ptr[3]; + let len = (data.len() as u16).to_le_bytes(); + data[6] = len[0]; + data[7] = len[1]; + unsafe { gsys::gr_user_break(u64::from_le_bytes(data)) } } /// Out of memory panic @@ -90,6 +100,8 @@ pub mod ext { /// } /// ``` pub fn oom_panic() -> ! { - unsafe { gsys::gr_oom_panic() } + let mut data = [0u8; 8]; + data[0] = 6; + unsafe { gsys::gr_user_break(u64::from_le_bytes(data)) } } } diff --git a/gsys/src/lib.rs b/gsys/src/lib.rs index 43f3ed4a1b5..b0a0369a272 100644 --- a/gsys/src/lib.rs +++ b/gsys/src/lib.rs @@ -66,6 +66,9 @@ pub type SignalCode = u32; /// Represents value type. pub type Value = u128; +/// Represents data for `gr_user_break` +pub type Data = u64; + /// Represents type defining concatenated block number with hash. 36 bytes. #[repr(C, packed)] #[derive(Default, Debug)] @@ -489,18 +492,6 @@ extern "C" { /// - `len`: `u32` length of the payload buffer. pub fn gr_debug(payload: *const SizedBufferStart, len: Length); - /// Infallible `gr_panic` control syscall. - /// - /// Stops the execution. - /// - /// Arguments type: - /// - `payload`: `const ptr` for the begging of the payload buffer. - /// - `len`: `u32` length of the payload buffer. - pub fn gr_panic(payload: *const SizedBufferStart, len: Length) -> !; - - /// Infallible `gr_oom_panic` control syscall. - pub fn gr_oom_panic() -> !; - /// Fallible `gr_reply_code` get syscall. /// /// Arguments type: @@ -513,21 +504,12 @@ extern "C" { /// - `err_code`: `mut ptr` for concatenated error code and signal code. pub fn gr_signal_code(err_code: *mut ErrorWithSignalCode); - /// Infallible `gr_exit` control syscall. - /// - /// Arguments type: - /// - `inheritor_id`: `const ptr` for program id. - pub fn gr_exit(inheritor_id: *const Hash) -> !; - /// Infallible `gr_gas_available` get syscall. /// /// Arguments type: /// - `gas`: `mut ptr` for `u64`. pub fn gr_gas_available(gas: *mut Gas); - /// Infallible `gr_leave` control syscall. - pub fn gr_leave() -> !; - /// Infallible `gr_message_id` get syscall. /// /// Arguments type: @@ -907,21 +889,6 @@ extern "C" { /// - `value`: `mut ptr` for incoming value of the message. pub fn gr_value(value: *mut Value); - /// Infallible `gr_wait_for` control syscall. - /// - /// Arguments type: - /// - `duration`: `u32` defining amount of blocks to wait. - pub fn gr_wait_for(duration: BlockNumber) -> !; - - /// Infallible `gr_wait_up_to` control syscall. - /// - /// Arguments type: - /// - `duration`: `u32` defining amount of blocks to wait. - pub fn gr_wait_up_to(duration: BlockNumber) -> !; - - /// Infallible `gr_wait` control syscall. - pub fn gr_wait() -> !; - /// Fallible `gr_wake` control syscall. /// /// Arguments type: @@ -929,4 +896,10 @@ extern "C" { /// - `delay`: `u32` amount of blocks to delay. /// - `err_mid`: `mut ptr` for error code. pub fn gr_wake(message_id: *const Hash, delay: BlockNumber, err: *mut ErrorCode); + + /// Infallible `gr_user_break` control syscall. + /// + /// Arguments type: + /// - `data`: `u64` which contains syscall data as le bytes. + pub fn gr_user_break(data: Data) -> !; } diff --git a/pallets/gear/src/benchmarking/tests/syscalls_integrity.rs b/pallets/gear/src/benchmarking/tests/syscalls_integrity.rs index 6a9009cda36..08431ddec8c 100644 --- a/pallets/gear/src/benchmarking/tests/syscalls_integrity.rs +++ b/pallets/gear/src/benchmarking/tests/syscalls_integrity.rs @@ -247,15 +247,9 @@ where SyscallName::BlockTimestamp => check_gr_block_timestamp::(), SyscallName::GasAvailable => check_gr_gas_available::(), SyscallName::ValueAvailable => check_gr_value_available::(), - SyscallName::Exit - | SyscallName::Leave - | SyscallName::Wait - | SyscallName::WaitFor - | SyscallName::WaitUpTo + SyscallName::UserBreak | SyscallName::Wake - | SyscallName::Debug - | SyscallName::Panic - | SyscallName::OomPanic => {/* tests here aren't required, read module docs for more info */}, + | SyscallName::Debug => {/* tests here aren't required, read module docs for more info */}, SyscallName::Alloc | SyscallName::Free | SyscallName::FreeRange => check_mem::(), diff --git a/utils/wasm-instrument/src/syscalls.rs b/utils/wasm-instrument/src/syscalls.rs index 7dccb4a0b54..f0418384247 100644 --- a/utils/wasm-instrument/src/syscalls.rs +++ b/utils/wasm-instrument/src/syscalls.rs @@ -83,14 +83,8 @@ pub enum SyscallName { ValueAvailable, // Changing execution path calls - Exit, - Leave, - Wait, - WaitFor, - WaitUpTo, + UserBreak, Wake, - Panic, - OomPanic, // Hard under the hood calls, serving proper program execution Alloc, @@ -119,15 +113,12 @@ impl SyscallName { SyscallName::CreateProgramWGas => "gr_create_program_wgas", SyscallName::ReplyDeposit => "gr_reply_deposit", SyscallName::Debug => "gr_debug", - SyscallName::Panic => "gr_panic", - SyscallName::OomPanic => "gr_oom_panic", - SyscallName::Exit => "gr_exit", SyscallName::Free => "free", SyscallName::FreeRange => "free_range", SyscallName::GasAvailable => "gr_gas_available", - SyscallName::Leave => "gr_leave", SyscallName::MessageId => "gr_message_id", SyscallName::SystemBreak => "gr_system_break", + SyscallName::UserBreak => "gr_user_break", SyscallName::PayProgramRent => "gr_pay_program_rent", SyscallName::ProgramId => "gr_program_id", SyscallName::Random => "gr_random", @@ -164,9 +155,6 @@ impl SyscallName { SyscallName::UnreserveGas => "gr_unreserve_gas", SyscallName::Value => "gr_value", SyscallName::ValueAvailable => "gr_value_available", - SyscallName::Wait => "gr_wait", - SyscallName::WaitFor => "gr_wait_for", - SyscallName::WaitUpTo => "gr_wait_up_to", SyscallName::Wake => "gr_wake", } } @@ -186,19 +174,13 @@ impl SyscallName { Self::Free, Self::FreeRange, Self::Debug, - Self::Panic, - Self::OomPanic, Self::BlockHeight, Self::BlockTimestamp, - Self::Exit, Self::GasAvailable, Self::PayProgramRent, Self::ProgramId, - Self::Leave, Self::ValueAvailable, - Self::Wait, - Self::WaitUpTo, - Self::WaitFor, + Self::UserBreak, Self::Wake, Self::ReplyCode, Self::SignalCode, @@ -255,19 +237,10 @@ impl SyscallName { .into(), Length, ]), - Self::Panic => SyscallSignature::gr_infallible([ - Ptr::SizedBufferStart { - length_param_idx: 1, - } - .into(), - Length, - ]), - Self::OomPanic => SyscallSignature::gr_infallible([]), Self::BlockHeight => SyscallSignature::gr_infallible([Ptr::MutBlockNumber.into()]), Self::BlockTimestamp => { SyscallSignature::gr_infallible([Ptr::MutBlockTimestamp.into()]) } - Self::Exit => SyscallSignature::gr_infallible([Ptr::Hash(HashType::ActorId).into()]), Self::GasAvailable => SyscallSignature::gr_infallible([Ptr::MutGas.into()]), Self::PayProgramRent => SyscallSignature::gr_fallible(( [Ptr::HashWithValue(HashType::ActorId).into()], @@ -276,11 +249,7 @@ impl SyscallName { Self::ProgramId => { SyscallSignature::gr_infallible([Ptr::MutHash(HashType::ActorId).into()]) } - Self::Leave => SyscallSignature::gr_infallible([]), Self::ValueAvailable => SyscallSignature::gr_infallible([Ptr::MutValue.into()]), - Self::Wait => SyscallSignature::gr_infallible([]), - Self::WaitUpTo => SyscallSignature::gr_infallible([DurationBlockNumber]), - Self::WaitFor => SyscallSignature::gr_infallible([DurationBlockNumber]), Self::Wake => SyscallSignature::gr_fallible(( [Ptr::Hash(HashType::MessageId).into(), DelayBlockNumber], ErrPtr::ErrorCode, @@ -528,6 +497,7 @@ impl SyscallName { Ptr::Hash(HashType::SubjectId).into(), Ptr::MutBlockNumberWithHash(HashType::SubjectId).into(), ]), + Self::UserBreak => SyscallSignature::gr_infallible([Data]), Self::SystemBreak => unimplemented!("Unsupported syscall signature for system_break"), } } @@ -568,6 +538,51 @@ impl SyscallName { } } +/// First byte of `gr_user_break` syscall parameter +/// +/// Used to encode the kind of breaking syscall to execute +#[derive(Debug, Clone, Copy, Ord, PartialOrd, Eq, PartialEq)] +pub enum UserBreakKind { + Exit, + Leave, + Wait, + WaitFor, + WaitUpTo, + Panic, + OomPanic, +} + +impl TryFrom for UserBreakKind { + type Error = (); + + fn try_from(value: u8) -> Result { + match value { + 0 => Ok(UserBreakKind::Exit), + 1 => Ok(UserBreakKind::Leave), + 2 => Ok(UserBreakKind::Wait), + 3 => Ok(UserBreakKind::WaitFor), + 4 => Ok(UserBreakKind::WaitUpTo), + 5 => Ok(UserBreakKind::Panic), + 6 => Ok(UserBreakKind::OomPanic), + _ => Err(()), + } + } +} + +impl From for u8 { + fn from(value: UserBreakKind) -> Self { + match value { + UserBreakKind::Exit => 0, + UserBreakKind::Leave => 1, + UserBreakKind::Wait => 2, + UserBreakKind::WaitFor => 3, + UserBreakKind::WaitUpTo => 4, + UserBreakKind::Panic => 5, + UserBreakKind::OomPanic => 6, + } + } +} + /// Syscall param type. /// /// `Ptr` variant contains additional data about the type this pointer @@ -591,6 +606,7 @@ pub enum RegularParamType { Free, // i32 page number to free FreeUpperBound, // i32 free upper bound for use with free_range Version, // i32 version number of exec settings + Data, // i64 data for user_break } /// Hash type. @@ -614,7 +630,7 @@ impl From for ValueType { ParamType::Regular(regular_ptr) => match regular_ptr { Length | Pointer(_) | Offset | DurationBlockNumber | DelayBlockNumber | Handler | Alloc | Free | FreeUpperBound | Version => ValueType::I32, - Gas => ValueType::I64, + Gas | Data => ValueType::I64, }, ParamType::Error(_) => ValueType::I32, }