Skip to content

Commit

Permalink
vm: Change operations to free temporaries
Browse files Browse the repository at this point in the history
  • Loading branch information
udoprog committed Jul 28, 2024
1 parent 859e39b commit a32e90a
Show file tree
Hide file tree
Showing 10 changed files with 341 additions and 215 deletions.
162 changes: 107 additions & 55 deletions crates/rune/src/compile/v1/assemble.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1170,7 +1170,7 @@ fn const_<'a, 'hir>(
span,
)?;

linear.free()?;
linear.free_non_dangling()?;
}
ConstValue::Tuple(ref tuple) => {
let mut linear = cx.scopes.linear(span, tuple.len())?;
Expand All @@ -1188,7 +1188,7 @@ fn const_<'a, 'hir>(
span,
)?;

linear.free()?;
linear.free_non_dangling()?;
}
ConstValue::Object(ref object) => {
let mut linear = cx.scopes.linear(span, object.len())?;
Expand All @@ -1213,7 +1213,7 @@ fn const_<'a, 'hir>(
span,
)?;

linear.free()?;
linear.free_non_dangling()?;
}
}

Expand Down Expand Up @@ -1644,7 +1644,7 @@ fn expr_async_block<'a, 'hir>(
&"async block",
)?;

linear.free()?;
linear.free_non_dangling()?;
Ok(Asm::new(span, ()))
}

Expand Down Expand Up @@ -1744,7 +1744,7 @@ fn expr_call<'a, 'hir>(
span,
)?;

