Skip to content

Commit

Permalink
enable/disable floats configuration (bytecodealliance#121)
Browse files Browse the repository at this point in the history
Added a new operator config option called enable_floats (defaults to true) under the OperatorValidatorConfig.

PR will be very useful for most (if not all) Blockchain projects using wasm for running smart-contracts.

Blockchain project using wasm avoid floats in order to stay deterministic across different hardware / operating-systems.
  • Loading branch information
YaronWittenstein authored and yurydelendik committed Aug 21, 2019
1 parent 4b13510 commit dd0a114
Show file tree
Hide file tree
Showing 4 changed files with 193 additions and 37 deletions.
5 changes: 5 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,11 @@ default = ["std"]
std = []
core = ["hashbrown"]

# The "deterministic" feature supports only wasm code with "deterministic" execution
# across any hardware. This feature is very critical for many Blockchain infrastructures
# that rely on deterministic executions of smart contracts across different hardwares.
deterministic = []

[[bench]]
name = "benchmark"
harness = false
134 changes: 97 additions & 37 deletions src/operators_validator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -269,6 +269,9 @@ pub struct OperatorValidatorConfig {
pub enable_simd: bool,
pub enable_bulk_memory: bool,
pub enable_multi_value: bool,

#[cfg(feature = "deterministic")]
pub deterministic_only: bool,
}

pub(crate) const DEFAULT_OPERATOR_VALIDATOR_CONFIG: OperatorValidatorConfig =
Expand All @@ -278,6 +281,9 @@ pub(crate) const DEFAULT_OPERATOR_VALIDATOR_CONFIG: OperatorValidatorConfig =
enable_simd: false,
enable_bulk_memory: false,
enable_multi_value: false,

#[cfg(feature = "deterministic")]
deterministic_only: true,
};

#[derive(Debug)]
Expand Down Expand Up @@ -488,6 +494,20 @@ impl OperatorValidator {
Ok(())
}

#[cfg(feature = "deterministic")]
fn check_non_deterministic_enabled(&self) -> OperatorValidatorResult<()> {
if !self.config.deterministic_only {
return Err("deterministic_only support is not enabled");
}
Ok(())
}

#[inline(always)]
#[cfg(not(feature = "deterministic"))]
fn check_non_deterministic_enabled(&self) -> OperatorValidatorResult<()> {
Ok(())
}

