Skip to content

Commit c2b42c7

Browse files
committed
use same ip in decode and fetch
This resulted in ~11% performance win with direct-threading dispatch.
1 parent c912b4f commit c2b42c7

File tree

4 files changed

+55
-47
lines changed

4 files changed

+55
-47
lines changed

crates/wasmi/src/engine/executor/handler/dispatch.rs

Lines changed: 13 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -14,21 +14,19 @@ use crate::{
1414
};
1515
use core::{marker::PhantomData, ptr::NonNull};
1616

17-
pub fn fetch_handler(ip: Ip) -> (Ip, Handler) {
17+
pub fn fetch_handler(ip: Ip) -> Handler {
1818
match cfg!(feature = "compact") {
1919
true => {
20-
let (ip, op_code) = unsafe { ip.decode::<OpCode>() };
21-
let handler = op_code_to_handler(op_code);
22-
(ip, handler)
20+
let (_, op_code) = unsafe { ip.decode::<OpCode>() };
21+
op_code_to_handler(op_code)
2322
}
2423
false => {
25-
let (ip, addr) = unsafe { ip.decode::<usize>() };
26-
let handler = unsafe {
24+
let (_, addr) = unsafe { ip.decode::<usize>() };
25+
unsafe {
2726
::core::mem::transmute::<*const (), Handler>(::core::ptr::with_exposed_provenance(
2827
addr,
2928
))
30-
};
31-
(ip, handler)
29+
}
3230
}
3331
}
3432
}
@@ -167,13 +165,13 @@ fn handle_reason(reason: Option<DoneReason>) -> Result<Sp, Error> {
167165
#[cfg(feature = "trampolines")]
168166
pub fn execute_until_done(
169167
mut state: VmState,
170-
ip: Ip,
168+
mut ip: Ip,
171169
mut sp: Sp,
172170
mut mem0: *mut u8,
173171
mut mem0_len: usize,
174172
mut instance: NonNull<InstanceEntity>,
175173
) -> Option<DoneReason> {
176-
let (mut ip, mut handler) = fetch_handler(ip);
174+
let mut handler = fetch_handler(ip);
177175
'exec: loop {
178176
match handler(&mut state, ip, sp, mem0, mem0_len, instance) {
179177
Done::Continue {
@@ -183,7 +181,8 @@ pub fn execute_until_done(
183181
next_mem0_len,
184182
next_instance,
185183
} => {
186-
(ip, handler) = fetch_handler(next_ip);
184+
handler = fetch_handler(next_ip);
185+
ip = next_ip;
187186
sp = next_sp;
188187
mem0 = next_mem0;
189188
mem0_len = next_mem0_len;
@@ -206,7 +205,7 @@ pub fn execute_until_done(
206205
instance: NonNull<InstanceEntity>,
207206
) -> Option<DoneReason> {
208207
let mut state = state;
209-
let (ip, handler) = fetch_handler(ip);
208+
let handler = fetch_handler(ip);
210209
handler(&mut state, ip, sp, mem0, mem0_len, instance);
211210
state.into_done_reason()
212211
}
@@ -324,8 +323,8 @@ macro_rules! trap {
324323
#[cfg(not(feature = "trampolines"))]
325324
macro_rules! dispatch {
326325
($state:expr, $ip:expr, $sp:expr, $mem0:expr, $mem0_len:expr, $instance:expr) => {{
327-
let (ip, handler) = $crate::engine::executor::handler::dispatch::fetch_handler($ip);
328-
handler($state, ip, $sp, $mem0, $mem0_len, $instance)
326+
let handler = $crate::engine::executor::handler::dispatch::fetch_handler($ip);
327+
handler($state, $ip, $sp, $mem0, $mem0_len, $instance)
329328
}};
330329
}
331330

crates/wasmi/src/engine/executor/handler/exec.rs

Lines changed: 32 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -30,10 +30,19 @@ use crate::{
3030
errors::FuelError,
3131
func::FuncEntity,
3232
instance::InstanceEntity,
33+
ir,
3334
ir::{Slot, SlotSpan},
3435
};
3536
use core::ptr::NonNull;
3637

38+
unsafe fn decode_op<Op: ir::Decode>(ip: Ip) -> (Ip, Op) {
39+
let ip = match cfg!(feature = "compact") {
40+
true => unsafe { ip.skip::<ir::OpCode>() },
41+
false => unsafe { ip.skip::<::core::primitive::usize>() },
42+
};
43+
unsafe { ip.decode() }
44+
}
45+
3746
fn identity<T>(value: T) -> T {
3847
value
3948
}
@@ -46,7 +55,7 @@ pub fn trap(
4655
mem0_len: usize,
4756
instance: NonNull<InstanceEntity>,
4857
) -> Done {
49-
let (ip, crate::ir::decode::Trap { trap_code }) = unsafe { ip.decode() };
58+
let (ip, crate::ir::decode::Trap { trap_code }) = unsafe { decode_op(ip) };
5059
trap!(trap_code, state, ip, sp, mem0, mem0_len, instance)
5160
}
5261

@@ -58,7 +67,7 @@ pub fn consume_fuel(
5867
mem0_len: usize,
5968
instance: NonNull<InstanceEntity>,
6069
) -> Done {
61-
let (ip, crate::ir::decode::ConsumeFuel { fuel }) = unsafe { ip.decode() };
70+
let (ip, crate::ir::decode::ConsumeFuel { fuel }) = unsafe { decode_op(ip) };
6271
let consumption_result = state
6372
.store
6473
.inner_mut()
@@ -86,7 +95,7 @@ pub fn copy_span(
8695
values,
8796
len,
8897
},
89-
) = unsafe { ip.decode() };
98+
) = unsafe { decode_op(ip) };
9099
exec_copy_span(sp, results, values, len);
91100
dispatch!(state, ip, sp, mem0, mem0_len, instance)
92101
}
@@ -99,7 +108,7 @@ pub fn branch(
99108
mem0_len: usize,
100109
instance: NonNull<InstanceEntity>,
101110
) -> Done {
102-
let (_new_ip, crate::ir::decode::Branch { offset }) = unsafe { ip.decode() };
111+
let (_new_ip, crate::ir::decode::Branch { offset }) = unsafe { decode_op(ip) };
103112
let ip = offset_ip(ip, offset);
104113
dispatch!(state, ip, sp, mem0, mem0_len, instance)
105114
}
@@ -112,7 +121,7 @@ pub fn global_get(
112121
mem0_len: usize,
113122
instance: NonNull<InstanceEntity>,
114123
) -> Done {
115-
let (ip, crate::ir::decode::GlobalGet { result, global }) = unsafe { ip.decode() };
124+
let (ip, crate::ir::decode::GlobalGet { result, global }) = unsafe { decode_op(ip) };
116125
let global = resolve_global(instance, global);
117126
let value = *state.store.inner().resolve_global(&global).get_untyped();
118127
set_value(sp, result, value);
@@ -127,7 +136,7 @@ pub fn global_set(
127136
mem0_len: usize,
128137
instance: NonNull<InstanceEntity>,
129138
) -> Done {
130-
let (ip, crate::ir::decode::GlobalSet { global, value }) = unsafe { ip.decode() };
139+
let (ip, crate::ir::decode::GlobalSet { global, value }) = unsafe { decode_op(ip) };
131140
let value: UntypedVal = get_value(value, sp);
132141
set_global(global, value, state, instance);
133142
dispatch!(state, ip, sp, mem0, mem0_len, instance)
@@ -141,7 +150,7 @@ pub fn global_set_32(
141150
mem0_len: usize,
142151
instance: NonNull<InstanceEntity>,
143152
) -> Done {
144-
let (ip, crate::ir::decode::GlobalSet32 { global, value }) = unsafe { ip.decode() };
153+
let (ip, crate::ir::decode::GlobalSet32 { global, value }) = unsafe { decode_op(ip) };
145154
let value: UntypedVal = get_value(value, sp).into();
146155
set_global(global, value, state, instance);
147156
dispatch!(state, ip, sp, mem0, mem0_len, instance)
@@ -155,7 +164,7 @@ pub fn global_set_64(
155164
mem0_len: usize,
156165
instance: NonNull<InstanceEntity>,
157166
) -> Done {
158-
let (ip, crate::ir::decode::GlobalSet64 { global, value }) = unsafe { ip.decode() };
167+
let (ip, crate::ir::decode::GlobalSet64 { global, value }) = unsafe { decode_op(ip) };
159168
let value: UntypedVal = get_value(value, sp).into();
160169
set_global(global, value, state, instance);
161170
dispatch!(state, ip, sp, mem0, mem0_len, instance)
@@ -169,7 +178,7 @@ pub fn call_internal(
169178
mem0_len: usize,
170179
instance: NonNull<InstanceEntity>,
171180
) -> Done {
172-
let (caller_ip, crate::ir::decode::CallInternal { params, func }) = unsafe { ip.decode() };
181+
let (caller_ip, crate::ir::decode::CallInternal { params, func }) = unsafe { decode_op(ip) };
173182
let func = EngineFunc::from(func);
174183
let (callee_ip, size) = compile_or_get_func!(state, ip, sp, mem0, mem0_len, instance, func);
175184
let callee_sp = match state
@@ -190,7 +199,7 @@ pub fn call_imported(
190199
mem0_len: usize,
191200
instance: NonNull<InstanceEntity>,
192201
) -> Done {
193-
let (caller_ip, crate::ir::decode::CallImported { params, func }) = unsafe { ip.decode() };
202+
let (caller_ip, crate::ir::decode::CallImported { params, func }) = unsafe { decode_op(ip) };
194203
let func = resolve_func(instance, func);
195204
let func = state.store.inner().resolve_func(&func);
196205
let (callee_ip, sp, mem0, mem0_len, instance) = match func {
@@ -241,7 +250,7 @@ pub fn call_indirect(
241250
func_type,
242251
table,
243252
},
244-
) = unsafe { ip.decode() };
253+
) = unsafe { decode_op(ip) };
245254
let func = match resolve_indirect_func(index, table, func_type, state, sp, instance) {
246255
Ok(func) => func,
247256
Err(trap) => break_with_trap!(trap, state, ip, sp, mem0, mem0_len, instance),
@@ -298,7 +307,7 @@ pub fn return_span(
298307
mem0_len: usize,
299308
instance: NonNull<InstanceEntity>,
300309
) -> Done {
301-
let (_ip, crate::ir::decode::ReturnSpan { values }) = unsafe { ip.decode() };
310+
let (_ip, crate::ir::decode::ReturnSpan { values }) = unsafe { decode_op(ip) };
302311
let dst = SlotSpan::new(Slot::from(0));
303312
let src = values.span();
304313
let len = values.len();
@@ -317,7 +326,7 @@ macro_rules! handler_return {
317326
mem0_len: usize,
318327
instance: NonNull<InstanceEntity>,
319328
) -> Done {
320-
let (_ip, crate::ir::decode::$op { value }) = unsafe { ip.decode() };
329+
let (_ip, crate::ir::decode::$op { value }) = unsafe { decode_op(ip) };
321330
let value = get_value(value, sp);
322331
set_value(sp, Slot::from(0), $eval(value));
323332
exec_return!(state, sp, mem0, mem0_len, instance)
@@ -342,7 +351,7 @@ macro_rules! handler_unary {
342351
mem0_len: usize,
343352
instance: NonNull<InstanceEntity>,
344353
) -> Done {
345-
let (ip, $crate::ir::decode::$op { result, value }) = unsafe { ip.decode() };
354+
let (ip, $crate::ir::decode::$op { result, value }) = unsafe { decode_op(ip) };
346355
let value = get_value(value, sp);
347356
let value = match $eval(value).into_trap_result() {
348357
Ok(value) => value,
@@ -429,7 +438,7 @@ macro_rules! handler_binary {
429438
mem0_len: usize,
430439
instance: NonNull<InstanceEntity>,
431440
) -> Done {
432-
let (ip, $crate::ir::decode::$decode { result, lhs, rhs }) = unsafe { ip.decode() };
441+
let (ip, $crate::ir::decode::$decode { result, lhs, rhs }) = unsafe { decode_op(ip) };
433442
let lhs = get_value(lhs, sp);
434443
let rhs = get_value(rhs, sp);
435444
let value = match $eval(lhs, rhs).into_trap_result() {
@@ -676,7 +685,7 @@ macro_rules! handler_cmp_branch {
676685
mem0_len: usize,
677686
instance: NonNull<InstanceEntity>,
678687
) -> Done {
679-
let (next_ip, $crate::ir::decode::$decode { offset, lhs, rhs }) = unsafe { ip.decode() };
688+
let (next_ip, $crate::ir::decode::$decode { offset, lhs, rhs }) = unsafe { decode_op(ip) };
680689
let lhs = get_value(lhs, sp);
681690
let rhs = get_value(rhs, sp);
682691
let ip = match $eval(lhs, rhs) {
@@ -795,7 +804,7 @@ macro_rules! handler_select {
795804
lhs,
796805
rhs,
797806
},
798-
) = unsafe { ip.decode() };
807+
) = unsafe { decode_op(ip) };
799808
let lhs = get_value(lhs, sp);
800809
let rhs = get_value(rhs, sp);
801810
let src = match $eval(lhs, rhs) {
@@ -879,7 +888,7 @@ macro_rules! handler_load_ss {
879888
offset,
880889
memory,
881890
},
882-
) = unsafe { ip.decode() };
891+
) = unsafe { decode_op(ip) };
883892
let ptr: u64 = get_value(ptr, sp);
884893
let offset: u64 = get_value(offset, sp);
885894
let mem_bytes = memory_bytes(memory, mem0, mem0_len, instance, state);
@@ -926,7 +935,7 @@ macro_rules! handler_load_si {
926935
address,
927936
memory,
928937
},
929-
) = unsafe { ip.decode() };
938+
) = unsafe { decode_op(ip) };
930939
let address = get_value(address, sp);
931940
let mem_bytes = memory_bytes(memory, mem0, mem0_len, instance, state);
932941
let loaded = match $load(mem_bytes, usize::from(address)) {
@@ -972,7 +981,7 @@ macro_rules! handler_load_mem0_offset16_ss {
972981
ptr,
973982
offset,
974983
},
975-
) = unsafe { ip.decode() };
984+
) = unsafe { decode_op(ip) };
976985
let ptr = get_value(ptr, sp);
977986
let offset = get_value(offset, sp);
978987
let mem_bytes = default_memory_bytes(mem0, mem0_len);
@@ -1020,7 +1029,7 @@ macro_rules! handler_store_sx {
10201029
value,
10211030
memory,
10221031
},
1023-
) = unsafe { ip.decode() };
1032+
) = unsafe { decode_op(ip) };
10241033
let ptr = get_value(ptr, sp);
10251034
let offset = get_value(offset, sp);
10261035
let value: $hint = get_value(value, sp);
@@ -1068,7 +1077,7 @@ macro_rules! handler_store_ix {
10681077
value,
10691078
memory,
10701079
},
1071-
) = unsafe { ip.decode() };
1080+
) = unsafe { decode_op(ip) };
10721081
let address = get_value(address, sp);
10731082
let value: $hint = get_value(value, sp);
10741083
let mem_bytes = memory_bytes(memory, mem0, mem0_len, instance, state);
@@ -1115,7 +1124,7 @@ macro_rules! handler_store_mem0_offset16_sx {
11151124
offset,
11161125
value,
11171126
},
1118-
) = unsafe { ip.decode() };
1127+
) = unsafe { decode_op(ip) };
11191128
let ptr = get_value(ptr, sp);
11201129
let offset = get_value(offset, sp);
11211130
let value: $hint = get_value(value, sp);

crates/wasmi/src/engine/executor/handler/state.rs

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -89,12 +89,19 @@ impl Ip {
8989
let decoded = match <T as ir::Decode>::decode(&mut ip) {
9090
Ok(decoded) => decoded,
9191
Err(error) => unsafe {
92-
crate::engine::utils::unreachable_unchecked!("failed to decode `OpCode` or op-handler: {error}")
93-
}
92+
crate::engine::utils::unreachable_unchecked!(
93+
"failed to decode `OpCode` or op-handler: {error}"
94+
)
95+
},
9496
};
9597
(ip.0, decoded)
9698
}
9799

100+
pub unsafe fn skip<T: ir::Decode>(self) -> Ip {
101+
let (ip, _) = unsafe { self.decode::<T>() };
102+
ip
103+
}
104+
98105
pub unsafe fn offset(self, delta: isize) -> Self {
99106
let value = unsafe { self.value.byte_offset(delta) };
100107
Self { value }

crates/wasmi/src/engine/translator/func/encoder.rs

Lines changed: 1 addition & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -779,14 +779,7 @@ fn trace_branch_offset(src: BytePos, dst: Pos<Op>) -> Result<BranchOffset, Error
779779
fn trace_offset_or_none(src: BytePos, dst: BytePos) -> Option<BranchOffset> {
780780
let src = isize::try_from(usize::from(src)).ok()?;
781781
let dst = isize::try_from(usize::from(dst)).ok()?;
782-
// Offset branch-offset by op-code encoded size since
783-
// execution handlers for operations act on `ip` pointing
784-
// to the first operand instead of the op-code.
785-
let op_code = match cfg!(feature = "compact") {
786-
true => mem::size_of::<OpCode>(),
787-
false => mem::size_of::<usize>(), // direct-threading uses fn-ptr sized op-codes
788-
};
789-
let offset = dst.checked_sub(src)?.checked_sub_unsigned(op_code)?;
782+
let offset = dst.checked_sub(src)?;
790783
i32::try_from(offset).map(BranchOffset::from).ok()
791784
}
792785
let Some(offset) = trace_offset_or_none(src, BytePos::from(dst)) else {

0 commit comments

Comments
 (0)