linear.free()?;
linear.free_non_dangling()?;
}
hir::Call::Associated { target, hash } => {
let linear = converge!(exprs_2(cx, span, slice::from_ref(target), hir.args)?);
Expand All @@ -1759,7 +1759,7 @@ fn expr_call<'a, 'hir>(
span,
)?;

linear.free()?;
linear.free_non_dangling()?;
}
hir::Call::Meta { hash } => {
let linear = converge!(exprs(cx, span, hir.args)?);
Expand All @@ -1774,7 +1774,7 @@ fn expr_call<'a, 'hir>(
span,
)?;

linear.free()?;
linear.free_non_dangling()?;
}
hir::Call::Expr { expr: e } => {
let mut function = cx.scopes.defer(span);
Expand All @@ -1791,7 +1791,7 @@ fn expr_call<'a, 'hir>(
span,
)?;

linear.free()?;
linear.free_non_dangling()?;
function.free()?;
}
hir::Call::ConstFn {
Expand Down Expand Up @@ -1871,9 +1871,9 @@ fn exprs_2_with<'a, 'hir, T>(
}
([e], []) | ([], [e]) => {
let e = map(e);
let mut needs = cx.scopes.defer(e);
let mut needs = cx.scopes.alloc(e)?;
converge!(expr(cx, e, &mut needs)?, free(needs));
linear = Linear::single(needs.into_addr()?);
linear = Linear::single(needs);
}
_ => {
let len = a.len() + b.len();
Expand Down Expand Up @@ -2066,9 +2066,19 @@ fn expr_for<'a, 'hir>(
let into_iter = cx.scopes.alloc(span)?.with_name("into_iter");
let binding = cx.scopes.alloc(&hir.binding)?.with_name("binding");

// Copy the iterator, since CallAssociated will consume it.
cx.asm.push_with_comment(
Inst::CallAssociated {
Inst::Copy {
addr: iter.addr(),
out: into_iter.output(),
},
span,
&"Protocol::INTO_ITER",
)?;

cx.asm.push_with_comment(
Inst::CallAssociated {
addr: into_iter.addr(),
hash: *Protocol::INTO_ITER,
args: 1,
out: into_iter.output(),
Expand Down Expand Up @@ -2106,12 +2116,22 @@ fn expr_for<'a, 'hir>(
drop: Some(into_iter.addr()),
})?;

let into_iter_copy = cx.scopes.alloc(span)?.with_name("into_iter_copy");

cx.asm.push(
Inst::Copy {
addr: into_iter.addr(),
out: into_iter_copy.output(),
},
span,
)?;

// Use the memoized loop variable.
if let Some(next_offset) = &next_offset {
cx.asm.push(
Inst::CallFn {
function: next_offset.addr(),
addr: into_iter.addr(),
addr: into_iter_copy.addr(),
args: 1,
out: binding.output(),
},
Expand All @@ -2120,7 +2140,7 @@ fn expr_for<'a, 'hir>(
} else {
cx.asm.push_with_comment(
Inst::CallAssociated {
addr: into_iter.addr(),
addr: into_iter_copy.addr(),
hash: *Protocol::NEXT,
args: 1,
out: binding.output(),
Expand All @@ -2130,6 +2150,8 @@ fn expr_for<'a, 'hir>(
)?;
}

into_iter_copy.free()?;

// Test loop condition and unwrap the option, or jump to `end_label` if the current value is `None`.
cx.asm
.iter_next(binding.addr(), &end_label, &hir.binding, binding.output())?;
Expand Down Expand Up @@ -2534,9 +2556,9 @@ fn expr_object<'a, 'hir>(
span,
)?;
}
}
};

linear.free()?;
linear.free_non_dangling()?;
}

Ok(Asm::new(span, ()))
Expand Down Expand Up @@ -2601,58 +2623,83 @@ fn expr_range<'a, 'hir>(
span: &'hir dyn Spanned,
needs: &mut dyn Needs<'a, 'hir>,
) -> compile::Result<Asm<'hir>> {
let a: Option<&hir::Expr<'hir>>;
let b: Option<&hir::Expr<'hir>>;
let range;
let vars;

let range = match hir {
match hir {
hir::ExprRange::RangeFrom { start } => {
a = Some(start);
b = None;
InstRange::RangeFrom
let mut s = cx.scopes.defer(start);
converge!(expr(cx, start, &mut s)?, free(s));

let start = s.into_addr()?;

range = InstRange::RangeFrom {
start: start.addr(),
};
vars = [Some(start), None];
}
hir::ExprRange::RangeFull => {
a = None;
b = None;
InstRange::RangeFull
range = InstRange::RangeFull;
vars = [None, None];
}
hir::ExprRange::RangeInclusive { start, end } => {
a = Some(start);
b = Some(end);
InstRange::RangeInclusive
let mut s = cx.scopes.defer(start);
converge!(expr(cx, start, &mut s)?, free(s));

let mut e = cx.scopes.defer(end);
converge!(expr(cx, end, &mut e)?, free(s, e));

let start = s.into_addr()?;
let end = e.into_addr()?;

range = InstRange::RangeInclusive {
start: start.addr(),
end: end.addr(),
};
vars = [Some(start), Some(end)];
}
hir::ExprRange::RangeToInclusive { end } => {
a = Some(end);
b = None;
InstRange::RangeToInclusive
let mut e = cx.scopes.defer(end);
converge!(expr(cx, end, &mut e)?, free(e));

let end = e.into_addr()?;

range = InstRange::RangeToInclusive { end: end.addr() };
vars = [Some(end), None];
}
hir::ExprRange::RangeTo { end } => {
a = Some(end);
b = None;
InstRange::RangeTo
let mut e = cx.scopes.defer(end);
converge!(expr(cx, end, &mut e)?, free(e));

let end = e.into_addr()?;

range = InstRange::RangeTo { end: end.addr() };
vars = [Some(end), None];
}
hir::ExprRange::Range { start, end } => {
a = Some(start);
b = Some(end);
InstRange::Range
}
};
let mut s = cx.scopes.defer(start);
converge!(expr(cx, start, &mut s)?, free(s));

let a = a.map(slice::from_ref).unwrap_or_default();
let b = b.map(slice::from_ref).unwrap_or_default();
let mut e = cx.scopes.defer(end);
converge!(expr(cx, end, &mut e)?, free(s, e));

if let Some(linear) = exprs_2(cx, span, a, b)?.into_converging() {
if let Some(out) = needs.try_alloc_output()? {
cx.asm.push(
Inst::Range {
addr: linear.addr(),
range,
out,
},
span,
)?;
let start = s.into_addr()?;
let end = e.into_addr()?;

range = InstRange::Range {
start: start.addr(),
end: end.addr(),
};
vars = [Some(start), Some(end)];
}
};

linear.free()?;
if let Some(out) = needs.try_alloc_output()? {
cx.asm.push(Inst::Range { range, out }, span)?;
}

for var in vars.into_iter().flatten() {
var.free()?;
}

Ok(Asm::new(span, ()))
Expand Down Expand Up @@ -2829,7 +2876,7 @@ fn expr_tuple<'a, 'hir>(

cx.asm.push(
Inst::$variant {
args: [$($expr.addr(),)*],
addr: [$($expr.addr(),)*],
out: needs.alloc_output()?,
},
span,
Expand Down Expand Up @@ -2859,9 +2906,11 @@ fn expr_tuple<'a, 'hir>(
},
span,
)?;
}

linear.free()?;
linear.free_non_dangling()?;
} else {
linear.free()?;
}
}
}

Expand Down Expand Up @@ -2936,9 +2985,12 @@ fn expr_vec<'a, 'hir>(
},
span,
)?;

linear.free_non_dangling()?;
} else {
linear.free()?;
}

linear.free()?;
Ok(Asm::new(span, ()))
}

