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