Skip to content

Commit

Permalink
Avoid hash lookup for intra-unit calls
Browse files Browse the repository at this point in the history
  • Loading branch information
udoprog committed Aug 21, 2023
1 parent cf5f746 commit b8fd316
Show file tree
Hide file tree
Showing 4 changed files with 46 additions and 4 deletions.
22 changes: 20 additions & 2 deletions crates/rune/src/compile/unit_builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -575,7 +575,6 @@ impl UnitBuilder {
);

self.debug_info_mut().functions.insert(hash, signature);

self.add_assembly(location, assembly, unit_encoder)?;
Ok(())
}
Expand Down Expand Up @@ -833,7 +832,26 @@ impl UnitBuilder {
.with_span(span)?;
}
AssemblyInst::Raw { raw } => {
storage.encode(raw).with_span(span)?;
// Optimization to avoid performing lookups for recursive
// function calls.
let inst = match raw {
inst @ Inst::Call { hash, args } => {
if let Some(UnitFn::Offset { offset, call, .. }) =
self.functions.get(&hash)
{
Inst::CallOffset {
offset: *offset,
call: *call,
args,
}
} else {
inst
}
}
inst => inst,
};

storage.encode(inst).with_span(span)?;
}
}

Expand Down
3 changes: 2 additions & 1 deletion crates/rune/src/runtime/call.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
use core::fmt;

use musli::{Decode, Encode};
use serde::{Deserialize, Serialize};

use crate::runtime::{Future, Generator, Stream, Value, Vm, VmResult};

/// The calling convention of a function.
#[derive(Debug, Clone, Copy, Serialize, Deserialize)]
#[derive(Debug, Clone, Copy, Serialize, Deserialize, Encode, Decode)]
#[non_exhaustive]
pub enum Call {
/// Function is `async` and returns a future that must be await:ed to make
Expand Down
15 changes: 14 additions & 1 deletion crates/rune/src/runtime/inst.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ use musli::{Decode, Encode};
use rune_macros::InstDisplay;
use serde::{Deserialize, Serialize};

use crate::runtime::{FormatSpec, Type, Value};
use crate::runtime::{Call, FormatSpec, Type, Value};
use crate::Hash;

/// Pre-canned panic reasons.
Expand Down Expand Up @@ -125,6 +125,19 @@ pub enum Inst {
/// The number of arguments to store in the environment on the stack.
count: usize,
},
/// Perform a function call within the same unit.
///
/// It will construct a new stack frame which includes the last `args`
/// number of entries.
#[musli(packed)]
CallOffset {
/// The offset of the function being called in the same unit.
offset: usize,
/// The calling convention to use.
call: Call,
/// The number of arguments expected on the stack for this call.
args: usize,
},
/// Perform a function call.
///
/// It will construct a new stack frame which includes the last `args`
Expand Down
10 changes: 10 additions & 0 deletions crates/rune/src/runtime/vm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2907,6 +2907,13 @@ impl Vm {
VmResult::Ok(())
}

/// Call a function at the given offset with the given number of arguments.
#[cfg_attr(feature = "bench", inline(never))]
fn op_call_offset(&mut self, offset: usize, call: Call, args: usize) -> VmResult<()> {
vm_try!(self.call_offset_fn(offset, call, args));
VmResult::Ok(())
}

#[cfg_attr(feature = "bench", inline(never))]
fn op_call_associated(&mut self, hash: Hash, args: usize) -> VmResult<()> {
// NB: +1 to include the instance itself.
Expand Down Expand Up @@ -3060,6 +3067,9 @@ impl Vm {
Inst::Call { hash, args } => {
vm_try!(self.op_call(hash, args));
}
Inst::CallOffset { offset, call, args } => {
vm_try!(self.op_call_offset(offset, call, args));
}
Inst::CallAssociated { hash, args } => {
vm_try!(self.op_call_associated(hash, args));
}
Expand Down

0 comments on commit b8fd316

Please sign in to comment.