use super::Schedule;
use alloc::vec::Vec;
use gwasm_instrument::{
gas_metering::{ConstantCostRules, MemoryGrowCost, Rules},
parity_wasm::elements::{self, Instruction, Module, SignExtInstruction, Type},
};
pub struct CustomConstantCostRules {
constant_cost_rules: ConstantCostRules,
}
impl CustomConstantCostRules {
pub fn new(instruction_cost: u32, memory_grow_cost: u32, call_per_local_cost: u32) -> Self {
Self {
constant_cost_rules: ConstantCostRules::new(
instruction_cost,
memory_grow_cost,
call_per_local_cost,
),
}
}
}
impl Default for CustomConstantCostRules {
fn default() -> Self {
Self {
constant_cost_rules: ConstantCostRules::new(1, 0, 1),
}
}
}
impl Rules for CustomConstantCostRules {
fn instruction_cost(&self, instruction: &Instruction) -> Option<u32> {
use self::elements::Instruction::*;
match *instruction {
End
| Unreachable
| Return
| Else
| Block(_)
| Loop(_)
| Nop
| Drop
| I32Const(_)
| I64Const(_)
| I32Load(_, _)
| I32Load8S(_, _)
| I32Load8U(_, _)
| I32Load16S(_, _)
| I32Load16U(_, _)
| I64Load(_, _)
| I64Load8S(_, _)
| I64Load8U(_, _)
| I64Load16S(_, _)
| I64Load16U(_, _)
| I64Load32S(_, _)
| I64Load32U(_, _)
| I32Store(_, _)
| I32Store8(_, _)
| I32Store16(_, _)
| I64Store(_, _)
| I64Store8(_, _)
| I64Store16(_, _)
| I64Store32(_, _)
| Select
| If(_)
| Br(_)
| BrIf(_)
| Call(_)
| GetLocal(_)
| SetLocal(_)
| TeeLocal(_)
| GetGlobal(_)
| SetGlobal(_)
| CurrentMemory(_)
| CallIndirect(_, _)
| BrTable(_)
| I32Clz
| I64Clz
| I32Ctz
| I64Ctz
| I32Popcnt
| I64Popcnt
| I32Eqz
| I64Eqz
| I64ExtendSI32
| I64ExtendUI32
| I32WrapI64
| I32Eq
| I64Eq
| I32Ne
| I64Ne
| I32LtS
| I64LtS
| I32LtU
| I64LtU
| I32GtS
| I64GtS
| I32GtU
| I64GtU
| I32LeS
| I64LeS
| I32LeU
| I64LeU
| I32GeS
| I64GeS
| I32GeU
| I64GeU
| I32Add
| I64Add
| I32Sub
| I64Sub
| I32Mul
| I64Mul
| I32DivS
| I64DivS
| I32DivU
| I64DivU
| I32RemS
| I64RemS
| I32RemU
| I64RemU
| I32And
| I64And
| I32Or
| I64Or
| I32Xor
| I64Xor
| I32Shl
| I64Shl
| I32ShrS
| I64ShrS
| I32ShrU
| I64ShrU
| I32Rotl
| I64Rotl
| I32Rotr
| I64Rotr
| SignExt(_) => Some(self.constant_cost_rules.instruction_cost(instruction)?),
_ => None,
}
}
fn memory_grow_cost(&self) -> MemoryGrowCost {
self.constant_cost_rules.memory_grow_cost()
}
fn call_per_local_cost(&self) -> u32 {
self.constant_cost_rules.call_per_local_cost()
}
}
pub struct ScheduleRules<'a> {
schedule: &'a Schedule,
params: Vec<u32>,
}
impl Schedule {
pub fn rules(&self, module: &Module) -> impl Rules + '_ {
ScheduleRules {
schedule: self,
params: module
.type_section()
.iter()
.flat_map(|section| section.types())
.map(|func| {
let Type::Function(func) = func;
func.params().len() as u32
})
.collect(),
}
}
}
impl<'a> Rules for ScheduleRules<'a> {
fn instruction_cost(&self, instruction: &Instruction) -> Option<u32> {
use Instruction::*;
use SignExtInstruction::*;
let w = &self.schedule.instruction_weights;
let max_params = self.schedule.limits.parameters;
let weight = match *instruction {
End | Unreachable | Return | Else | Block(_) | Loop(_) | Nop | Drop => 0,
I32Const(_) | I64Const(_) => w.i64const,
I32Load(_, _)
| I32Load8S(_, _)
| I32Load8U(_, _)
| I32Load16S(_, _)
| I32Load16U(_, _) => w.i32load,
I64Load(_, _)
| I64Load8S(_, _)
| I64Load8U(_, _)
| I64Load16S(_, _)
| I64Load16U(_, _)
| I64Load32S(_, _)
| I64Load32U(_, _) => w.i64load,
I32Store(_, _) | I32Store8(_, _) | I32Store16(_, _) => w.i32store,
I64Store(_, _) | I64Store8(_, _) | I64Store16(_, _) | I64Store32(_, _) => w.i64store,
Select => w.select,
If(_) => w.r#if,
Br(_) => w.br,
BrIf(_) => w.br_if,
Call(_) => w.call,
GetLocal(_) => w.local_get,
SetLocal(_) => w.local_set,
TeeLocal(_) => w.local_tee,
GetGlobal(_) => w.global_get,
SetGlobal(_) => w.global_set,
CurrentMemory(_) => w.memory_current,
CallIndirect(idx, _) => *self.params.get(idx as usize).unwrap_or(&max_params),
BrTable(ref data) => w
.br_table
.saturating_add(w.br_table_per_entry.saturating_mul(data.table.len() as u32)),
I32Clz => w.i32clz,
I64Clz => w.i64clz,
I32Ctz => w.i32ctz,
I64Ctz => w.i64ctz,
I32Popcnt => w.i32popcnt,
I64Popcnt => w.i64popcnt,
I32Eqz => w.i32eqz,
I64Eqz => w.i64eqz,
I64ExtendSI32 => w.i64extendsi32,
I64ExtendUI32 => w.i64extendui32,
I32WrapI64 => w.i32wrapi64,
I32Eq => w.i32eq,
I64Eq => w.i64eq,
I32Ne => w.i32ne,
I64Ne => w.i64ne,
I32LtS => w.i32lts,
I64LtS => w.i64lts,
I32LtU => w.i32ltu,
I64LtU => w.i64ltu,
I32GtS => w.i32gts,
I64GtS => w.i64gts,
I32GtU => w.i32gtu,
I64GtU => w.i64gtu,
I32LeS => w.i32les,
I64LeS => w.i64les,
I32LeU => w.i32leu,
I64LeU => w.i64leu,
I32GeS => w.i32ges,
I64GeS => w.i64ges,
I32GeU => w.i32geu,
I64GeU => w.i64geu,
I32Add => w.i32add,
I64Add => w.i64add,
I32Sub => w.i32sub,
I64Sub => w.i64sub,
I32Mul => w.i32mul,
I64Mul => w.i64mul,
I32DivS => w.i32divs,
I64DivS => w.i64divs,
I32DivU => w.i32divu,
I64DivU => w.i64divu,
I32RemS => w.i32rems,
I64RemS => w.i64rems,
I32RemU => w.i32remu,
I64RemU => w.i64remu,
I32And => w.i32and,
I64And => w.i64and,
I32Or => w.i32or,
I64Or => w.i64or,
I32Xor => w.i32xor,
I64Xor => w.i64xor,
I32Shl => w.i32shl,
I64Shl => w.i64shl,
I32ShrS => w.i32shrs,
I64ShrS => w.i64shrs,
I32ShrU => w.i32shru,
I64ShrU => w.i64shru,
I32Rotl => w.i32rotl,
I64Rotl => w.i64rotl,
I32Rotr => w.i32rotr,
I64Rotr => w.i64rotr,
SignExt(ref s) => match s {
I32Extend8S => w.i32extend8s,
I32Extend16S => w.i32extend16s,
I64Extend8S => w.i64extend8s,
I64Extend16S => w.i64extend16s,
I64Extend32S => w.i64extend32s,
},
_ => return None,
};
Some(weight)
}
fn memory_grow_cost(&self) -> MemoryGrowCost {
MemoryGrowCost::Free
}
fn call_per_local_cost(&self) -> u32 {
self.schedule.instruction_weights.call_per_local
}
}