cranelift: Implement PartialEq in Function (#6157)
This commit is contained in:
@@ -64,7 +64,7 @@ impl<'de> Deserialize<'de> for VersionMarker {
|
|||||||
|
|
||||||
/// Function parameters used when creating this function, and that will become applied after
|
/// Function parameters used when creating this function, and that will become applied after
|
||||||
/// compilation to materialize the final `CompiledCode`.
|
/// compilation to materialize the final `CompiledCode`.
|
||||||
#[derive(Clone)]
|
#[derive(Clone, PartialEq)]
|
||||||
#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]
|
#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]
|
||||||
pub struct FunctionParameters {
|
pub struct FunctionParameters {
|
||||||
/// The first `SourceLoc` appearing in the function, serving as a base for every relative
|
/// The first `SourceLoc` appearing in the function, serving as a base for every relative
|
||||||
@@ -351,7 +351,7 @@ impl FunctionStencil {
|
|||||||
|
|
||||||
/// Functions can be cloned, but it is not a very fast operation.
|
/// Functions can be cloned, but it is not a very fast operation.
|
||||||
/// The clone will have all the same entity numbers as the original.
|
/// The clone will have all the same entity numbers as the original.
|
||||||
#[derive(Clone)]
|
#[derive(Clone, PartialEq)]
|
||||||
#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]
|
#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]
|
||||||
pub struct Function {
|
pub struct Function {
|
||||||
/// Name of this function.
|
/// Name of this function.
|
||||||
|
|||||||
@@ -604,12 +604,9 @@ mod tests {
|
|||||||
let mut env = FunctionStore::default();
|
let mut env = FunctionStore::default();
|
||||||
env.add(func.name.to_string(), &func);
|
env.add(func.name.to_string(), &func);
|
||||||
let state = InterpreterState::default().with_function_store(env);
|
let state = InterpreterState::default().with_function_store(env);
|
||||||
let result = Interpreter::new(state)
|
let result = Interpreter::new(state).call_by_name("%test", &[]).unwrap();
|
||||||
.call_by_name("%test", &[])
|
|
||||||
.unwrap()
|
|
||||||
.unwrap_return();
|
|
||||||
|
|
||||||
assert_eq!(result, vec![DataValue::I8(1)])
|
assert_eq!(result, ControlFlow::Return(smallvec![DataValue::I8(1)]));
|
||||||
}
|
}
|
||||||
|
|
||||||
// We don't have a way to check for traps with the current filetest infrastructure
|
// We don't have a way to check for traps with the current filetest infrastructure
|
||||||
@@ -626,12 +623,12 @@ mod tests {
|
|||||||
let mut env = FunctionStore::default();
|
let mut env = FunctionStore::default();
|
||||||
env.add(func.name.to_string(), &func);
|
env.add(func.name.to_string(), &func);
|
||||||
let state = InterpreterState::default().with_function_store(env);
|
let state = InterpreterState::default().with_function_store(env);
|
||||||
let trap = Interpreter::new(state)
|
let trap = Interpreter::new(state).call_by_name("%test", &[]).unwrap();
|
||||||
.call_by_name("%test", &[])
|
|
||||||
.unwrap()
|
|
||||||
.unwrap_trap();
|
|
||||||
|
|
||||||
assert_eq!(trap, CraneliftTrap::User(TrapCode::IntegerDivisionByZero));
|
assert_eq!(
|
||||||
|
trap,
|
||||||
|
ControlFlow::Trap(CraneliftTrap::User(TrapCode::IntegerDivisionByZero))
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@@ -683,10 +680,9 @@ mod tests {
|
|||||||
let state = InterpreterState::default().with_function_store(env);
|
let state = InterpreterState::default().with_function_store(env);
|
||||||
let result = Interpreter::new(state)
|
let result = Interpreter::new(state)
|
||||||
.call_by_name("%parent", &[DataValue::I32(0)])
|
.call_by_name("%parent", &[DataValue::I32(0)])
|
||||||
.unwrap()
|
.unwrap();
|
||||||
.unwrap_return();
|
|
||||||
|
|
||||||
assert_eq!(result, vec![DataValue::I32(0)])
|
assert_eq!(result, ControlFlow::Return(smallvec![DataValue::I32(0)]));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@@ -704,11 +700,9 @@ mod tests {
|
|||||||
|
|
||||||
// The default interpreter should not enable the fuel mechanism
|
// The default interpreter should not enable the fuel mechanism
|
||||||
let state = InterpreterState::default().with_function_store(env.clone());
|
let state = InterpreterState::default().with_function_store(env.clone());
|
||||||
let result = Interpreter::new(state)
|
let result = Interpreter::new(state).call_by_name("%test", &[]).unwrap();
|
||||||
.call_by_name("%test", &[])
|
|
||||||
.unwrap()
|
assert_eq!(result, ControlFlow::Return(smallvec![DataValue::I32(2)]));
|
||||||
.unwrap_return();
|
|
||||||
assert_eq!(result, vec![DataValue::I32(2)]);
|
|
||||||
|
|
||||||
// With 2 fuel, we should execute the iconst and iadd, but not the return thus giving a
|
// With 2 fuel, we should execute the iconst and iadd, but not the return thus giving a
|
||||||
// fuel exhausted error
|
// fuel exhausted error
|
||||||
@@ -726,9 +720,9 @@ mod tests {
|
|||||||
let result = Interpreter::new(state)
|
let result = Interpreter::new(state)
|
||||||
.with_fuel(Some(3))
|
.with_fuel(Some(3))
|
||||||
.call_by_name("%test", &[])
|
.call_by_name("%test", &[])
|
||||||
.unwrap()
|
.unwrap();
|
||||||
.unwrap_return();
|
|
||||||
assert_eq!(result, vec![DataValue::I32(2)]);
|
assert_eq!(result, ControlFlow::Return(smallvec![DataValue::I32(2)]));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Verifies that writing to the stack on a called function does not overwrite the parents
|
// Verifies that writing to the stack on a called function does not overwrite the parents
|
||||||
@@ -784,10 +778,9 @@ mod tests {
|
|||||||
DataValue::I64(11),
|
DataValue::I64(11),
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
.unwrap()
|
.unwrap();
|
||||||
.unwrap_return();
|
|
||||||
|
|
||||||
assert_eq!(result, vec![DataValue::I64(26)])
|
assert_eq!(result, ControlFlow::Return(smallvec![DataValue::I64(26)]))
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@@ -808,10 +801,12 @@ mod tests {
|
|||||||
let state = InterpreterState::default().with_function_store(env);
|
let state = InterpreterState::default().with_function_store(env);
|
||||||
let trap = Interpreter::new(state)
|
let trap = Interpreter::new(state)
|
||||||
.call_by_name("%stack_write", &[])
|
.call_by_name("%stack_write", &[])
|
||||||
.unwrap()
|
.unwrap();
|
||||||
.unwrap_trap();
|
|
||||||
|
|
||||||
assert_eq!(trap, CraneliftTrap::User(TrapCode::HeapOutOfBounds));
|
assert_eq!(
|
||||||
|
trap,
|
||||||
|
ControlFlow::Trap(CraneliftTrap::User(TrapCode::HeapOutOfBounds))
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@@ -832,10 +827,12 @@ mod tests {
|
|||||||
let state = InterpreterState::default().with_function_store(env);
|
let state = InterpreterState::default().with_function_store(env);
|
||||||
let trap = Interpreter::new(state)
|
let trap = Interpreter::new(state)
|
||||||
.call_by_name("%stack_write", &[])
|
.call_by_name("%stack_write", &[])
|
||||||
.unwrap()
|
.unwrap();
|
||||||
.unwrap_trap();
|
|
||||||
|
|
||||||
assert_eq!(trap, CraneliftTrap::User(TrapCode::HeapOutOfBounds));
|
assert_eq!(
|
||||||
|
trap,
|
||||||
|
ControlFlow::Trap(CraneliftTrap::User(TrapCode::HeapOutOfBounds))
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@@ -855,10 +852,12 @@ mod tests {
|
|||||||
let state = InterpreterState::default().with_function_store(env);
|
let state = InterpreterState::default().with_function_store(env);
|
||||||
let trap = Interpreter::new(state)
|
let trap = Interpreter::new(state)
|
||||||
.call_by_name("%stack_load", &[])
|
.call_by_name("%stack_load", &[])
|
||||||
.unwrap()
|
.unwrap();
|
||||||
.unwrap_trap();
|
|
||||||
|
|
||||||
assert_eq!(trap, CraneliftTrap::User(TrapCode::HeapOutOfBounds));
|
assert_eq!(
|
||||||
|
trap,
|
||||||
|
ControlFlow::Trap(CraneliftTrap::User(TrapCode::HeapOutOfBounds))
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@@ -878,10 +877,12 @@ mod tests {
|
|||||||
let state = InterpreterState::default().with_function_store(env);
|
let state = InterpreterState::default().with_function_store(env);
|
||||||
let trap = Interpreter::new(state)
|
let trap = Interpreter::new(state)
|
||||||
.call_by_name("%stack_load", &[])
|
.call_by_name("%stack_load", &[])
|
||||||
.unwrap()
|
.unwrap();
|
||||||
.unwrap_trap();
|
|
||||||
|
|
||||||
assert_eq!(trap, CraneliftTrap::User(TrapCode::HeapOutOfBounds));
|
assert_eq!(
|
||||||
|
trap,
|
||||||
|
ControlFlow::Trap(CraneliftTrap::User(TrapCode::HeapOutOfBounds))
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@@ -904,10 +905,12 @@ mod tests {
|
|||||||
let state = InterpreterState::default().with_function_store(env);
|
let state = InterpreterState::default().with_function_store(env);
|
||||||
let trap = Interpreter::new(state)
|
let trap = Interpreter::new(state)
|
||||||
.call_by_name("%stack_load", &[])
|
.call_by_name("%stack_load", &[])
|
||||||
.unwrap()
|
.unwrap();
|
||||||
.unwrap_trap();
|
|
||||||
|
|
||||||
assert_eq!(trap, CraneliftTrap::User(TrapCode::HeapOutOfBounds));
|
assert_eq!(
|
||||||
|
trap,
|
||||||
|
ControlFlow::Trap(CraneliftTrap::User(TrapCode::HeapOutOfBounds))
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@@ -930,10 +933,12 @@ mod tests {
|
|||||||
let state = InterpreterState::default().with_function_store(env);
|
let state = InterpreterState::default().with_function_store(env);
|
||||||
let trap = Interpreter::new(state)
|
let trap = Interpreter::new(state)
|
||||||
.call_by_name("%stack_store", &[])
|
.call_by_name("%stack_store", &[])
|
||||||
.unwrap()
|
.unwrap();
|
||||||
.unwrap_trap();
|
|
||||||
|
|
||||||
assert_eq!(trap, CraneliftTrap::User(TrapCode::HeapOutOfBounds));
|
assert_eq!(
|
||||||
|
trap,
|
||||||
|
ControlFlow::Trap(CraneliftTrap::User(TrapCode::HeapOutOfBounds))
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@@ -950,12 +955,12 @@ mod tests {
|
|||||||
let mut env = FunctionStore::default();
|
let mut env = FunctionStore::default();
|
||||||
env.add(func.name.to_string(), &func);
|
env.add(func.name.to_string(), &func);
|
||||||
let state = InterpreterState::default().with_function_store(env);
|
let state = InterpreterState::default().with_function_store(env);
|
||||||
let trap = Interpreter::new(state)
|
let trap = Interpreter::new(state).call_by_name("%test", &[]).unwrap();
|
||||||
.call_by_name("%test", &[])
|
|
||||||
.unwrap()
|
|
||||||
.unwrap_trap();
|
|
||||||
|
|
||||||
assert_eq!(trap, CraneliftTrap::User(TrapCode::IntegerOverflow));
|
assert_eq!(
|
||||||
|
trap,
|
||||||
|
ControlFlow::Trap(CraneliftTrap::User(TrapCode::IntegerOverflow))
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@@ -980,12 +985,12 @@ mod tests {
|
|||||||
}])
|
}])
|
||||||
});
|
});
|
||||||
|
|
||||||
let result = Interpreter::new(state)
|
let result = Interpreter::new(state).call_by_name("%test", &[]).unwrap();
|
||||||
.call_by_name("%test", &[])
|
|
||||||
.unwrap()
|
|
||||||
.unwrap_return();
|
|
||||||
|
|
||||||
assert_eq!(result, vec![DataValue::F32(Ieee32::with_float(1.0))])
|
assert_eq!(
|
||||||
|
result,
|
||||||
|
ControlFlow::Return(smallvec![DataValue::F32(Ieee32::with_float(1.0))])
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@@ -1005,12 +1010,12 @@ mod tests {
|
|||||||
let mut env = FunctionStore::default();
|
let mut env = FunctionStore::default();
|
||||||
env.add(func.name.to_string(), &func);
|
env.add(func.name.to_string(), &func);
|
||||||
let state = InterpreterState::default().with_function_store(env);
|
let state = InterpreterState::default().with_function_store(env);
|
||||||
let trap = Interpreter::new(state)
|
let trap = Interpreter::new(state).call_by_name("%test", &[]).unwrap();
|
||||||
.call_by_name("%test", &[])
|
|
||||||
.unwrap()
|
|
||||||
.unwrap_trap();
|
|
||||||
|
|
||||||
assert_eq!(trap, CraneliftTrap::User(TrapCode::HeapMisaligned));
|
assert_eq!(
|
||||||
|
trap,
|
||||||
|
ControlFlow::Trap(CraneliftTrap::User(TrapCode::HeapMisaligned))
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@@ -1031,12 +1036,12 @@ mod tests {
|
|||||||
let mut env = FunctionStore::default();
|
let mut env = FunctionStore::default();
|
||||||
env.add(func.name.to_string(), &func);
|
env.add(func.name.to_string(), &func);
|
||||||
let state = InterpreterState::default().with_function_store(env);
|
let state = InterpreterState::default().with_function_store(env);
|
||||||
let trap = Interpreter::new(state)
|
let trap = Interpreter::new(state).call_by_name("%test", &[]).unwrap();
|
||||||
.call_by_name("%test", &[])
|
|
||||||
.unwrap()
|
|
||||||
.unwrap_trap();
|
|
||||||
|
|
||||||
assert_eq!(trap, CraneliftTrap::User(TrapCode::HeapMisaligned));
|
assert_eq!(
|
||||||
|
trap,
|
||||||
|
ControlFlow::Trap(CraneliftTrap::User(TrapCode::HeapMisaligned))
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// When a trap occurs in a function called by another function, the trap was not being propagated
|
// When a trap occurs in a function called by another function, the trap was not being propagated
|
||||||
@@ -1074,12 +1079,12 @@ mod tests {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let state = InterpreterState::default().with_function_store(env);
|
let state = InterpreterState::default().with_function_store(env);
|
||||||
let trap = Interpreter::new(state)
|
let trap = Interpreter::new(state).call_by_name("%u1", &[]).unwrap();
|
||||||
.call_by_name("%u1", &[])
|
|
||||||
.unwrap()
|
|
||||||
.unwrap_trap();
|
|
||||||
|
|
||||||
// Ensure that the correct trap was propagated.
|
// Ensure that the correct trap was propagated.
|
||||||
assert_eq!(trap, CraneliftTrap::User(TrapCode::HeapMisaligned));
|
assert_eq!(
|
||||||
|
trap,
|
||||||
|
ControlFlow::Trap(CraneliftTrap::User(TrapCode::HeapMisaligned))
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1370,7 +1370,7 @@ pub enum StepError {
|
|||||||
|
|
||||||
/// Enumerate the ways in which the control flow can change based on a single step in a Cranelift
|
/// Enumerate the ways in which the control flow can change based on a single step in a Cranelift
|
||||||
/// interpreter.
|
/// interpreter.
|
||||||
#[derive(Debug)]
|
#[derive(Debug, PartialEq)]
|
||||||
pub enum ControlFlow<'a, V> {
|
pub enum ControlFlow<'a, V> {
|
||||||
/// Return one or more values from an instruction to be assigned to a left-hand side, e.g.:
|
/// Return one or more values from an instruction to be assigned to a left-hand side, e.g.:
|
||||||
/// in `v0 = iadd v1, v2`, the sum of `v1` and `v2` is assigned to `v0`.
|
/// in `v0 = iadd v1, v2`, the sum of `v1` and `v2` is assigned to `v0`.
|
||||||
@@ -1394,30 +1394,6 @@ pub enum ControlFlow<'a, V> {
|
|||||||
Trap(CraneliftTrap),
|
Trap(CraneliftTrap),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, V> ControlFlow<'a, V> {
|
|
||||||
/// For convenience, we can unwrap the [ControlFlow] state assuming that it is a
|
|
||||||
/// [ControlFlow::Return], panicking otherwise.
|
|
||||||
#[cfg(test)]
|
|
||||||
pub fn unwrap_return(self) -> Vec<V> {
|
|
||||||
if let ControlFlow::Return(values) = self {
|
|
||||||
values.into_vec()
|
|
||||||
} else {
|
|
||||||
panic!("expected the control flow to be in the return state")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// For convenience, we can unwrap the [ControlFlow] state assuming that it is a
|
|
||||||
/// [ControlFlow::Trap], panicking otherwise.
|
|
||||||
#[cfg(test)]
|
|
||||||
pub fn unwrap_trap(self) -> CraneliftTrap {
|
|
||||||
if let ControlFlow::Trap(trap) = self {
|
|
||||||
trap
|
|
||||||
} else {
|
|
||||||
panic!("expected the control flow to be a trap")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Error, Debug, PartialEq, Eq, Hash)]
|
#[derive(Error, Debug, PartialEq, Eq, Hash)]
|
||||||
pub enum CraneliftTrap {
|
pub enum CraneliftTrap {
|
||||||
#[error("user code: {0}")]
|
#[error("user code: {0}")]
|
||||||
|
|||||||
Reference in New Issue
Block a user