fn check_threads_enabled(&self) -> OperatorValidatorResult<()> {
if !self.config.enable_threads {
return Err("threads support is not enabled");
Expand Down Expand Up @@ -782,11 +802,13 @@ impl OperatorValidator {
self.func_state.change_frame_with_type(1, Type::I64)?;
}
Operator::F32Load { ref memarg } => {
self.check_non_deterministic_enabled()?;
self.check_memarg(memarg, 2, resources)?;
self.check_operands_1(Type::I32)?;
self.func_state.change_frame_with_type(1, Type::F32)?;
}
Operator::F64Load { ref memarg } => {
self.check_non_deterministic_enabled()?;
self.check_memarg(memarg, 3, resources)?;
self.check_operands_1(Type::I32)?;
self.func_state.change_frame_with_type(1, Type::F64)?;
Expand Down Expand Up @@ -852,11 +874,13 @@ impl OperatorValidator {
self.func_state.change_frame(2)?;
}
Operator::F32Store { ref memarg } => {
self.check_non_deterministic_enabled()?;
self.check_memarg(memarg, 2, resources)?;
self.check_operands_2(Type::I32, Type::F32)?;
self.func_state.change_frame(2)?;
}
Operator::F64Store { ref memarg } => {
self.check_non_deterministic_enabled()?;
self.check_memarg(memarg, 3, resources)?;
self.check_operands_2(Type::I32, Type::F64)?;
self.func_state.change_frame(2)?;
Expand Down Expand Up @@ -901,8 +925,14 @@ impl OperatorValidator {
}
Operator::I32Const { .. } => self.func_state.change_frame_with_type(0, Type::I32)?,
Operator::I64Const { .. } => self.func_state.change_frame_with_type(0, Type::I64)?,
Operator::F32Const { .. } => self.func_state.change_frame_with_type(0, Type::F32)?,
Operator::F64Const { .. } => self.func_state.change_frame_with_type(0, Type::F64)?,
Operator::F32Const { .. } => {
self.check_non_deterministic_enabled()?;
self.func_state.change_frame_with_type(0, Type::F32)?;
}
Operator::F64Const { .. } => {
self.check_non_deterministic_enabled()?;
self.func_state.change_frame_with_type(0, Type::F64)?;
}
Operator::I32Eqz => {
self.check_operands_1(Type::I32)?;
self.func_state.change_frame_with_type(1, Type::I32)?;
Expand Down Expand Up @@ -943,6 +973,7 @@ impl OperatorValidator {
| Operator::F32Gt
| Operator::F32Le
| Operator::F32Ge => {
self.check_non_deterministic_enabled()?;
self.check_operands_2(Type::F32, Type::F32)?;
self.func_state.change_frame_with_type(2, Type::I32)?;
}
Expand All @@ -952,6 +983,7 @@ impl OperatorValidator {
| Operator::F64Gt
| Operator::F64Le
| Operator::F64Ge => {
self.check_non_deterministic_enabled()?;
self.check_operands_2(Type::F64, Type::F64)?;
self.func_state.change_frame_with_type(2, Type::I32)?;
}
Expand Down Expand Up @@ -1006,6 +1038,7 @@ impl OperatorValidator {
| Operator::F32Trunc
| Operator::F32Nearest
| Operator::F32Sqrt => {
self.check_non_deterministic_enabled()?;
self.check_operands_1(Type::F32)?;
self.func_state.change_frame_with_type(1, Type::F32)?;
}
Expand All @@ -1016,6 +1049,7 @@ impl OperatorValidator {
| Operator::F32Min
| Operator::F32Max
| Operator::F32Copysign => {
self.check_non_deterministic_enabled()?;
self.check_operands_2(Type::F32, Type::F32)?;
self.func_state.change_frame_with_type(2, Type::F32)?;
}
Expand All @@ -1026,6 +1060,7 @@ impl OperatorValidator {
| Operator::F64Trunc
| Operator::F64Nearest
| Operator::F64Sqrt => {
self.check_non_deterministic_enabled()?;
self.check_operands_1(Type::F64)?;
self.func_state.change_frame_with_type(1, Type::F64)?;
}
Expand All @@ -1036,6 +1071,7 @@ impl OperatorValidator {
| Operator::F64Min
| Operator::F64Max
| Operator::F64Copysign => {
self.check_non_deterministic_enabled()?;
self.check_operands_2(Type::F64, Type::F64)?;
self.func_state.change_frame_with_type(2, Type::F64)?;
}
Expand Down Expand Up @@ -1064,26 +1100,32 @@ impl OperatorValidator {
self.func_state.change_frame_with_type(1, Type::I64)?;
}
Operator::F32ConvertSI32 | Operator::F32ConvertUI32 => {
self.check_non_deterministic_enabled()?;
self.check_operands_1(Type::I32)?;
self.func_state.change_frame_with_type(1, Type::F32)?;
}
Operator::F32ConvertSI64 | Operator::F32ConvertUI64 => {
self.check_non_deterministic_enabled()?;
self.check_operands_1(Type::I64)?;
self.func_state.change_frame_with_type(1, Type::F32)?;
}
Operator::F32DemoteF64 => {
self.check_non_deterministic_enabled()?;
self.check_operands_1(Type::F64)?;
self.func_state.change_frame_with_type(1, Type::F32)?;
}
Operator::F64ConvertSI32 | Operator::F64ConvertUI32 => {
self.check_non_deterministic_enabled()?;
self.check_operands_1(Type::I32)?;
self.func_state.change_frame_with_type(1, Type::F64)?;
}
Operator::F64ConvertSI64 | Operator::F64ConvertUI64 => {
self.check_non_deterministic_enabled()?;
self.check_operands_1(Type::I64)?;
self.func_state.change_frame_with_type(1, Type::F64)?;
}
Operator::F64PromoteF32 => {
self.check_non_deterministic_enabled()?;
self.check_operands_1(Type::F32)?;
self.func_state.change_frame_with_type(1, Type::F64)?;
}
Expand All @@ -1096,10 +1138,12 @@ impl OperatorValidator {
self.func_state.change_frame_with_type(1, Type::I64)?;
}
Operator::F32ReinterpretI32 => {
self.check_non_deterministic_enabled()?;
self.check_operands_1(Type::I32)?;
self.func_state.change_frame_with_type(1, Type::F32)?;
}
Operator::F64ReinterpretI64 => {
self.check_non_deterministic_enabled()?;
self.check_operands_1(Type::I64)?;
self.func_state.change_frame_with_type(1, Type::F64)?;
}
Expand Down Expand Up @@ -1302,11 +1346,13 @@ impl OperatorValidator {
self.func_state.change_frame_with_type(1, Type::V128)?;
}
Operator::F32x4Splat => {
self.check_non_deterministic_enabled()?;
self.check_simd_enabled()?;
self.check_operands_1(Type::F32)?;
self.func_state.change_frame_with_type(1, Type::V128)?;
}
Operator::F64x2Splat => {
self.check_non_deterministic_enabled()?;
self.check_simd_enabled()?;
self.check_operands_1(Type::F64)?;
self.func_state.change_frame_with_type(1, Type::V128)?;
Expand Down Expand Up @@ -1360,29 +1406,62 @@ impl OperatorValidator {
self.func_state.change_frame_with_type(2, Type::V128)?;
}
Operator::F32x4ExtractLane { lane } => {
self.check_non_deterministic_enabled()?;
self.check_simd_enabled()?;
self.check_simd_lane_index(lane, 4)?;
self.check_operands_1(Type::V128)?;
self.func_state.change_frame_with_type(1, Type::F32)?;
}
Operator::F32x4ReplaceLane { lane } => {
self.check_non_deterministic_enabled()?;
self.check_simd_enabled()?;
self.check_simd_lane_index(lane, 4)?;
self.check_operands_2(Type::V128, Type::F32)?;
self.func_state.change_frame_with_type(2, Type::V128)?;
}
Operator::F64x2ExtractLane { lane } => {
self.check_non_deterministic_enabled()?;
self.check_simd_enabled()?;
self.check_simd_lane_index(lane, 2)?;
self.check_operands_1(Type::V128)?;
self.func_state.change_frame_with_type(1, Type::F64)?;
}
Operator::F64x2ReplaceLane { lane } => {
self.check_non_deterministic_enabled()?;
self.check_simd_enabled()?;
self.check_simd_lane_index(lane, 2)?;
self.check_operands_2(Type::V128, Type::F64)?;
self.func_state.change_frame_with_type(2, Type::V128)?;
}
Operator::F32x4Eq
| Operator::F32x4Ne
| Operator::F32x4Lt
| Operator::F32x4Gt
| Operator::F32x4Le
| Operator::F32x4Ge
| Operator::F64x2Eq
| Operator::F64x2Ne
| Operator::F64x2Lt
| Operator::F64x2Gt
| Operator::F64x2Le
| Operator::F64x2Ge
| Operator::F32x4Add
| Operator::F32x4Sub
| Operator::F32x4Mul
| Operator::F32x4Div
| Operator::F32x4Min
| Operator::F32x4Max
| Operator::F64x2Add
| Operator::F64x2Sub
| Operator::F64x2Mul
| Operator::F64x2Div
| Operator::F64x2Min
| Operator::F64x2Max => {
self.check_non_deterministic_enabled()?;
self.check_simd_enabled()?;
self.check_operands_2(Type::V128, Type::V128)?;
self.func_state.change_frame_with_type(2, Type::V128)?;
}
Operator::I8x16Eq
| Operator::I8x16Ne
| Operator::I8x16LtS
Expand Down Expand Up @@ -1413,18 +1492,6 @@ impl OperatorValidator {
| Operator::I32x4LeU
| Operator::I32x4GeS
| Operator::I32x4GeU
| Operator::F32x4Eq
| Operator::F32x4Ne
| Operator::F32x4Lt
| Operator::F32x4Gt
| Operator::F32x4Le
| Operator::F32x4Ge
| Operator::F64x2Eq
| Operator::F64x2Ne
| Operator::F64x2Lt
| Operator::F64x2Gt
| Operator::F64x2Le
| Operator::F64x2Ge
| Operator::V128And
| Operator::V128Or
| Operator::V128Xor
Expand All @@ -1446,42 +1513,35 @@ impl OperatorValidator {
| Operator::I32x4Sub
| Operator::I32x4Mul
| Operator::I64x2Add
| Operator::I64x2Sub
| Operator::F32x4Add
| Operator::F32x4Sub
| Operator::F32x4Mul
| Operator::F32x4Div
| Operator::F32x4Min
| Operator::F32x4Max
| Operator::F64x2Add
| Operator::F64x2Sub
| Operator::F64x2Mul
| Operator::F64x2Div
| Operator::F64x2Min
| Operator::F64x2Max => {
| Operator::I64x2Sub => {
self.check_simd_enabled()?;
self.check_operands_2(Type::V128, Type::V128)?;
self.func_state.change_frame_with_type(2, Type::V128)?;
}
Operator::V128Not
| Operator::I8x16Neg
| Operator::I16x8Neg
| Operator::I32x4Neg
| Operator::I64x2Neg
| Operator::F32x4Abs
Operator::F32x4Abs
| Operator::F32x4Neg
| Operator::F32x4Sqrt
| Operator::F64x2Abs
| Operator::F64x2Neg
| Operator::F64x2Sqrt
| Operator::I32x4TruncSF32x4Sat
| Operator::I32x4TruncUF32x4Sat
| Operator::I64x2TruncSF64x2Sat
| Operator::I64x2TruncUF64x2Sat
| Operator::F32x4ConvertSI32x4
| Operator::F32x4ConvertUI32x4
| Operator::F64x2ConvertSI64x2
| Operator::F64x2ConvertUI64x2 => {
self.check_non_deterministic_enabled()?;
self.check_simd_enabled()?;
self.check_operands_1(Type::V128)?;
self.func_state.change_frame_with_type(1, Type::V128)?;
}
Operator::V128Not
| Operator::I8x16Neg
| Operator::I16x8Neg
| Operator::I32x4Neg
| Operator::I64x2Neg
| Operator::I32x4TruncSF32x4Sat
| Operator::I32x4TruncUF32x4Sat
| Operator::I64x2TruncSF64x2Sat
| Operator::I64x2TruncUF64x2Sat => {
self.check_simd_enabled()?;
self.check_operands_1(Type::V128)?;
self.func_state.change_frame_with_type(1, Type::V128)?;
Expand Down
Loading

0 comments on commit dd0a114

Please sign in to comment.