Skip to content

Commit

Permalink
rune: Optimize value dropping
Browse files Browse the repository at this point in the history
  • Loading branch information
udoprog committed Nov 5, 2024
1 parent aa45a38 commit cdcf862
Show file tree
Hide file tree
Showing 13 changed files with 291 additions and 180 deletions.
30 changes: 24 additions & 6 deletions crates/rune/src/cli/run.rs
Original file line number Diff line number Diff line change
Expand Up @@ -181,6 +181,8 @@ pub(super) async fn run(

let mut functions = unit.iter_functions().peekable();
let mut strings = unit.iter_static_strings().peekable();
let mut bytes = unit.iter_static_bytes().peekable();
let mut drop_sets = unit.iter_static_drop_sets().peekable();
let mut keys = unit.iter_static_object_keys().peekable();
let mut constants = unit.iter_constants().peekable();

Expand All @@ -199,16 +201,16 @@ pub(super) async fn run(
if strings.peek().is_some() {
writeln!(io.stdout, "# strings")?;

for string in strings {
writeln!(io.stdout, "{} = {:?}", string.hash(), string)?;
for (i, string) in strings.enumerate() {
writeln!(io.stdout, "{i} = {string:?}")?;
}
}

if args.dump_constants && constants.peek().is_some() {
writeln!(io.stdout, "# constants")?;
if bytes.peek().is_some() {
writeln!(io.stdout, "# bytes")?;

for constant in constants {
writeln!(io.stdout, "{} = {:?}", constant.0, constant.1)?;
for (i, bytes) in bytes.enumerate() {
writeln!(io.stdout, "{i} = {bytes:?}")?;
}
}

Expand All @@ -219,6 +221,22 @@ pub(super) async fn run(
writeln!(io.stdout, "{} = {:?}", hash, keys)?;
}
}

if drop_sets.peek().is_some() {
writeln!(io.stdout, "# drop sets")?;

for (i, set) in drop_sets.enumerate() {
writeln!(io.stdout, "{i} = {set:?}")?;
}
}

if args.dump_constants && constants.peek().is_some() {
writeln!(io.stdout, "# constants")?;

for (hash, constant) in constants {
writeln!(io.stdout, "{hash} = {constant:?}")?;
}
}
}

let runtime = Arc::new(context.runtime()?);
Expand Down
50 changes: 48 additions & 2 deletions crates/rune/src/compile/unit_builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,8 @@ use crate::query::QueryInner;
use crate::runtime::debug::{DebugArgs, DebugSignature};
use crate::runtime::unit::UnitEncoder;
use crate::runtime::{
Call, ConstValue, DebugInfo, DebugInst, Inst, Label, Protocol, Rtti, RttiKind, StaticString,
Unit, UnitFn,
Call, ConstValue, DebugInfo, DebugInst, Inst, InstAddress, Label, Protocol, Rtti, RttiKind,
StaticString, Unit, UnitFn,
};
use crate::{Context, Diagnostics, Hash, Item, SourceId};

Expand Down Expand Up @@ -72,6 +72,10 @@ pub(crate) struct UnitBuilder {
static_object_keys: Vec<Box<[String]>>,
/// Used to detect duplicates in the collection of static object keys.
static_object_keys_rev: HashMap<Hash, usize>,
/// A static string.
drop_sets: Vec<Arc<[InstAddress]>>,
/// Reverse lookup for drop sets.
drop_sets_rev: HashMap<Vec<InstAddress>, usize>,
/// Runtime type information for types.
rtti: hash::Map<Arc<Rtti>>,
/// The current label count.
Expand All @@ -87,6 +91,14 @@ pub(crate) struct UnitBuilder {
}

impl UnitBuilder {
/// Construct a new drop set.
pub(crate) fn drop_set(&mut self) -> DropSet<'_> {
DropSet {
builder: self,
addresses: Vec::new(),
}
}

/// Insert an identifier for debug purposes.
pub(crate) fn insert_debug_ident(&mut self, ident: &str) -> alloc::Result<()> {
self.hash_to_ident
Expand Down Expand Up @@ -150,6 +162,7 @@ impl UnitBuilder {
self.static_strings,
self.static_bytes,
self.static_object_keys,
self.drop_sets,
self.rtti,
self.debug,
self.constants,
Expand Down Expand Up @@ -914,3 +927,36 @@ impl UnitBuilder {
Ok(())
}
}

/// A set of addresses that should be dropped.
pub(crate) struct DropSet<'a> {
builder: &'a mut UnitBuilder,
addresses: Vec<InstAddress>,
}

impl DropSet<'_> {
/// Construct a new drop set.
pub(crate) fn push(&mut self, addr: InstAddress) -> alloc::Result<()> {
self.addresses.try_push(addr)
}

pub(crate) fn finish(self) -> alloc::Result<Option<usize>> {
if self.addresses.is_empty() {
return Ok(None);
}

if let Some(set) = self.builder.drop_sets_rev.get(&self.addresses) {
return Ok(Some(*set));
}

let set = self.builder.drop_sets.len();

self.builder
.drop_sets_rev
.try_insert(self.addresses.try_clone()?, set)?;
self.builder
.drop_sets
.try_push(Arc::from(&self.addresses[..]))?;
Ok(Some(set))
}
}
36 changes: 27 additions & 9 deletions crates/rune/src/compile/v1/assemble.rs
Original file line number Diff line number Diff line change
Expand Up @@ -75,8 +75,14 @@ impl<'a, 'hir, 'arena> Ctxt<'a, 'hir, 'arena> {
.drain_dangling_into(&mut self.drop)
.with_span(span)?;

let mut drop_set = self.q.unit.drop_set();

for addr in self.drop.drain(..).rev() {
self.asm.push(Inst::Drop { addr }, span)?;
drop_set.push(addr)?;
}

if let Some(set) = drop_set.finish()? {
self.asm.push(Inst::Drop { set }, span)?;
}

Ok(())
Expand Down Expand Up @@ -1738,9 +1744,15 @@ fn expr_break<'hir>(
cx.asm.push(Inst::unit(out), span)?;
}

let mut drop_set = cx.q.unit.drop_set();

// Drop loop temporaries.
for addr in cx.drop.drain(..) {
cx.asm.push(Inst::Drop { addr }, span)?;
drop_set.push(addr)?;
}

if let Some(set) = drop_set.finish()? {
cx.asm.push(Inst::Drop { set }, span)?;
}

cx.asm.jump(&break_label, span)?;
Expand Down Expand Up @@ -2217,15 +2229,15 @@ fn expr_for<'a, 'hir>(

cx.asm.label(&end_label)?;

let mut drop_set = cx.q.unit.drop_set();
drop_set.push(into_iter.addr())?;

// NB: Dropping has to happen before the break label. When breaking,
// the break statement is responsible for ensuring that active
// iterators are dropped.
cx.asm.push(
Inst::Drop {
addr: into_iter.addr(),
},
span,
)?;
if let Some(set) = drop_set.finish()? {
cx.asm.push(Inst::Drop { set }, span)?;
}

cx.asm.label(&break_label)?;

Expand Down Expand Up @@ -2820,9 +2832,15 @@ fn expr_select_inner<'a, 'hir>(

cx.asm.label(&end_label)?;

let mut drop_set = cx.q.unit.drop_set();

// Drop futures we are currently using.
for addr in &linear {
cx.asm.push(Inst::Drop { addr: addr.addr() }, span)?;
drop_set.push(addr.addr())?;
}

if let Some(set) = drop_set.finish()? {
cx.asm.push(Inst::Drop { set }, span)?;
}

value_addr.free()?;
Expand Down
13 changes: 3 additions & 10 deletions crates/rune/src/runtime/inst.rs
Original file line number Diff line number Diff line change
Expand Up @@ -414,18 +414,11 @@ pub enum Inst {
/// Where the value is being moved to.
out: Output,
},
/// Drop the value in the given frame offset, cleaning out it's slot in
/// memory.
///
/// # Operation
///
/// ```text
/// => *noop*
/// ```
/// Drop the given value set.
#[musli(packed)]
Drop {
/// Address of the value being dropped.
addr: InstAddress,
/// An indicator of the set of addresses to drop.
set: usize,
},
/// Swap two values on the stack using their offsets relative to the current
/// stack frame.
Expand Down
8 changes: 4 additions & 4 deletions crates/rune/src/runtime/protocol_caller.rs
Original file line number Diff line number Diff line change
Expand Up @@ -66,19 +66,19 @@ impl ProtocolCaller for EnvProtocolCaller {
args: expected,
call,
..
}) = unit.function(hash)
}) = unit.function(&hash)
{
vm_try!(check_args(count, expected));
vm_try!(check_args(count, *expected));

let mut stack = vm_try!(Stack::with_capacity(count));
vm_try!(stack.push(target));
vm_try!(args.push_to_stack(&mut stack));
let mut vm = Vm::with_stack(context.clone(), unit.clone(), stack);
vm.set_ip(offset);
vm.set_ip(*offset);
return VmResult::Ok(CallResultOnly::Ok(vm_try!(call.call_with_vm(vm))));
}

if let Some(handler) = context.function(hash) {
if let Some(handler) = context.function(&hash) {
let mut stack = vm_try!(Stack::with_capacity(count));
let addr = stack.addr();
vm_try!(stack.push(target));
Expand Down
15 changes: 9 additions & 6 deletions crates/rune/src/runtime/runtime_context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -42,18 +42,21 @@ impl RuntimeContext {
}

/// Lookup the given native function handler in the context.
pub fn function(&self, hash: Hash) -> Option<&Arc<FunctionHandler>> {
self.functions.get(&hash)
#[inline]
pub fn function(&self, hash: &Hash) -> Option<&Arc<FunctionHandler>> {
self.functions.get(hash)
}

/// Read a constant value.
pub fn constant(&self, hash: Hash) -> Option<&ConstValue> {
self.constants.get(&hash)
#[inline]
pub fn constant(&self, hash: &Hash) -> Option<&ConstValue> {
self.constants.get(hash)
}

/// Read a constant constructor.
pub(crate) fn construct(&self, hash: Hash) -> Option<&dyn ConstConstruct> {
Some(&**self.construct.get(&hash)?)
#[inline]
pub(crate) fn construct(&self, hash: &Hash) -> Option<&dyn ConstConstruct> {
Some(&**self.construct.get(hash)?)
}
}

Expand Down
Loading

0 comments on commit cdcf862

Please sign in to comment.