Expand Down
9 changes: 9 additions & 0 deletions crates/rune/src/compile/v1/linear.rs
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,15 @@ impl<'a, 'hir> Linear<'a, 'hir> {
Ok(())
}

#[inline]
pub(super) fn free_non_dangling(self) -> compile::Result<()> {
for addr in self.into_iter().rev() {
addr.free_non_dangling()?;
}

Ok(())
}

#[inline]
pub(super) fn forget(self) -> compile::Result<()> {
for var in self {
Expand Down
16 changes: 13 additions & 3 deletions crates/rune/src/compile/v1/needs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -290,15 +290,25 @@ impl<'a, 'hir> Address<'a, 'hir> {
Ok(())
}

pub(super) fn free(self) -> compile::Result<()> {
self.free_inner(true)
}

pub(super) fn free_non_dangling(self) -> compile::Result<()> {
self.free_inner(false)
}

/// Free the current address.
pub(super) fn free(mut self) -> compile::Result<()> {
fn free_inner(mut self, dangling: bool) -> compile::Result<()> {
match replace(&mut self.kind, AddressKind::Freed) {
AddressKind::Local | AddressKind::Dangling => {
self.scopes.free_addr(self.span, self.address, self.name)?;
self.scopes
.free_addr(self.span, self.address, self.name, dangling)?;
}
AddressKind::Scope(scope) => {
if self.scopes.top_id() == scope {
self.scopes.free_addr(self.span, self.address, self.name)?;
self.scopes
.free_addr(self.span, self.address, self.name, dangling)?;
}
}
AddressKind::Freed => {
Expand Down
5 changes: 4 additions & 1 deletion crates/rune/src/compile/v1/scopes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -421,6 +421,7 @@ impl<'hir> Scopes<'hir> {
span: &dyn Spanned,
addr: InstAddress,
name: Option<&'static str>,
dangling: bool,
) -> compile::Result<()> {
let mut scopes = self.scopes.borrow_mut();

Expand All @@ -447,7 +448,9 @@ impl<'hir> Scopes<'hir> {
));
}

self.dangling.borrow_mut().insert(addr).with_span(span)?;
if dangling {
self.dangling.borrow_mut().insert(addr).with_span(span)?;
}

let mut slots = self.slots.borrow_mut();

Expand Down
Loading

0 comments on commit a32e90a

Please sign in to comment.