From 7673d0c96c00f90c45117f4d24f39e2f41ddcfd8 Mon Sep 17 00:00:00 2001 From: Wei Tang Date: Wed, 22 Nov 2023 02:02:13 +0100 Subject: [PATCH] Implement PrecompileSet trait --- jsontests/src/run.rs | 19 +-- src/call_stack.rs | 237 +++++++++++++++++++++++-------- src/invoker.rs | 44 ++++-- src/lib.rs | 2 +- src/standard/invoker/mod.rs | 123 +++++++++++----- src/standard/invoker/routines.rs | 65 +++++---- 6 files changed, 355 insertions(+), 135 deletions(-) diff --git a/jsontests/src/run.rs b/jsontests/src/run.rs index a1e99b017..58c97aa4a 100644 --- a/jsontests/src/run.rs +++ b/jsontests/src/run.rs @@ -5,7 +5,7 @@ use evm::backend::in_memory::{ }; use evm::standard::{Config, Etable, Gasometer, Invoker, TransactArgs}; use evm::utils::u256_to_h256; -use evm::{Capture, GasedMachine}; +use evm::Capture; use primitive_types::U256; use std::collections::{BTreeMap, BTreeSet}; @@ -59,7 +59,7 @@ pub fn run_test(_filename: &str, _test_name: &str, test: Test, debug: bool) -> R .collect::>(); let etable = Etable::runtime(); - let invoker = Invoker::<_, Gasometer, _, _, _>::new(&config, &etable); + let invoker = Invoker::<_, Gasometer, _, (), _, _>::new(&config, &(), &etable); let args = TransactArgs::Call { caller: test.transaction.sender, address: test.transaction.to, @@ -101,13 +101,14 @@ pub fn run_test(_filename: &str, _test_name: &str, test: Test, debug: bool) -> R let _step_result = evm::HeapTransact::new(args, &invoker, &mut step_backend).and_then( |mut stepper| loop { { - let machine: &GasedMachine<_, Gasometer> = stepper.last_machine()?; - println!( - "pc: {}, opcode: {:?}, gas: 0x{:x}", - machine.machine.position(), - machine.machine.peek_opcode(), - machine.gasometer.gas(), - ); + if let Some(machine) = stepper.last_machine() { + println!( + "pc: {}, opcode: {:?}, gas: 0x{:x}", + machine.machine.position(), + machine.machine.peek_opcode(), + machine.gasometer.gas(), + ); + } } if let Err(Capture::Exit(result)) = stepper.step() { break result; diff --git a/src/call_stack.rs b/src/call_stack.rs index bf1bcef40..81f8267da 100644 --- a/src/call_stack.rs +++ b/src/call_stack.rs @@ -1,4 +1,4 @@ -use crate::{Capture, ExitError, ExitFatal, ExitResult, Invoker}; +use crate::{Capture, ExitError, ExitFatal, ExitResult, Invoker, InvokerControl}; use core::convert::Infallible; struct Substack { @@ -123,6 +123,7 @@ where .pop() .expect("checked stack is not empty above; qed"); + let machine = self.invoker.deconstruct_machine(machine); let feedback_result = self.invoker.exit_substack( exit, machine, @@ -153,7 +154,7 @@ where self.backend, self.initial_depth + self.stack.len() + 1, ) { - Capture::Exit(Ok((trap_data, sub_machine))) => { + Capture::Exit(Ok((trap_data, InvokerControl::Enter(sub_machine)))) => { self.stack.push(Substack { invoke: trap_data, machine, @@ -164,6 +165,29 @@ where machine: sub_machine, }) } + Capture::Exit(Ok(( + trap_data, + InvokerControl::DirectExit((exit, sub_machine)), + ))) => { + let feedback_result = self.invoker.exit_substack( + exit, + sub_machine, + trap_data, + &mut machine, + self.backend, + ); + + match feedback_result { + Ok(()) => Some(LastSubstack { + status: LastSubstackStatus::Running, + machine, + }), + Err(err) => Some(LastSubstack { + machine, + status: LastSubstackStatus::Exited(Capture::Exit(Err(err))), + }), + } + } Capture::Exit(Err(err)) => Some(LastSubstack { status: LastSubstackStatus::Exited(Capture::Exit(Err(err))), machine, @@ -204,7 +228,7 @@ where Capture::Exit(exit) => return Ok((exit, machine)), Capture::Trap(trap) => { match invoker.enter_substack(trap, &mut machine, backend, initial_depth + 1) { - Capture::Exit(Ok((trap_data, sub_machine))) => { + Capture::Exit(Ok((trap_data, InvokerControl::Enter(sub_machine)))) => { let (sub_result, sub_machine) = if heap_depth .map(|hd| initial_depth + 1 >= hd) .unwrap_or(false) @@ -219,6 +243,23 @@ where execute(sub_machine, initial_depth + 1, heap_depth, backend, invoker)? }; + match invoker.exit_substack( + sub_result, + invoker.deconstruct_machine(sub_machine), + trap_data, + &mut machine, + backend, + ) { + Ok(()) => { + result = invoker.run_machine(&mut machine, backend); + } + Err(err) => return Ok((Err(err), machine)), + } + } + Capture::Exit(Ok(( + trap_data, + InvokerControl::DirectExit((sub_result, sub_machine)), + ))) => { match invoker.exit_substack( sub_result, sub_machine, @@ -240,11 +281,22 @@ where } } -pub struct HeapTransact<'backend, 'invoker, H, Tr, I: Invoker> { - call_stack: CallStack<'backend, 'invoker, H, Tr, I>, - transact_invoke: I::TransactInvoke, +enum HeapTransactState<'backend, 'invoker, H, Tr, I: Invoker> { + Created { + args: I::TransactArgs, + invoker: &'invoker I, + backend: &'backend mut H, + }, + Running { + call_stack: CallStack<'backend, 'invoker, H, Tr, I>, + transact_invoke: I::TransactInvoke, + }, } +pub struct HeapTransact<'backend, 'invoker, H, Tr, I: Invoker>( + Option>, +); + impl<'backend, 'invoker, H, Tr, I> HeapTransact<'backend, 'invoker, H, Tr, I> where I: Invoker, @@ -254,13 +306,11 @@ where invoker: &'invoker I, backend: &'backend mut H, ) -> Result { - let (transact_invoke, machine) = invoker.new_transact(args, backend)?; - let call_stack = CallStack::new(machine, 0, backend, invoker); - - Ok(Self { - transact_invoke, - call_stack, - }) + Ok(Self(Some(HeapTransactState::Created { + args, + invoker, + backend, + }))) } fn step_with( @@ -269,22 +319,70 @@ where ) -> Result<(), Capture, I::Interrupt>> where FS: Fn( - &mut CallStack, + &mut CallStack<'backend, 'invoker, H, Tr, I>, ) -> Result<(), Capture, I::Interrupt>>, { - match fs(&mut self.call_stack) { - Ok(()) => Ok(()), - Err(Capture::Trap(interrupt)) => Err(Capture::Trap(interrupt)), - Err(Capture::Exit(Err(fatal))) => Err(Capture::Exit(Err(fatal.into()))), - Err(Capture::Exit(Ok((ret, machine)))) => { - Err(Capture::Exit(self.call_stack.invoker.finalize_transact( - &self.transact_invoke, - ret, - machine, - self.call_stack.backend, - ))) + let ret; + + self.0 = match self.0.take() { + Some(HeapTransactState::Running { + mut call_stack, + transact_invoke, + }) => { + ret = match fs(&mut call_stack) { + Ok(()) => Ok(()), + Err(Capture::Trap(interrupt)) => Err(Capture::Trap(interrupt)), + Err(Capture::Exit(Err(fatal))) => Err(Capture::Exit(Err(fatal.into()))), + Err(Capture::Exit(Ok((ret, machine)))) => { + let machine = call_stack.invoker.deconstruct_machine(machine); + Err(Capture::Exit(call_stack.invoker.finalize_transact( + &transact_invoke, + ret, + machine, + call_stack.backend, + ))) + } + }; + + Some(HeapTransactState::Running { + call_stack, + transact_invoke, + }) } - } + Some(HeapTransactState::Created { + args, + invoker, + backend, + }) => { + let (transact_invoke, control) = match invoker.new_transact(args, backend) { + Ok((transact_invoke, control)) => (transact_invoke, control), + Err(err) => return Err(Capture::Exit(Err(err))), + }; + + match control { + InvokerControl::Enter(machine) => { + let call_stack = CallStack::new(machine, 0, backend, invoker); + + ret = Ok(()); + Some(HeapTransactState::Running { + call_stack, + transact_invoke, + }) + } + InvokerControl::DirectExit((exit, machine)) => { + return Err(Capture::Exit(invoker.finalize_transact( + &transact_invoke, + exit, + machine, + backend, + ))); + } + } + } + None => return Err(Capture::Exit(Err(ExitFatal::AlreadyExited.into()))), + }; + + ret } pub fn step_run( @@ -309,10 +407,13 @@ where } } - pub fn last_machine(&self) -> Result<&I::Machine, ExitError> { - match &self.call_stack.last { - Some(last) => Ok(&last.machine), - None => Err(ExitFatal::AlreadyExited.into()), + pub fn last_machine(&self) -> Option<&I::Machine> { + match &self.0 { + Some(HeapTransactState::Running { call_stack, .. }) => match &call_stack.last { + Some(last) => Some(&last.machine), + None => None, + }, + _ => None, } } } @@ -322,34 +423,47 @@ where I: Invoker, { fn drop(&mut self) { - if let Some(mut last) = self.call_stack.last.take() { - loop { - if let Some(mut parent) = self.call_stack.stack.pop() { - let _ = self.call_stack.invoker.exit_substack( - ExitFatal::Unfinished.into(), - last.machine, - parent.invoke, - &mut parent.machine, - self.call_stack.backend, - ); + if let Some(state) = self.0.take() { + match state { + HeapTransactState::Running { + mut call_stack, + transact_invoke, + } => { + if let Some(mut last) = call_stack.last.take() { + loop { + if let Some(mut parent) = call_stack.stack.pop() { + let last_machine = + call_stack.invoker.deconstruct_machine(last.machine); + let _ = call_stack.invoker.exit_substack( + ExitFatal::Unfinished.into(), + last_machine, + parent.invoke, + &mut parent.machine, + call_stack.backend, + ); + + last = LastSubstack { + machine: parent.machine, + status: LastSubstackStatus::Exited(Capture::Exit( + ExitFatal::Unfinished.into(), + )), + }; + } else { + break; + } + } - last = LastSubstack { - machine: parent.machine, - status: LastSubstackStatus::Exited(Capture::Exit( + let last_machine = call_stack.invoker.deconstruct_machine(last.machine); + let _ = call_stack.invoker.finalize_transact( + &transact_invoke, ExitFatal::Unfinished.into(), - )), - }; - } else { - break; + last_machine, + call_stack.backend, + ); + } } + _ => (), } - - let _ = self.call_stack.invoker.finalize_transact( - &self.transact_invoke, - ExitFatal::Unfinished.into(), - last.machine, - self.call_stack.backend, - ); } } } @@ -363,7 +477,16 @@ pub fn transact( where I: Invoker, { - let (transact_invoke, machine) = invoker.new_transact(args, backend)?; - let (ret, machine) = execute(machine, 0, heap_depth, backend, invoker)?; - invoker.finalize_transact(&transact_invoke, ret, machine, backend) + let (transact_invoke, control) = invoker.new_transact(args, backend)?; + + match control { + InvokerControl::Enter(machine) => { + let (ret, machine) = execute(machine, 0, heap_depth, backend, invoker)?; + let machine = invoker.deconstruct_machine(machine); + invoker.finalize_transact(&transact_invoke, ret, machine, backend) + } + InvokerControl::DirectExit((exit, machine)) => { + invoker.finalize_transact(&transact_invoke, exit, machine, backend) + } + } } diff --git a/src/invoker.rs b/src/invoker.rs index c12dcb119..d73ad39d7 100644 --- a/src/invoker.rs +++ b/src/invoker.rs @@ -1,7 +1,13 @@ use crate::{Capture, ExitError, ExitResult}; +pub enum InvokerControl { + Enter(VE), + DirectExit(VD), +} + pub trait Invoker { type Machine; + type MachineDeconstruct; type Interrupt; type TransactArgs; @@ -15,35 +21,49 @@ pub trait Invoker { machine: &mut Self::Machine, handler: &mut H, ) -> Result<(), Capture>; + fn deconstruct_machine(&self, machine: Self::Machine) -> Self::MachineDeconstruct; fn new_transact( &self, args: Self::TransactArgs, handler: &mut H, - ) -> Result<(Self::TransactInvoke, Self::Machine), ExitError>; - + ) -> Result< + ( + Self::TransactInvoke, + InvokerControl, + ), + ExitError, + >; fn finalize_transact( &self, invoke: &Self::TransactInvoke, exit: ExitResult, - machine: Self::Machine, + machine: Self::MachineDeconstruct, handler: &mut H, ) -> Result; + fn enter_substack( + &self, + trap: Tr, + machine: &mut Self::Machine, + handler: &mut H, + depth: usize, + ) -> Capture< + Result< + ( + Self::SubstackInvoke, + InvokerControl, + ), + ExitError, + >, + Self::Interrupt, + >; fn exit_substack( &self, result: ExitResult, - child: Self::Machine, + child: Self::MachineDeconstruct, trap_data: Self::SubstackInvoke, parent: &mut Self::Machine, handler: &mut H, ) -> Result<(), ExitError>; - - fn enter_substack( - &self, - trap: Tr, - machine: &mut Self::Machine, - handler: &mut H, - depth: usize, - ) -> Capture, Self::Interrupt>; } diff --git a/src/lib.rs b/src/lib.rs index acdefee0a..0e3f07c5c 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -18,7 +18,7 @@ pub use evm_interpreter::*; pub use crate::backend::TransactionalBackend; pub use crate::call_stack::{transact, HeapTransact}; pub use crate::gasometer::{Gas, GasedMachine, Gasometer}; -pub use crate::invoker::Invoker; +pub use crate::invoker::{Invoker, InvokerControl}; #[derive(Clone, Debug, Copy)] pub enum MergeStrategy { diff --git a/src/standard/invoker/mod.rs b/src/standard/invoker/mod.rs index ba559719f..0fe347f84 100644 --- a/src/standard/invoker/mod.rs +++ b/src/standard/invoker/mod.rs @@ -4,9 +4,9 @@ use super::{Config, MergeableRuntimeState, TransactGasometer}; use crate::call_create::{CallCreateTrapData, CallTrapData, CreateScheme, CreateTrapData}; use crate::{ Capture, Context, Control, Etable, ExitError, ExitException, ExitResult, ExitSucceed, - GasedMachine, Gasometer as GasometerT, Invoker as InvokerT, Machine, MergeStrategy, Opcode, - RuntimeBackend, RuntimeEnvironment, RuntimeState, TransactionContext, TransactionalBackend, - Transfer, + GasedMachine, Gasometer as GasometerT, Invoker as InvokerT, InvokerControl, Machine, + MergeStrategy, Opcode, RuntimeBackend, RuntimeEnvironment, RuntimeState, TransactionContext, + TransactionalBackend, Transfer, }; use alloc::rc::Rc; use core::cmp::min; @@ -100,31 +100,62 @@ impl TransactArgs { } } -pub struct Invoker<'config, 'etable, S, G, H, Tr, F> { +pub trait PrecompileSet { + fn execute( + &self, + state: &mut S, + gasometer: &mut G, + handler: &mut H, + ) -> Option<(ExitResult, Vec)>; +} + +impl PrecompileSet for () { + fn execute( + &self, + _state: &mut S, + _gasometer: &mut G, + _handler: &mut H, + ) -> Option<(ExitResult, Vec)> { + None + } +} + +pub struct Invoker<'config, 'precompile, 'etable, S, G, H, Pre, Tr, F> { config: &'config Config, etable: &'etable Etable, + precompile: &'precompile Pre, _marker: PhantomData, } -impl<'config, 'etable, S, G, H, Tr, F> Invoker<'config, 'etable, S, G, H, Tr, F> { - pub fn new(config: &'config Config, etable: &'etable Etable) -> Self { +impl<'config, 'precompile, 'etable, S, G, H, Pre, Tr, F> + Invoker<'config, 'precompile, 'etable, S, G, H, Pre, Tr, F> +{ + pub fn new( + config: &'config Config, + precompile: &'precompile Pre, + etable: &'etable Etable, + ) -> Self { Self { config, etable, + precompile, _marker: PhantomData, } } } -impl<'config, 'etable, S, G, H, Tr, F> InvokerT for Invoker<'config, 'etable, S, G, H, Tr, F> +impl<'config, 'precompile, 'etable, S, G, H, Pre, Tr, F> InvokerT + for Invoker<'config, 'precompile, 'etable, S, G, H, Pre, Tr, F> where S: MergeableRuntimeState, G: GasometerT + TransactGasometer<'config, S>, H: RuntimeEnvironment + RuntimeBackend + TransactionalBackend, + Pre: PrecompileSet, Tr: IntoCallCreateTrap, F: Fn(&mut Machine, &mut H, Opcode, usize) -> Control, { type Machine = GasedMachine; + type MachineDeconstruct = (S, G, Vec); type Interrupt = Tr::Interrupt; type TransactArgs = TransactArgs; type TransactInvoke = TransactInvoke; @@ -147,11 +178,25 @@ where machine.step(handler, self.etable) } + fn deconstruct_machine(&self, machine: GasedMachine) -> (S, G, Vec) { + ( + machine.machine.state, + machine.gasometer, + machine.machine.retval, + ) + } + fn new_transact( &self, args: TransactArgs, handler: &mut H, - ) -> Result<(TransactInvoke, GasedMachine), ExitError> { + ) -> Result< + ( + TransactInvoke, + InvokerControl, (ExitResult, Self::MachineDeconstruct)>, + ), + ExitError, + > { let caller = args.caller(); let gas_price = args.gas_price(); @@ -211,7 +256,7 @@ where value, }; - let work = || -> Result<(TransactInvoke, GasedMachine), ExitError> { + let work = || -> Result<(TransactInvoke, _), ExitError> { match args { TransactArgs::Call { caller, @@ -235,6 +280,7 @@ where let machine = routines::make_enter_call_machine( self.config, + self.precompile, code, data, false, // is_static @@ -270,7 +316,7 @@ where let gasometer = G::new_transact_create(gas_limit, &init_code, &access_list, self.config)?; - let machine = routines::make_enter_create_machine( + let machine = InvokerControl::Enter(routines::make_enter_create_machine( self.config, caller, init_code, @@ -284,7 +330,7 @@ where }), gasometer, handler, - )?; + )?); Ok((invoke, machine)) } @@ -304,21 +350,21 @@ where &self, invoke: &TransactInvoke, result: ExitResult, - mut machine: GasedMachine, + (_substate, mut submeter, retval): (S, G, Vec), handler: &mut H, ) -> Result { - let left_gas = machine.gasometer.effective_gas(); + let left_gas = submeter.effective_gas(); let work = || -> Result { if result.is_ok() { if let Some(address) = invoke.create_address { - let retbuf = machine.machine.retval; + let retbuf = retval; routines::deploy_create_code( self.config, address, &retbuf, - &mut machine.gasometer, + &mut submeter, handler, )?; } @@ -357,7 +403,16 @@ where machine: &mut GasedMachine, handler: &mut H, depth: usize, - ) -> Capture), ExitError>, Tr::Interrupt> { + ) -> Capture< + Result< + ( + SubstackInvoke, + InvokerControl, (ExitResult, Self::MachineDeconstruct)>, + ), + ExitError, + >, + Tr::Interrupt, + > { fn l64(gas: U256) -> U256 { gas - gas / U256::from(64) } @@ -417,6 +472,7 @@ where Capture::Exit(routines::enter_call_substack( self.config, + self.precompile, code, call_trap_data, is_static, @@ -439,15 +495,18 @@ where gas: U256::from(gas_limit), }); - Capture::Exit(routines::enter_create_substack( - self.config, - code, - create_trap_data, - is_static, - substate, - submeter, - handler, - )) + Capture::Exit( + routines::enter_create_substack( + self.config, + code, + create_trap_data, + is_static, + substate, + submeter, + handler, + ) + .map(|(invoke, machine)| (invoke, InvokerControl::Enter(machine))), + ) } } } @@ -455,7 +514,7 @@ where fn exit_substack( &self, result: ExitResult, - child: GasedMachine, + (substate, submeter, retval): (S, G, Vec), trap_data: SubstackInvoke, parent: &mut GasedMachine, handler: &mut H, @@ -468,10 +527,10 @@ where match trap_data { SubstackInvoke::Create { address, trap } => { - let retbuf = child.machine.retval; - parent.machine.state.merge(child.machine.state, strategy); + let retbuf = retval; + parent.machine.state.merge(substate, strategy); - let mut child_gasometer = child.gasometer; + let mut child_gasometer = submeter; let result = result.and_then(|_| { routines::deploy_create_code( self.config, @@ -492,12 +551,12 @@ where Ok(()) } SubstackInvoke::Call { trap } => { - parent.machine.state.merge(child.machine.state, strategy); + parent.machine.state.merge(substate, strategy); - let retbuf = child.machine.retval; + let retbuf = retval; handler.pop_substate(strategy); - GasometerT::::merge(&mut parent.gasometer, child.gasometer, strategy); + GasometerT::::merge(&mut parent.gasometer, submeter, strategy); trap.feedback(result, retbuf, &mut parent.machine)?; diff --git a/src/standard/invoker/routines.rs b/src/standard/invoker/routines.rs index 7f87f5057..400cc6ed4 100644 --- a/src/standard/invoker/routines.rs +++ b/src/standard/invoker/routines.rs @@ -1,26 +1,29 @@ -use super::{CallTrapData, CreateTrapData, SubstackInvoke}; +use super::{CallTrapData, CreateTrapData, PrecompileSet, SubstackInvoke}; use crate::standard::{Config, MergeableRuntimeState}; use crate::{ - ExitError, ExitException, GasedMachine, Gasometer as GasometerT, Machine, MergeStrategy, - Opcode, RuntimeBackend, RuntimeEnvironment, TransactionalBackend, Transfer, + ExitError, ExitException, ExitResult, GasedMachine, Gasometer as GasometerT, InvokerControl, + Machine, MergeStrategy, Opcode, RuntimeBackend, RuntimeEnvironment, TransactionalBackend, + Transfer, }; use alloc::rc::Rc; use primitive_types::{H160, U256}; -pub fn make_enter_call_machine<'config, S, G, H>( +pub fn make_enter_call_machine<'config, 'precompile, S, G, H, Pre>( config: &'config Config, + precompile: &'precompile Pre, code: Vec, input: Vec, is_static: bool, transfer: Option, - state: S, - gasometer: G, + mut state: S, + mut gasometer: G, handler: &mut H, -) -> Result, ExitError> +) -> Result, (ExitResult, (S, G, Vec))>, ExitError> where S: MergeableRuntimeState, G: GasometerT, H: RuntimeEnvironment + RuntimeBackend + TransactionalBackend, + Pre: PrecompileSet, { handler.mark_hot(state.as_ref().context.address, None); @@ -28,21 +31,26 @@ where handler.transfer(transfer)?; } - // TODO: precompile contracts. - - let machine = Machine::::new( - Rc::new(code), - Rc::new(input.clone()), - config.stack_limit, - config.memory_limit, - state, - ); + if let Some((exit, retval)) = precompile.execute(&mut state, &mut gasometer, handler) { + Ok(InvokerControl::DirectExit(( + exit, + (state, gasometer, retval), + ))) + } else { + let machine = Machine::::new( + Rc::new(code), + Rc::new(input.clone()), + config.stack_limit, + config.memory_limit, + state, + ); - Ok(GasedMachine { - machine, - gasometer, - is_static, - }) + Ok(InvokerControl::Enter(GasedMachine { + machine, + gasometer, + is_static, + })) + } } pub fn make_enter_create_machine<'config, S, G, H>( @@ -98,25 +106,34 @@ where }) } -pub fn enter_call_substack<'config, S, G, H>( +pub fn enter_call_substack<'config, 'precompile, S, G, H, Pre>( config: &'config Config, + precompile: &'precompile Pre, code: Vec, trap_data: CallTrapData, is_static: bool, state: S, gasometer: G, handler: &mut H, -) -> Result<(SubstackInvoke, GasedMachine), ExitError> +) -> Result< + ( + SubstackInvoke, + InvokerControl, (ExitResult, (S, G, Vec))>, + ), + ExitError, +> where S: MergeableRuntimeState, G: GasometerT, H: RuntimeEnvironment + RuntimeBackend + TransactionalBackend, + Pre: PrecompileSet, { handler.push_substate(); - let work = || -> Result<(SubstackInvoke, GasedMachine), ExitError> { + let work = || -> Result<(SubstackInvoke, _), ExitError> { let machine = make_enter_call_machine( config, + precompile, code, trap_data.input.clone(), is_static,