Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 9 additions & 9 deletions fuel-vm/benches/execution.rs
Original file line number Diff line number Diff line change
Expand Up @@ -58,15 +58,15 @@ fn execution(c: &mut Criterion) {
group_execution.bench_function("Infinite `meq` loop", |b| {
b.iter(|| {
for _ in 0..1000 {
let _ = interpreter.execute().unwrap();
let _ = interpreter.execute::<false>().unwrap();
}
})
});

group_execution.bench_function("Infinite `meq` loop black box", |b| {
b.iter(|| {
for _ in 0..1000 {
black_box(interpreter.execute()).unwrap();
black_box(interpreter.execute::<false>()).unwrap();
}
})
});
Expand All @@ -75,7 +75,7 @@ fn execution(c: &mut Criterion) {
b.iter(|| {
for _ in 0..1000 {
unsafe {
let dummy = interpreter.execute().unwrap();
let dummy = interpreter.execute::<false>().unwrap();
std::ptr::read_volatile(&dummy)
};
}
Expand Down Expand Up @@ -103,15 +103,15 @@ fn execution(c: &mut Criterion) {
group_execution.bench_function("Infinite `add` loop", |b| {
b.iter(|| {
for _ in 0..1000 {
let _ = interpreter.execute().unwrap();
let _ = interpreter.execute::<false>().unwrap();
}
})
});

group_execution.bench_function("Infinite `add` loop black box", |b| {
b.iter(|| {
for _ in 0..1000 {
black_box(interpreter.execute()).unwrap();
black_box(interpreter.execute::<false>()).unwrap();
}
})
});
Expand All @@ -120,7 +120,7 @@ fn execution(c: &mut Criterion) {
b.iter(|| {
for _ in 0..1000 {
unsafe {
let dummy = interpreter.execute().unwrap();
let dummy = interpreter.execute::<false>().unwrap();
std::ptr::read_volatile(&dummy)
};
}
Expand Down Expand Up @@ -148,15 +148,15 @@ fn execution(c: &mut Criterion) {
group_execution.bench_function("Infinite `not` loop", |b| {
b.iter(|| {
for _ in 0..1000 {
let _ = interpreter.execute().unwrap();
let _ = interpreter.execute::<false>().unwrap();
}
})
});

group_execution.bench_function("Infinite `not` loop black box", |b| {
b.iter(|| {
for _ in 0..1000 {
black_box(interpreter.execute()).unwrap();
black_box(interpreter.execute::<false>()).unwrap();
}
})
});
Expand All @@ -165,7 +165,7 @@ fn execution(c: &mut Criterion) {
b.iter(|| {
for _ in 0..1000 {
unsafe {
let dummy = interpreter.execute().unwrap();
let dummy = interpreter.execute::<false>().unwrap();
std::ptr::read_volatile(&dummy)
};
}
Expand Down
10 changes: 7 additions & 3 deletions fuel-vm/src/interpreter/diff/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,9 @@ fn reset_vm_state() {
let desired = Interpreter::<_, _, Script>::with_memory_storage();
let mut latest = Interpreter::<_, _, Script>::with_memory_storage();
latest.set_gas(1_000_000);
latest.instruction(op::addi(0x10, 0x11, 1)).unwrap();
latest
.instruction::<_, false>(op::addi(0x10, 0x11, 1))
.unwrap();
let diff: Diff<InitialVmState> = latest.rollback_to(&desired).into();
assert_ne!(desired, latest);
latest.reset_vm_state(&diff);
Expand Down Expand Up @@ -75,7 +77,9 @@ fn record_and_invert_storage() {
)
.unwrap();
latest.set_gas(1_000_000);
latest.instruction(op::addi(0x10, 0x11, 1)).unwrap();
latest
.instruction::<_, false>(op::addi(0x10, 0x11, 1))
.unwrap();

let storage_diff: Diff<InitialVmState> = latest.storage_diff().into();
let mut diff: Diff<InitialVmState> = latest.rollback_to(&desired).into();
Expand All @@ -95,7 +99,7 @@ fn record_and_invert_storage() {
)
.unwrap();
d.set_gas(1_000_000);
d.instruction(op::addi(0x10, 0x11, 1)).unwrap();
d.instruction::<_, false>(op::addi(0x10, 0x11, 1)).unwrap();

assert_ne!(c, d);
d.reset_vm_state(&diff);
Expand Down
26 changes: 15 additions & 11 deletions fuel-vm/src/interpreter/executors/instruction.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,9 +32,11 @@ where
V: Verifier,
{
/// Execute the current instruction located in `$m[$pc]`.
pub fn execute(&mut self) -> Result<ExecuteState, InterpreterError<S::DataError>> {
pub fn execute<const PREDICATE: bool>(
&mut self,
) -> Result<ExecuteState, InterpreterError<S::DataError>> {
let raw_instruction = self.fetch_instruction()?;
self.instruction_per_inner(raw_instruction)
self.instruction_per_inner::<PREDICATE>(raw_instruction)
}

/// Reads the current instruction located in `$m[$pc]`,
Expand All @@ -59,17 +61,17 @@ where
}

/// Execute a provided instruction
pub fn instruction<R: Into<RawInstruction> + Copy>(
pub fn instruction<R: Into<RawInstruction> + Copy, const PREDICATE: bool>(
&mut self,
raw: R,
) -> Result<ExecuteState, InterpreterError<S::DataError>> {
let raw = raw.into();
let raw = raw.to_be_bytes();

self.instruction_per_inner(raw)
self.instruction_per_inner::<PREDICATE>(raw)
}

fn instruction_per_inner(
fn instruction_per_inner<const PREDICATE: bool>(
&mut self,
raw: [u8; 4],
) -> Result<ExecuteState, InterpreterError<S::DataError>> {
Expand All @@ -80,22 +82,24 @@ where
}
}

self.instruction_inner(raw).map_err(|e| {
self.instruction_inner::<PREDICATE>(raw).map_err(|e| {
InterpreterError::from_runtime(e, RawInstruction::from_be_bytes(raw))
})
}

fn instruction_inner(
fn instruction_inner<const PREDICATE: bool>(
&mut self,
raw: [u8; 4],
) -> IoResult<ExecuteState, S::DataError> {
let instruction = Instruction::try_from(raw)
.map_err(|_| RuntimeError::from(PanicReason::InvalidInstruction))?;

// TODO additional branch that might be optimized after
// https://github.com/FuelLabs/fuel-asm/issues/68
if self.is_predicate() && !instruction.opcode().is_predicate_allowed() {
return Err(PanicReason::ContractInstructionNotAllowed.into())
if PREDICATE {
// TODO additional branch that might be optimized after
// https://github.com/FuelLabs/fuel-asm/issues/68
if !instruction.opcode().is_predicate_allowed() {
return Err(PanicReason::ContractInstructionNotAllowed.into())
}
}

instruction.execute(self)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ fn cant_write_to_reserved_registers(raw_random_instruction: u32) -> TestResult {
.expect("failed dynamic checks");

vm.init_script(tx).expect("Failed to init VM");
let res = vm.instruction(raw_random_instruction);
let res = vm.instruction::<_, false>(raw_random_instruction);

if writes_to_ra(opcode) || writes_to_rb(opcode) {
// if this opcode writes to $rA or $rB, expect an error since we're attempting to
Expand Down
2 changes: 1 addition & 1 deletion fuel-vm/src/interpreter/executors/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -981,7 +981,7 @@ where
// Check whether the instruction will be executed in a call context
let in_call = !self.frames.is_empty();

match self.execute() {
match self.execute::<true>() {
// Proceeding with the execution normally
Ok(ExecuteState::Proceed) => continue,
// Debugger events are returned directly to the caller
Expand Down
2 changes: 1 addition & 1 deletion fuel-vm/src/interpreter/executors/predicate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ where
&mut self,
) -> Result<ProgramState, PredicateVerificationFailed> {
loop {
match self.execute()? {
match self.execute::<false>()? {
ExecuteState::Return(r) => {
if r == 1 {
return Ok(ProgramState::Return(r))
Expand Down
4 changes: 0 additions & 4 deletions fuel-vm/src/interpreter/internal.rs
Original file line number Diff line number Diff line change
Expand Up @@ -111,10 +111,6 @@ where
&self.context
}

pub(crate) const fn is_predicate(&self) -> bool {
self.context.is_predicate()
}

pub(crate) fn internal_contract(&self) -> Result<ContractId, PanicReason> {
internal_contract(&self.context, self.registers.fp(), self.memory.as_ref())
}
Expand Down
39 changes: 23 additions & 16 deletions fuel-vm/src/interpreter/memory/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -48,45 +48,51 @@ fn memcopy() {
let alloc = 1024;

// r[0x10] := 1024
vm.instruction(op::addi(0x10, RegId::ZERO, alloc)).unwrap();
vm.instruction(op::aloc(0x10)).unwrap();
vm.instruction::<_, false>(op::addi(0x10, RegId::ZERO, alloc))
.unwrap();
vm.instruction::<_, false>(op::aloc(0x10)).unwrap();

// r[0x20] := 128
vm.instruction(op::addi(0x20, RegId::ZERO, 128)).unwrap();
vm.instruction::<_, false>(op::addi(0x20, RegId::ZERO, 128))
.unwrap();

for i in 0..alloc {
vm.instruction(op::addi(0x21, RegId::ZERO, i)).unwrap();
vm.instruction(op::sb(RegId::HP, 0x21, i as Immediate12))
vm.instruction::<_, false>(op::addi(0x21, RegId::ZERO, i))
.unwrap();
vm.instruction::<_, false>(op::sb(RegId::HP, 0x21, i as Immediate12))
.unwrap();
}

// r[0x23] := m[$hp, 0x20] == m[$zero, 0x20]
vm.instruction(op::meq(0x23, RegId::HP, RegId::ZERO, 0x20))
vm.instruction::<_, false>(op::meq(0x23, RegId::HP, RegId::ZERO, 0x20))
.unwrap();

assert_eq!(0, vm.registers()[0x23]);

// r[0x12] := $hp + r[0x20]
vm.instruction(op::add(0x12, RegId::HP, 0x20)).unwrap();
vm.instruction::<_, false>(op::add(0x12, RegId::HP, 0x20))
.unwrap();

// Test ownership
vm.instruction(op::mcp(RegId::HP, 0x12, 0x20)).unwrap();
vm.instruction::<_, false>(op::mcp(RegId::HP, 0x12, 0x20))
.unwrap();

// r[0x23] := m[0x30, 0x20] == m[0x12, 0x20]
vm.instruction(op::meq(0x23, RegId::HP, 0x12, 0x20))
vm.instruction::<_, false>(op::meq(0x23, RegId::HP, 0x12, 0x20))
.unwrap();

assert_eq!(1, vm.registers()[0x23]);

// Assert ownership
vm.instruction(op::subi(0x24, RegId::HP, 1)).unwrap(); // TODO: look into this
let ownership_violated = vm.instruction(op::mcp(0x24, 0x12, 0x20));
vm.instruction::<_, false>(op::subi(0x24, RegId::HP, 1))
.unwrap(); // TODO: look into this
let ownership_violated = vm.instruction::<_, false>(op::mcp(0x24, 0x12, 0x20));

assert!(ownership_violated.is_err());

// Assert no panic on overlapping
vm.instruction(op::subi(0x25, 0x12, 1)).unwrap();
let overlapping = vm.instruction(op::mcp(RegId::HP, 0x25, 0x20));
vm.instruction::<_, false>(op::subi(0x25, 0x12, 1)).unwrap();
let overlapping = vm.instruction::<_, false>(op::mcp(RegId::HP, 0x25, 0x20));

assert!(overlapping.is_err());
}
Expand All @@ -112,11 +118,12 @@ fn stack_alloc_ownership() {
.unwrap();
vm.init_script(tx).expect("Failed to init VM");

vm.instruction(op::move_(0x10, RegId::SP)).unwrap();
vm.instruction(op::cfei(2)).unwrap();
vm.instruction::<_, false>(op::move_(0x10, RegId::SP))
.unwrap();
vm.instruction::<_, false>(op::cfei(2)).unwrap();

// Assert allocated stack is writable
vm.instruction(op::mcli(0x10, 2)).unwrap();
vm.instruction::<_, false>(op::mcli(0x10, 2)).unwrap();
}

#[test_case(
Expand Down
Loading