mirror of
https://github.com/fluencelabs/wasm-utils
synced 2025-07-01 15:31:44 +00:00
add rules with forbid operations
This commit is contained in:
@ -16,7 +16,9 @@ fn main() {
|
|||||||
// Loading module
|
// Loading module
|
||||||
let module = parity_wasm::deserialize_file(&args[1]).expect("Module deserialization to succeed");
|
let module = parity_wasm::deserialize_file(&args[1]).expect("Module deserialization to succeed");
|
||||||
|
|
||||||
let result = wasm_utils::inject_gas_counter(module, &Default::default());
|
let result = wasm_utils::inject_gas_counter(
|
||||||
|
module, &Default::default()
|
||||||
|
).expect("Failed to inject gas. Some forbidden opcodes?");
|
||||||
|
|
||||||
parity_wasm::serialize_to_file(&args[2], result).expect("Module serialization to succeed")
|
parity_wasm::serialize_to_file(&args[2], result).expect("Module serialization to succeed")
|
||||||
}
|
}
|
||||||
|
67
src/gas.rs
67
src/gas.rs
@ -65,7 +65,7 @@ pub fn inject_counter(
|
|||||||
opcodes: &mut elements::Opcodes,
|
opcodes: &mut elements::Opcodes,
|
||||||
rules: &rules::Set,
|
rules: &rules::Set,
|
||||||
gas_func: u32,
|
gas_func: u32,
|
||||||
) {
|
) -> Result<(), ()> {
|
||||||
use parity_wasm::elements::Opcode::*;
|
use parity_wasm::elements::Opcode::*;
|
||||||
|
|
||||||
let mut stack: Vec<(usize, usize)> = Vec::new();
|
let mut stack: Vec<(usize, usize)> = Vec::new();
|
||||||
@ -83,7 +83,7 @@ pub fn inject_counter(
|
|||||||
let opcode = &opcodes.elements()[cursor];
|
let opcode = &opcodes.elements()[cursor];
|
||||||
match *opcode {
|
match *opcode {
|
||||||
Block(_) | If(_) | Loop(_) => {
|
Block(_) | If(_) | Loop(_) => {
|
||||||
InjectAction::Spawn(rules.process(opcode))
|
InjectAction::Spawn(rules.process(opcode)?)
|
||||||
},
|
},
|
||||||
Else => {
|
Else => {
|
||||||
InjectAction::IncrementSpawn
|
InjectAction::IncrementSpawn
|
||||||
@ -92,7 +92,7 @@ pub fn inject_counter(
|
|||||||
InjectAction::Increment
|
InjectAction::Increment
|
||||||
},
|
},
|
||||||
_ => {
|
_ => {
|
||||||
InjectAction::Continue(rules.process(opcode))
|
InjectAction::Continue(rules.process(opcode)?)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -125,9 +125,17 @@ pub fn inject_counter(
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn inject_gas_counter(module: elements::Module, rules: &rules::Set) -> elements::Module {
|
/// Injects gas counter.
|
||||||
|
///
|
||||||
|
/// Can only fail if encounters operation forbidden by gas rules,
|
||||||
|
/// in this case it returns error with the original module.
|
||||||
|
pub fn inject_gas_counter(module: elements::Module, rules: &rules::Set)
|
||||||
|
-> Result<elements::Module, elements::Module>
|
||||||
|
{
|
||||||
// Injecting gas counting external
|
// Injecting gas counting external
|
||||||
let mut mbuilder = builder::from_module(module);
|
let mut mbuilder = builder::from_module(module);
|
||||||
let import_sig = mbuilder.push_signature(
|
let import_sig = mbuilder.push_signature(
|
||||||
@ -153,6 +161,7 @@ pub fn inject_gas_counter(module: elements::Module, rules: &rules::Set) -> eleme
|
|||||||
let gas_func = module.import_count(elements::ImportCountType::Function) as u32 - 1;
|
let gas_func = module.import_count(elements::ImportCountType::Function) as u32 - 1;
|
||||||
let total_func = module.functions_space() as u32;
|
let total_func = module.functions_space() as u32;
|
||||||
let mut need_grow_counter = false;
|
let mut need_grow_counter = false;
|
||||||
|
let mut error = false;
|
||||||
|
|
||||||
// Updating calling addresses (all calls to function index >= `gas_func` should be incremented)
|
// Updating calling addresses (all calls to function index >= `gas_func` should be incremented)
|
||||||
for section in module.sections_mut() {
|
for section in module.sections_mut() {
|
||||||
@ -160,7 +169,10 @@ pub fn inject_gas_counter(module: elements::Module, rules: &rules::Set) -> eleme
|
|||||||
&mut elements::Section::Code(ref mut code_section) => {
|
&mut elements::Section::Code(ref mut code_section) => {
|
||||||
for ref mut func_body in code_section.bodies_mut() {
|
for ref mut func_body in code_section.bodies_mut() {
|
||||||
update_call_index(func_body.code_mut(), gas_func);
|
update_call_index(func_body.code_mut(), gas_func);
|
||||||
inject_counter(func_body.code_mut(), rules, gas_func);
|
if let Err(_) = inject_counter(func_body.code_mut(), rules, gas_func) {
|
||||||
|
error = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
if rules.grow_cost() > 0 {
|
if rules.grow_cost() > 0 {
|
||||||
if inject_grow_counter(func_body.code_mut(), total_func) > 0 {
|
if inject_grow_counter(func_body.code_mut(), total_func) > 0 {
|
||||||
need_grow_counter = true;
|
need_grow_counter = true;
|
||||||
@ -190,7 +202,9 @@ pub fn inject_gas_counter(module: elements::Module, rules: &rules::Set) -> eleme
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if need_grow_counter { add_grow_counter(module, rules, gas_func) } else { module }
|
if error { return Err(module); }
|
||||||
|
|
||||||
|
if need_grow_counter { Ok(add_grow_counter(module, rules, gas_func)) } else { Ok(module) }
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
@ -224,7 +238,7 @@ mod tests {
|
|||||||
.build()
|
.build()
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
let injected_module = inject_gas_counter(module, &rules::Set::default().with_grow_cost(10000));
|
let injected_module = inject_gas_counter(module, &rules::Set::default().with_grow_cost(10000)).unwrap();
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
&vec![
|
&vec![
|
||||||
@ -280,7 +294,7 @@ mod tests {
|
|||||||
.build()
|
.build()
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
let injected_module = inject_gas_counter(module, &rules::Set::default());
|
let injected_module = inject_gas_counter(module, &rules::Set::default()).unwrap();
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
&vec![
|
&vec![
|
||||||
@ -322,7 +336,7 @@ mod tests {
|
|||||||
.build()
|
.build()
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
let injected_module = inject_gas_counter(module, &Default::default());
|
let injected_module = inject_gas_counter(module, &Default::default()).unwrap();
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
&vec![
|
&vec![
|
||||||
@ -364,7 +378,7 @@ mod tests {
|
|||||||
.build()
|
.build()
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
let injected_module = inject_gas_counter(module, &Default::default());
|
let injected_module = inject_gas_counter(module, &Default::default()).unwrap();
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
&vec![
|
&vec![
|
||||||
@ -417,7 +431,7 @@ mod tests {
|
|||||||
.build()
|
.build()
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
let injected_module = inject_gas_counter(module, &Default::default());
|
let injected_module = inject_gas_counter(module, &Default::default()).unwrap();
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
&vec![
|
&vec![
|
||||||
@ -479,7 +493,7 @@ mod tests {
|
|||||||
.build()
|
.build()
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
let injected_module = inject_gas_counter(module, &Default::default());
|
let injected_module = inject_gas_counter(module, &Default::default()).unwrap();
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
&vec![
|
&vec![
|
||||||
@ -507,4 +521,33 @@ mod tests {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn forbidden() {
|
||||||
|
use parity_wasm::elements::Opcode::*;
|
||||||
|
|
||||||
|
let module = builder::module()
|
||||||
|
.global()
|
||||||
|
.value_type().i32()
|
||||||
|
.build()
|
||||||
|
.function()
|
||||||
|
.signature().param().i32().build()
|
||||||
|
.body()
|
||||||
|
.with_opcodes(elements::Opcodes::new(
|
||||||
|
vec![
|
||||||
|
F32Const(555555),
|
||||||
|
End
|
||||||
|
]
|
||||||
|
))
|
||||||
|
.build()
|
||||||
|
.build()
|
||||||
|
.build();
|
||||||
|
|
||||||
|
let rules = rules::Set::default().with_forbidden_floats();
|
||||||
|
|
||||||
|
if let Err(_) = inject_gas_counter(module, &rules) { }
|
||||||
|
else { panic!("Should be error because of the forbidden operation")}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
@ -16,7 +16,6 @@ mod symbols;
|
|||||||
mod logger;
|
mod logger;
|
||||||
mod ext;
|
mod ext;
|
||||||
mod pack;
|
mod pack;
|
||||||
mod nondeterminism_check;
|
|
||||||
mod runtime_type;
|
mod runtime_type;
|
||||||
|
|
||||||
pub use optimizer::{optimize, Error as OptimizerError};
|
pub use optimizer::{optimize, Error as OptimizerError};
|
||||||
@ -24,5 +23,4 @@ pub use gas::inject_gas_counter;
|
|||||||
pub use logger::init_log;
|
pub use logger::init_log;
|
||||||
pub use ext::{externalize, externalize_mem, underscore_funcs, ununderscore_funcs, shrink_unknown_stack};
|
pub use ext::{externalize, externalize_mem, underscore_funcs, ununderscore_funcs, shrink_unknown_stack};
|
||||||
pub use pack::pack_instance;
|
pub use pack::pack_instance;
|
||||||
pub use nondeterminism_check::is_deterministic;
|
|
||||||
pub use runtime_type::inject_runtime_type;
|
pub use runtime_type::inject_runtime_type;
|
||||||
|
@ -1,138 +0,0 @@
|
|||||||
use parity_wasm::{elements};
|
|
||||||
use parity_wasm::elements::{ Section, Opcode };
|
|
||||||
use parity_wasm::elements::Opcode::*;
|
|
||||||
|
|
||||||
fn have_nondeterministic_opcodes (opcodes: &[Opcode]) -> bool {
|
|
||||||
for opcode in opcodes {
|
|
||||||
match *opcode {
|
|
||||||
F32Abs |
|
|
||||||
F32Neg |
|
|
||||||
F32Ceil |
|
|
||||||
F32Floor |
|
|
||||||
F32Trunc |
|
|
||||||
F32Nearest |
|
|
||||||
F32Sqrt |
|
|
||||||
F32Add |
|
|
||||||
F32Sub |
|
|
||||||
F32Mul |
|
|
||||||
F32Div |
|
|
||||||
F32Min |
|
|
||||||
F32Max |
|
|
||||||
F32Copysign |
|
|
||||||
F64Abs |
|
|
||||||
F64Neg |
|
|
||||||
F64Ceil |
|
|
||||||
F64Floor |
|
|
||||||
F64Trunc |
|
|
||||||
F64Nearest |
|
|
||||||
F64Sqrt |
|
|
||||||
F64Add |
|
|
||||||
F64Sub |
|
|
||||||
F64Mul |
|
|
||||||
F64Div |
|
|
||||||
F64Min |
|
|
||||||
F64Max |
|
|
||||||
F64Copysign |
|
|
||||||
I32TruncSF32 |
|
|
||||||
I32TruncUF32 |
|
|
||||||
I32TruncSF64 |
|
|
||||||
I32TruncUF64 |
|
|
||||||
I64TruncSF32 |
|
|
||||||
I64TruncUF32 |
|
|
||||||
I64TruncSF64 |
|
|
||||||
I64TruncUF64 |
|
|
||||||
F32ConvertSI32 |
|
|
||||||
F32ConvertUI32 |
|
|
||||||
F32ConvertSI64 |
|
|
||||||
F32ConvertUI64 |
|
|
||||||
F32DemoteF64 |
|
|
||||||
F64ConvertSI32 |
|
|
||||||
F64ConvertUI32 |
|
|
||||||
F64ConvertSI64 |
|
|
||||||
F64ConvertUI64 |
|
|
||||||
F64PromoteF32 |
|
|
||||||
I32ReinterpretF32 |
|
|
||||||
I64ReinterpretF64 |
|
|
||||||
F32ReinterpretI32 |
|
|
||||||
F64ReinterpretI64 |
|
|
||||||
F32Eq |
|
|
||||||
F32Ne |
|
|
||||||
F32Lt |
|
|
||||||
F32Gt |
|
|
||||||
F32Le |
|
|
||||||
F32Ge |
|
|
||||||
F64Eq |
|
|
||||||
F64Ne |
|
|
||||||
F64Lt |
|
|
||||||
F64Gt |
|
|
||||||
F64Le |
|
|
||||||
F64Ge
|
|
||||||
=> return true,
|
|
||||||
_ => continue
|
|
||||||
}
|
|
||||||
}
|
|
||||||
false
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
pub fn is_deterministic(module: &elements::Module) -> bool {
|
|
||||||
for section in module.sections() {
|
|
||||||
match *section {
|
|
||||||
Section::Code(ref cs) => {
|
|
||||||
for body in cs.bodies() {
|
|
||||||
if have_nondeterministic_opcodes(body.code().elements()) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
_ => continue
|
|
||||||
}
|
|
||||||
}
|
|
||||||
true
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(test)]
|
|
||||||
mod tests {
|
|
||||||
use parity_wasm::{builder, elements};
|
|
||||||
use super::*;
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn nondeterminism_found() {
|
|
||||||
let module = builder::module()
|
|
||||||
.function().signature().return_type().f32().build()
|
|
||||||
.body()
|
|
||||||
.with_opcodes(elements::Opcodes::new(
|
|
||||||
vec![
|
|
||||||
elements::Opcode::F32Const(1), // unrelated to this test matter
|
|
||||||
elements::Opcode::F32Const(1), // unrelated to this test matter
|
|
||||||
elements::Opcode::F32Add,
|
|
||||||
elements::Opcode::End
|
|
||||||
]
|
|
||||||
))
|
|
||||||
.build()
|
|
||||||
.build()
|
|
||||||
.build();
|
|
||||||
assert_eq!(false, is_deterministic(&module));
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn nondeterminism_not() {
|
|
||||||
let module = builder::module()
|
|
||||||
.function().signature().return_type().i32().build()
|
|
||||||
.body()
|
|
||||||
.with_opcodes(elements::Opcodes::new(
|
|
||||||
vec![
|
|
||||||
elements::Opcode::I32Const(1),
|
|
||||||
elements::Opcode::I32Const(1),
|
|
||||||
elements::Opcode::I32Add,
|
|
||||||
elements::Opcode::End
|
|
||||||
]
|
|
||||||
))
|
|
||||||
.build()
|
|
||||||
.build()
|
|
||||||
.build();
|
|
||||||
assert_eq!(true, is_deterministic(&module));
|
|
||||||
}
|
|
||||||
}
|
|
147
src/rules.rs
147
src/rules.rs
@ -3,6 +3,13 @@ use parity_wasm::elements;
|
|||||||
|
|
||||||
pub struct UnknownInstruction;
|
pub struct UnknownInstruction;
|
||||||
|
|
||||||
|
#[derive(Debug, PartialEq, Eq, Copy, Clone)]
|
||||||
|
pub enum Metering {
|
||||||
|
Regular,
|
||||||
|
Forbidden,
|
||||||
|
Fixed(u32),
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, Hash, PartialEq, Eq, Copy, Clone)]
|
#[derive(Debug, Hash, PartialEq, Eq, Copy, Clone)]
|
||||||
pub enum InstructionType {
|
pub enum InstructionType {
|
||||||
Bit,
|
Bit,
|
||||||
@ -12,13 +19,15 @@ pub enum InstructionType {
|
|||||||
Load,
|
Load,
|
||||||
Store,
|
Store,
|
||||||
Const,
|
Const,
|
||||||
|
FloatConst,
|
||||||
Local,
|
Local,
|
||||||
Global,
|
Global,
|
||||||
ControlFlow,
|
ControlFlow,
|
||||||
IntegerComparsion,
|
IntegerComparsion,
|
||||||
FloatComparsion,
|
FloatComparsion,
|
||||||
Numeric,
|
Float,
|
||||||
Conversion,
|
Conversion,
|
||||||
|
FloatConversion,
|
||||||
Reinterpretation,
|
Reinterpretation,
|
||||||
Unreachable,
|
Unreachable,
|
||||||
Nop,
|
Nop,
|
||||||
@ -43,8 +52,9 @@ impl ::std::str::FromStr for InstructionType {
|
|||||||
"flow" => Ok(InstructionType::ControlFlow),
|
"flow" => Ok(InstructionType::ControlFlow),
|
||||||
"integer_comp" => Ok(InstructionType::IntegerComparsion),
|
"integer_comp" => Ok(InstructionType::IntegerComparsion),
|
||||||
"float_comp" => Ok(InstructionType::FloatComparsion),
|
"float_comp" => Ok(InstructionType::FloatComparsion),
|
||||||
"numeric" => Ok(InstructionType::Numeric),
|
"float" => Ok(InstructionType::Float),
|
||||||
"conversion" => Ok(InstructionType::Conversion),
|
"conversion" => Ok(InstructionType::Conversion),
|
||||||
|
"float_conversion" => Ok(InstructionType::FloatConversion),
|
||||||
"reinterpret" => Ok(InstructionType::Reinterpretation),
|
"reinterpret" => Ok(InstructionType::Reinterpretation),
|
||||||
"unreachable" => Ok(InstructionType::Unreachable),
|
"unreachable" => Ok(InstructionType::Unreachable),
|
||||||
"nop" => Ok(InstructionType::Nop),
|
"nop" => Ok(InstructionType::Nop),
|
||||||
@ -112,8 +122,9 @@ impl InstructionType {
|
|||||||
|
|
||||||
I32Const(_) => InstructionType::Const,
|
I32Const(_) => InstructionType::Const,
|
||||||
I64Const(_) => InstructionType::Const,
|
I64Const(_) => InstructionType::Const,
|
||||||
F32Const(_) => InstructionType::Const,
|
|
||||||
F64Const(_) => InstructionType::Const,
|
F32Const(_) => InstructionType::FloatConst,
|
||||||
|
F64Const(_) => InstructionType::FloatConst,
|
||||||
|
|
||||||
I32Eqz => InstructionType::IntegerComparsion,
|
I32Eqz => InstructionType::IntegerComparsion,
|
||||||
I32Eq => InstructionType::IntegerComparsion,
|
I32Eq => InstructionType::IntegerComparsion,
|
||||||
@ -191,56 +202,57 @@ impl InstructionType {
|
|||||||
I64Rotl => InstructionType::Bit,
|
I64Rotl => InstructionType::Bit,
|
||||||
I64Rotr => InstructionType::Bit,
|
I64Rotr => InstructionType::Bit,
|
||||||
|
|
||||||
F32Abs => InstructionType::Numeric,
|
F32Abs => InstructionType::Float,
|
||||||
F32Neg => InstructionType::Numeric,
|
F32Neg => InstructionType::Float,
|
||||||
F32Ceil => InstructionType::Numeric,
|
F32Ceil => InstructionType::Float,
|
||||||
F32Floor => InstructionType::Numeric,
|
F32Floor => InstructionType::Float,
|
||||||
F32Trunc => InstructionType::Numeric,
|
F32Trunc => InstructionType::Float,
|
||||||
F32Nearest => InstructionType::Numeric,
|
F32Nearest => InstructionType::Float,
|
||||||
F32Sqrt => InstructionType::Numeric,
|
F32Sqrt => InstructionType::Float,
|
||||||
F32Add => InstructionType::Numeric,
|
F32Add => InstructionType::Float,
|
||||||
F32Sub => InstructionType::Numeric,
|
F32Sub => InstructionType::Float,
|
||||||
F32Mul => InstructionType::Numeric,
|
F32Mul => InstructionType::Float,
|
||||||
F32Div => InstructionType::Numeric,
|
F32Div => InstructionType::Float,
|
||||||
F32Min => InstructionType::Numeric,
|
F32Min => InstructionType::Float,
|
||||||
F32Max => InstructionType::Numeric,
|
F32Max => InstructionType::Float,
|
||||||
F32Copysign => InstructionType::Numeric,
|
F32Copysign => InstructionType::Float,
|
||||||
F64Abs => InstructionType::Numeric,
|
F64Abs => InstructionType::Float,
|
||||||
F64Neg => InstructionType::Numeric,
|
F64Neg => InstructionType::Float,
|
||||||
F64Ceil => InstructionType::Numeric,
|
F64Ceil => InstructionType::Float,
|
||||||
F64Floor => InstructionType::Numeric,
|
F64Floor => InstructionType::Float,
|
||||||
F64Trunc => InstructionType::Numeric,
|
F64Trunc => InstructionType::Float,
|
||||||
F64Nearest => InstructionType::Numeric,
|
F64Nearest => InstructionType::Float,
|
||||||
F64Sqrt => InstructionType::Numeric,
|
F64Sqrt => InstructionType::Float,
|
||||||
F64Add => InstructionType::Numeric,
|
F64Add => InstructionType::Float,
|
||||||
F64Sub => InstructionType::Numeric,
|
F64Sub => InstructionType::Float,
|
||||||
F64Mul => InstructionType::Numeric,
|
F64Mul => InstructionType::Float,
|
||||||
F64Div => InstructionType::Numeric,
|
F64Div => InstructionType::Float,
|
||||||
F64Min => InstructionType::Numeric,
|
F64Min => InstructionType::Float,
|
||||||
F64Max => InstructionType::Numeric,
|
F64Max => InstructionType::Float,
|
||||||
F64Copysign => InstructionType::Numeric,
|
F64Copysign => InstructionType::Float,
|
||||||
|
|
||||||
I32WrapI64 => InstructionType::Conversion,
|
I32WrapI64 => InstructionType::Conversion,
|
||||||
I32TruncSF32 => InstructionType::Conversion,
|
|
||||||
I32TruncUF32 => InstructionType::Conversion,
|
|
||||||
I32TruncSF64 => InstructionType::Conversion,
|
|
||||||
I32TruncUF64 => InstructionType::Conversion,
|
|
||||||
I64ExtendSI32 => InstructionType::Conversion,
|
I64ExtendSI32 => InstructionType::Conversion,
|
||||||
I64ExtendUI32 => InstructionType::Conversion,
|
I64ExtendUI32 => InstructionType::Conversion,
|
||||||
I64TruncSF32 => InstructionType::Conversion,
|
|
||||||
I64TruncUF32 => InstructionType::Conversion,
|
I32TruncSF32 => InstructionType::FloatConversion,
|
||||||
I64TruncSF64 => InstructionType::Conversion,
|
I32TruncUF32 => InstructionType::FloatConversion,
|
||||||
I64TruncUF64 => InstructionType::Conversion,
|
I32TruncSF64 => InstructionType::FloatConversion,
|
||||||
F32ConvertSI32 => InstructionType::Conversion,
|
I32TruncUF64 => InstructionType::FloatConversion,
|
||||||
F32ConvertUI32 => InstructionType::Conversion,
|
I64TruncSF32 => InstructionType::FloatConversion,
|
||||||
F32ConvertSI64 => InstructionType::Conversion,
|
I64TruncUF32 => InstructionType::FloatConversion,
|
||||||
F32ConvertUI64 => InstructionType::Conversion,
|
I64TruncSF64 => InstructionType::FloatConversion,
|
||||||
F32DemoteF64 => InstructionType::Conversion,
|
I64TruncUF64 => InstructionType::FloatConversion,
|
||||||
F64ConvertSI32 => InstructionType::Conversion,
|
F32ConvertSI32 => InstructionType::FloatConversion,
|
||||||
F64ConvertUI32 => InstructionType::Conversion,
|
F32ConvertUI32 => InstructionType::FloatConversion,
|
||||||
F64ConvertSI64 => InstructionType::Conversion,
|
F32ConvertSI64 => InstructionType::FloatConversion,
|
||||||
F64ConvertUI64 => InstructionType::Conversion,
|
F32ConvertUI64 => InstructionType::FloatConversion,
|
||||||
F64PromoteF32 => InstructionType::Conversion,
|
F32DemoteF64 => InstructionType::FloatConversion,
|
||||||
|
F64ConvertSI32 => InstructionType::FloatConversion,
|
||||||
|
F64ConvertUI32 => InstructionType::FloatConversion,
|
||||||
|
F64ConvertSI64 => InstructionType::FloatConversion,
|
||||||
|
F64ConvertUI64 => InstructionType::FloatConversion,
|
||||||
|
F64PromoteF32 => InstructionType::FloatConversion,
|
||||||
|
|
||||||
I32ReinterpretF32 => InstructionType::Reinterpretation,
|
I32ReinterpretF32 => InstructionType::Reinterpretation,
|
||||||
I64ReinterpretF64 => InstructionType::Reinterpretation,
|
I64ReinterpretF64 => InstructionType::Reinterpretation,
|
||||||
@ -250,19 +262,34 @@ impl InstructionType {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Default)]
|
#[derive(Debug)]
|
||||||
pub struct Set {
|
pub struct Set {
|
||||||
entries: HashMap<InstructionType, u32>,
|
regular: u32,
|
||||||
|
entries: HashMap<InstructionType, Metering>,
|
||||||
grow: u32,
|
grow: u32,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Default for Set {
|
||||||
|
fn default() -> Self {
|
||||||
|
Set {
|
||||||
|
regular: 1,
|
||||||
|
entries: HashMap::new(),
|
||||||
|
grow: 0,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl Set {
|
impl Set {
|
||||||
pub fn new(entries: HashMap<InstructionType, u32>) -> Self {
|
pub fn new(regular: u32, entries: HashMap<InstructionType, Metering>) -> Self {
|
||||||
Set { entries: entries, grow: 0, }
|
Set { regular: regular, entries: entries, grow: 0, }
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn process(&self, opcode: &elements::Opcode) -> u32 {
|
pub fn process(&self, opcode: &elements::Opcode) -> Result<u32, ()> {
|
||||||
self.entries.get(&InstructionType::op(opcode)).map(|x| *x).unwrap_or(1)
|
match self.entries.get(&InstructionType::op(opcode)).map(|x| *x) {
|
||||||
|
None | Some(Metering::Regular) => Ok(self.regular),
|
||||||
|
Some(Metering::Forbidden) => Err(()),
|
||||||
|
Some(Metering::Fixed(val)) => Ok(val),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn grow_cost(&self) -> u32 {
|
pub fn grow_cost(&self) -> u32 {
|
||||||
@ -273,4 +300,12 @@ impl Set {
|
|||||||
self.grow = val;
|
self.grow = val;
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn with_forbidden_floats(mut self) -> Self {
|
||||||
|
self.entries.insert(InstructionType::Float, Metering::Forbidden);
|
||||||
|
self.entries.insert(InstructionType::FloatComparsion, Metering::Forbidden);
|
||||||
|
self.entries.insert(InstructionType::FloatConst, Metering::Forbidden);
|
||||||
|
self.entries.insert(InstructionType::FloatConversion, Metering::Forbidden);
|
||||||
|
self
|
||||||
|
}
|
||||||
}
|
}
|
Reference in New Issue
Block a user