fuel_vm/interpreter/executors/
instruction.rs

1use crate::{
2    error::{
3        InterpreterError,
4        IoResult,
5        RuntimeError,
6    },
7    interpreter::{
8        EcalHandler,
9        ExecutableTransaction,
10        Interpreter,
11        Memory,
12    },
13    state::ExecuteState,
14    storage::InterpreterStorage,
15    verification::Verifier,
16};
17
18use fuel_asm::{
19    Instruction,
20    PanicInstruction,
21    PanicReason,
22    RawInstruction,
23    RegId,
24};
25
26impl<M, S, Tx, Ecal, V> Interpreter<M, S, Tx, Ecal, V>
27where
28    M: Memory,
29    S: InterpreterStorage,
30    Tx: ExecutableTransaction,
31    Ecal: EcalHandler,
32    V: Verifier,
33{
34    /// Execute the current instruction located in `$m[$pc]`.
35    pub fn execute<const PREDICATE: bool>(
36        &mut self,
37    ) -> Result<ExecuteState, InterpreterError<S::DataError>> {
38        let raw_instruction = self.fetch_instruction()?;
39        self.instruction_per_inner::<PREDICATE>(raw_instruction)
40    }
41
42    /// Reads the current instruction located in `$m[$pc]`,
43    /// performing memory boundary checks.
44    fn fetch_instruction(&self) -> Result<[u8; 4], InterpreterError<S::DataError>> {
45        let pc = self.registers[RegId::PC];
46
47        let raw_instruction: [u8; 4] =
48            self.memory().read_bytes(pc).map_err(|reason| {
49                InterpreterError::PanicInstruction(PanicInstruction::error(
50                    reason,
51                    0, // The value is meaningless since fetch was out-of-bounds
52                ))
53            })?;
54        if pc < self.registers[RegId::IS] || pc >= self.registers[RegId::SSP] {
55            return Err(InterpreterError::PanicInstruction(PanicInstruction::error(
56                PanicReason::MemoryNotExecutable,
57                RawInstruction::from_be_bytes(raw_instruction),
58            )))
59        }
60        Ok(raw_instruction)
61    }
62
63    /// Execute a provided instruction
64    pub fn instruction<R, const PREDICATE: bool>(
65        &mut self,
66        raw: R,
67    ) -> Result<ExecuteState, InterpreterError<S::DataError>>
68    where
69        R: Into<RawInstruction> + Copy,
70    {
71        let raw = raw.into();
72        let raw = raw.to_be_bytes();
73
74        self.instruction_per_inner::<PREDICATE>(raw)
75    }
76
77    fn instruction_per_inner<const PREDICATE: bool>(
78        &mut self,
79        raw: [u8; 4],
80    ) -> Result<ExecuteState, InterpreterError<S::DataError>> {
81        if self.debugger.is_active() {
82            let debug = self.eval_debugger_state();
83            if !debug.should_continue() {
84                return Ok(debug.into())
85            }
86        }
87
88        self.instruction_inner::<PREDICATE>(raw).map_err(|e| {
89            InterpreterError::from_runtime(e, RawInstruction::from_be_bytes(raw))
90        })
91    }
92
93    fn instruction_inner<const PREDICATE: bool>(
94        &mut self,
95        raw: [u8; 4],
96    ) -> IoResult<ExecuteState, S::DataError> {
97        let instruction = Instruction::try_from(raw)
98            .map_err(|_| RuntimeError::from(PanicReason::InvalidInstruction))?;
99
100        if PREDICATE {
101            // TODO additional branch that might be optimized after
102            // https://github.com/FuelLabs/fuel-asm/issues/68
103            if !instruction.opcode().is_predicate_allowed() {
104                return Err(PanicReason::ContractInstructionNotAllowed.into())
105            }
106        }
107
108        instruction.execute(self)
109    }
110}
111
112pub trait Execute<M, S, Tx, Ecal, V>
113where
114    M: Memory,
115    S: InterpreterStorage,
116    Tx: ExecutableTransaction,
117    Ecal: EcalHandler,
118    V: Verifier,
119{
120    fn execute(
121        self,
122        interpreter: &mut Interpreter<M, S, Tx, Ecal, V>,
123    ) -> IoResult<ExecuteState, S::DataError>;
124}
125
126impl<M, S, Tx, Ecal, V> Execute<M, S, Tx, Ecal, V> for Instruction
127where
128    M: Memory,
129    S: InterpreterStorage,
130    Tx: ExecutableTransaction,
131    Ecal: EcalHandler,
132    V: Verifier,
133{
134    fn execute(
135        self,
136        interpreter: &mut Interpreter<M, S, Tx, Ecal, V>,
137    ) -> IoResult<ExecuteState, S::DataError> {
138        match self {
139            Instruction::ADD(op) => op.execute(interpreter),
140            Instruction::AND(op) => op.execute(interpreter),
141            Instruction::DIV(op) => op.execute(interpreter),
142            Instruction::EQ(op) => op.execute(interpreter),
143            Instruction::EXP(op) => op.execute(interpreter),
144            Instruction::GT(op) => op.execute(interpreter),
145            Instruction::LT(op) => op.execute(interpreter),
146            Instruction::MLOG(op) => op.execute(interpreter),
147            Instruction::MROO(op) => op.execute(interpreter),
148            Instruction::MOD(op) => op.execute(interpreter),
149            Instruction::MOVE(op) => op.execute(interpreter),
150            Instruction::MUL(op) => op.execute(interpreter),
151            Instruction::NOT(op) => op.execute(interpreter),
152            Instruction::OR(op) => op.execute(interpreter),
153            Instruction::SLL(op) => op.execute(interpreter),
154            Instruction::SRL(op) => op.execute(interpreter),
155            Instruction::SUB(op) => op.execute(interpreter),
156            Instruction::XOR(op) => op.execute(interpreter),
157            Instruction::MLDV(op) => op.execute(interpreter),
158            Instruction::RET(op) => op.execute(interpreter),
159            Instruction::RETD(op) => op.execute(interpreter),
160            Instruction::ALOC(op) => op.execute(interpreter),
161            Instruction::MCL(op) => op.execute(interpreter),
162            Instruction::MCP(op) => op.execute(interpreter),
163            Instruction::MEQ(op) => op.execute(interpreter),
164            Instruction::BHSH(op) => op.execute(interpreter),
165            Instruction::BHEI(op) => op.execute(interpreter),
166            Instruction::BURN(op) => op.execute(interpreter),
167            Instruction::CALL(op) => op.execute(interpreter),
168            Instruction::CCP(op) => op.execute(interpreter),
169            Instruction::CROO(op) => op.execute(interpreter),
170            Instruction::CSIZ(op) => op.execute(interpreter),
171            Instruction::CB(op) => op.execute(interpreter),
172            Instruction::LDC(op) => op.execute(interpreter),
173            Instruction::LOG(op) => op.execute(interpreter),
174            Instruction::LOGD(op) => op.execute(interpreter),
175            Instruction::MINT(op) => op.execute(interpreter),
176            Instruction::RVRT(op) => op.execute(interpreter),
177            Instruction::SCWQ(op) => op.execute(interpreter),
178            Instruction::SRW(op) => op.execute(interpreter),
179            Instruction::SRWQ(op) => op.execute(interpreter),
180            Instruction::SWW(op) => op.execute(interpreter),
181            Instruction::SWWQ(op) => op.execute(interpreter),
182            Instruction::TR(op) => op.execute(interpreter),
183            Instruction::TRO(op) => op.execute(interpreter),
184            Instruction::ECK1(op) => op.execute(interpreter),
185            Instruction::ECR1(op) => op.execute(interpreter),
186            Instruction::ED19(op) => op.execute(interpreter),
187            Instruction::K256(op) => op.execute(interpreter),
188            Instruction::S256(op) => op.execute(interpreter),
189            Instruction::TIME(op) => op.execute(interpreter),
190            Instruction::NOOP(op) => op.execute(interpreter),
191            Instruction::FLAG(op) => op.execute(interpreter),
192            Instruction::BAL(op) => op.execute(interpreter),
193            Instruction::JMP(op) => op.execute(interpreter),
194            Instruction::JNE(op) => op.execute(interpreter),
195            Instruction::SMO(op) => op.execute(interpreter),
196            Instruction::ADDI(op) => op.execute(interpreter),
197            Instruction::ANDI(op) => op.execute(interpreter),
198            Instruction::DIVI(op) => op.execute(interpreter),
199            Instruction::EXPI(op) => op.execute(interpreter),
200            Instruction::MODI(op) => op.execute(interpreter),
201            Instruction::MULI(op) => op.execute(interpreter),
202            Instruction::ORI(op) => op.execute(interpreter),
203            Instruction::SLLI(op) => op.execute(interpreter),
204            Instruction::SRLI(op) => op.execute(interpreter),
205            Instruction::SUBI(op) => op.execute(interpreter),
206            Instruction::XORI(op) => op.execute(interpreter),
207            Instruction::JNEI(op) => op.execute(interpreter),
208            Instruction::LB(op) => op.execute(interpreter),
209            Instruction::LW(op) => op.execute(interpreter),
210            Instruction::SB(op) => op.execute(interpreter),
211            Instruction::SW(op) => op.execute(interpreter),
212            Instruction::MCPI(op) => op.execute(interpreter),
213            Instruction::GTF(op) => op.execute(interpreter),
214            Instruction::MCLI(op) => op.execute(interpreter),
215            Instruction::GM(op) => op.execute(interpreter),
216            Instruction::MOVI(op) => op.execute(interpreter),
217            Instruction::JNZI(op) => op.execute(interpreter),
218            Instruction::JMPF(op) => op.execute(interpreter),
219            Instruction::JMPB(op) => op.execute(interpreter),
220            Instruction::JNZF(op) => op.execute(interpreter),
221            Instruction::JNZB(op) => op.execute(interpreter),
222            Instruction::JNEF(op) => op.execute(interpreter),
223            Instruction::JNEB(op) => op.execute(interpreter),
224            Instruction::JI(op) => op.execute(interpreter),
225            Instruction::CFEI(op) => op.execute(interpreter),
226            Instruction::CFSI(op) => op.execute(interpreter),
227            Instruction::CFE(op) => op.execute(interpreter),
228            Instruction::CFS(op) => op.execute(interpreter),
229            Instruction::PSHL(op) => op.execute(interpreter),
230            Instruction::PSHH(op) => op.execute(interpreter),
231            Instruction::POPL(op) => op.execute(interpreter),
232            Instruction::POPH(op) => op.execute(interpreter),
233            Instruction::WDCM(op) => op.execute(interpreter),
234            Instruction::WQCM(op) => op.execute(interpreter),
235            Instruction::WDOP(op) => op.execute(interpreter),
236            Instruction::WQOP(op) => op.execute(interpreter),
237            Instruction::WDML(op) => op.execute(interpreter),
238            Instruction::WQML(op) => op.execute(interpreter),
239            Instruction::WDDV(op) => op.execute(interpreter),
240            Instruction::WQDV(op) => op.execute(interpreter),
241            Instruction::WDMD(op) => op.execute(interpreter),
242            Instruction::WQMD(op) => op.execute(interpreter),
243            Instruction::WDAM(op) => op.execute(interpreter),
244            Instruction::WQAM(op) => op.execute(interpreter),
245            Instruction::WDMM(op) => op.execute(interpreter),
246            Instruction::WQMM(op) => op.execute(interpreter),
247            Instruction::ECAL(op) => op.execute(interpreter),
248            Instruction::BSIZ(op) => op.execute(interpreter),
249            Instruction::BLDD(op) => op.execute(interpreter),
250            Instruction::ECOP(op) => op.execute(interpreter),
251            Instruction::EPAR(op) => op.execute(interpreter),
252        }
253    }
254}
255
256/// Computes nth root of target, rounding down to nearest integer.
257/// This function uses the floating point operation to get an approximate solution,
258/// but corrects the result using exponentation to check for inaccuracy.
259pub fn checked_nth_root(target: u64, nth_root: u64) -> Option<u64> {
260    if nth_root == 0 {
261        // Zeroth root is not defined
262        return None
263    }
264
265    if nth_root == 1 || target <= 1 {
266        // Corner cases
267        return Some(target)
268    }
269
270    if nth_root >= target || nth_root > 64 {
271        // For any root >= target, result always 1
272        // For any n>1, n**64 can never fit into u64
273        return Some(1)
274    }
275
276    let nth_root = u32::try_from(nth_root).expect("Never loses bits, checked above");
277
278    // Use floating point operation to get an approximation for the starting point.
279    // This is at most off by one in either direction.
280
281    #[cfg(feature = "std")]
282    let powf = f64::powf;
283    #[cfg(not(feature = "std"))]
284    let powf = libm::pow;
285
286    #[allow(clippy::cast_possible_truncation, clippy::cast_sign_loss)]
287    let guess = powf(target as f64, (nth_root as f64).recip()) as u64;
288
289    debug_assert!(guess != 0, "This should never occur for {{target, n}} > 1");
290
291    // Check if a value raised to nth_power is below the target value, handling overflow
292    // correctly
293    let is_nth_power_below_target = |v: u64| match v.checked_pow(nth_root) {
294        Some(pow) => target < pow,
295        None => true, // v**nth_root >= 2**64 and target < 2**64
296    };
297
298    // Compute guess**n to check if the guess is too large.
299    // Note that if guess == 1, then g1 == 1 as well, meaning that we will not return
300    // here.
301    if is_nth_power_below_target(guess) {
302        return Some(guess.saturating_sub(1))
303    }
304
305    // Check if the initial guess was correct
306    let guess_plus_one = guess.checked_add(1).expect(
307        "Guess cannot be u64::MAX, as we have taken a root > 2 of a value to get it",
308    );
309    if is_nth_power_below_target(guess_plus_one) {
310        return Some(guess)
311    }
312
313    // If not, then the value above must be the correct one.
314    Some(guess_plus_one)
315}
316
317#[cfg(test)]
318mod tests;