extern crate dotscope;
use criterion::{criterion_group, criterion_main, Criterion};
use dotscope::assembly::{decode_stream, InstructionAssembler, InstructionEncoder};
use dotscope::metadata::token::Token;
use dotscope::Result;
use std::hint::black_box;
fn assemble_simple() -> Result<(
Vec<u8>,
u16,
Vec<dotscope::metadata::method::ExceptionHandler>,
)> {
let mut asm = InstructionAssembler::new();
asm.ldarg_1()?.ldarg_2()?.add()?.ret()?;
asm.finish()
}
fn assemble_complex() -> Result<(
Vec<u8>,
u16,
Vec<dotscope::metadata::method::ExceptionHandler>,
)> {
let mut asm = InstructionAssembler::new();
asm.ldc_i4_0()?
.stloc_0()?
.br("loop_condition")?
.label("loop_start")?
.ldarg_0()?
.ldloc_0()?
.ldarg_1()?
.stelem_i4()?
.ldloc_0()?
.ldc_i4_1()?
.add()?
.stloc_0()?
.label("loop_condition")?
.ldloc_0()?
.ldc_i4_const(10)?
.clt()?
.brtrue("loop_start")?
.ret()?;
asm.finish()
}
fn assemble_object(
field_token: Token,
method_token: Token,
) -> Result<(
Vec<u8>,
u16,
Vec<dotscope::metadata::method::ExceptionHandler>,
)> {
let mut asm = InstructionAssembler::new();
asm.ldarg_0()?
.ldfld(field_token)?
.ldnull()?
.ceq()?
.brfalse("not_null")?
.ldarg_0()?
.newobj(method_token)?
.stfld(field_token)?
.label("not_null")?
.ldarg_0()?
.ldfld(field_token)?
.callvirt(method_token)?
.ret()?;
asm.finish()
}
fn assemble_with_optimizations() -> Result<(
Vec<u8>,
u16,
Vec<dotscope::metadata::method::ExceptionHandler>,
)> {
let mut asm = InstructionAssembler::new();
asm.ldc_i4_const(0)?
.ldc_i4_const(1)?
.ldc_i4_const(127)?
.ldc_i4_const(1000)?
.add()?
.add()?
.add()?
.ret()?;
asm.finish()
}
fn assemble_manual_selection() -> Result<(
Vec<u8>,
u16,
Vec<dotscope::metadata::method::ExceptionHandler>,
)> {
let mut asm = InstructionAssembler::new();
asm.ldc_i4_0()?
.ldc_i4_1()?
.ldc_i4_s(127)?
.ldc_i4(1000)?
.add()?
.add()?
.add()?
.ret()?;
asm.finish()
}
fn assemble_large_method() -> Result<(
Vec<u8>,
u16,
Vec<dotscope::metadata::method::ExceptionHandler>,
)> {
let mut asm = InstructionAssembler::new();
for i in 0i32..50 {
asm.ldarg_0()?
.ldc_i4_const(i)?
.ceq()?
.brtrue(&format!("case_{i}"))?;
}
asm.ldc_i4_m1()?.ret()?;
for i in 0i32..50 {
asm.label(&format!("case_{i}"))?
.ldc_i4_const(i.saturating_mul(2))?
.ret()?;
}
asm.finish()
}
fn encode_simple_direct() -> Result<(Vec<u8>, u16, std::collections::HashMap<String, u32>)> {
let mut encoder = InstructionEncoder::new();
encoder.emit_instruction("ldarg.1", None)?;
encoder.emit_instruction("ldarg.2", None)?;
encoder.emit_instruction("add", None)?;
encoder.emit_instruction("ret", None)?;
encoder.finalize()
}
pub fn criterion_benchmark(c: &mut Criterion) {
c.bench_function("bench_assemble_simple_method", |b| {
b.iter(|| {
black_box(assemble_simple().ok());
});
});
c.bench_function("bench_assemble_complex_method", |b| {
b.iter(|| {
black_box(assemble_complex().ok());
});
});
c.bench_function("bench_assemble_object_method", |b| {
let field_token = Token::new(0x04000001);
let method_token = Token::new(0x06000001);
let _type_token = Token::new(0x02000001);
b.iter(|| {
black_box(assemble_object(field_token, method_token).ok());
});
});
c.bench_function("bench_assemble_encoder_direct", |b| {
b.iter(|| {
black_box(encode_simple_direct().ok());
});
});
let simple_bytecode = assemble_simple().map(|(b, _, _)| b).unwrap_or_default();
let complex_bytecode = assemble_complex().map(|(b, _, _)| b).unwrap_or_default();
c.bench_function("bench_roundtrip_simple", |b| {
b.iter(|| {
let _: Result<_> = (|| {
let (bytecode, _max_stack, _) = assemble_simple()?;
let mut parser = dotscope::Parser::new(&bytecode);
decode_stream(&mut parser, 0x1000)
})();
});
});
c.bench_function("bench_roundtrip_complex", |b| {
b.iter(|| {
let _: Result<_> = (|| {
let (bytecode, _max_stack, _) = assemble_complex()?;
let mut parser = dotscope::Parser::new(&bytecode);
decode_stream(&mut parser, 0x1000)
})();
});
});
c.bench_function("bench_disassemble_simple", |b| {
b.iter(|| {
let mut parser = dotscope::Parser::new(&simple_bytecode);
black_box(decode_stream(&mut parser, 0x1000).ok());
});
});
c.bench_function("bench_disassemble_complex", |b| {
b.iter(|| {
let mut parser = dotscope::Parser::new(&complex_bytecode);
black_box(decode_stream(&mut parser, 0x1000).ok());
});
});
c.bench_function("bench_assemble_with_optimizations", |b| {
b.iter(|| {
black_box(assemble_with_optimizations().ok());
});
});
c.bench_function("bench_assemble_manual_selection", |b| {
b.iter(|| {
black_box(assemble_manual_selection().ok());
});
});
c.bench_function("bench_assemble_large_method", |b| {
b.iter(|| {
black_box(assemble_large_method().ok());
});
});
}
criterion_group!(benches, criterion_benchmark);
criterion_main!(benches);