use crate::{
interpreter::Interpreter,
interpreter_types::{
InterpreterTypes as ITy, Jumps, LoopControl, MemoryTr, RuntimeFlag, StackTr,
},
InstructionExecResult as Result, InstructionResult, InterpreterAction,
};
use context_interface::{cfg::GasParams, Host};
use primitives::{hints_util::cold_path, Bytes, U256};
use crate::InstructionContext as Ictx;
pub fn jump<IT: ITy, H: ?Sized>(context: Ictx<'_, H, IT>) -> Result {
popn!([target], context.interpreter);
jump_inner(context.interpreter, target)
}
pub fn jumpi<IT: ITy, H: ?Sized>(context: Ictx<'_, H, IT>) -> Result {
popn!([target, cond], context.interpreter);
if !cond.is_zero() {
jump_inner(context.interpreter, target)?;
}
Ok(())
}
#[inline(always)]
fn jump_inner<IT: ITy>(
interpreter: &mut Interpreter<IT>,
target: U256,
) -> Result<(), InstructionResult> {
let target = as_usize_saturated!(target);
if !interpreter.bytecode.is_valid_legacy_jump(target) {
cold_path();
return Err(InstructionResult::InvalidJump);
}
interpreter.bytecode.absolute_jump(target);
Ok(())
}
pub const fn jumpdest<IT: ITy, H: ?Sized>(_context: Ictx<'_, H, IT>) -> Result {
Ok(())
}
pub fn pc<IT: ITy, H: ?Sized>(context: Ictx<'_, H, IT>) -> Result {
push!(
context.interpreter,
U256::from(context.interpreter.bytecode.pc() - 1)
);
Ok(())
}
#[inline]
fn return_inner(
interpreter: &mut Interpreter<impl ITy>,
gas_params: &GasParams,
instruction_result: InstructionResult,
) -> Result<(), InstructionResult> {
popn!([offset, len], interpreter);
let len = as_usize_or_fail!(interpreter, len);
let mut output = Bytes::default();
if len != 0 {
let offset = as_usize_or_fail!(interpreter, offset);
interpreter.resize_memory(gas_params, offset, len)?;
output = interpreter.memory.slice_len(offset, len).to_vec().into()
}
interpreter
.bytecode
.set_action(InterpreterAction::new_return(
instruction_result,
output,
interpreter.gas,
));
Err(instruction_result)
}
pub fn ret<IT: ITy, H: Host + ?Sized>(context: Ictx<'_, H, IT>) -> Result {
return_inner(
context.interpreter,
context.host.gas_params(),
InstructionResult::Return,
)
}
pub fn revert<IT: ITy, H: Host + ?Sized>(context: Ictx<'_, H, IT>) -> Result {
check!(context.interpreter, BYZANTIUM);
return_inner(
context.interpreter,
context.host.gas_params(),
InstructionResult::Revert,
)
}
pub const fn stop<IT: ITy, H: ?Sized>(_context: Ictx<'_, H, IT>) -> Result {
Err(InstructionResult::Stop)
}
pub const fn invalid<IT: ITy, H: ?Sized>(_context: Ictx<'_, H, IT>) -> Result {
Err(InstructionResult::InvalidFEOpcode)
}
pub const fn unknown<IT: ITy, H: ?Sized>(_context: Ictx<'_, H, IT>) -> Result {
Err(InstructionResult::OpcodeNotFound)
}