diff --git a/crates/rune/src/compile/assembly.rs b/crates/rune/src/compile/assembly.rs index 230463e8d..a0198578c 100644 --- a/crates/rune/src/compile/assembly.rs +++ b/crates/rune/src/compile/assembly.rs @@ -24,11 +24,6 @@ pub(crate) enum AssemblyInst { addr: InstAddress, label: Label, }, - JumpIfBranch { - addr: InstAddress, - branch: i64, - label: Label, - }, IterNext { addr: InstAddress, label: Label, @@ -143,26 +138,6 @@ impl Assembly { Ok(()) } - /// Add a conditional jump-if-branch instruction. - pub(crate) fn jump_if_branch( - &mut self, - addr: InstAddress, - branch: i64, - label: &Label, - span: &dyn Spanned, - ) -> compile::Result<()> { - self.inner_push( - AssemblyInst::JumpIfBranch { - addr, - branch, - label: label.try_clone()?, - }, - span, - )?; - - Ok(()) - } - /// Add an instruction that advanced an iterator. pub(crate) fn iter_next( &mut self, diff --git a/crates/rune/src/compile/unit_builder.rs b/crates/rune/src/compile/unit_builder.rs index 3641d97c0..20aef4126 100644 --- a/crates/rune/src/compile/unit_builder.rs +++ b/crates/rune/src/compile/unit_builder.rs @@ -857,29 +857,6 @@ impl UnitBuilder { .encode(Inst::JumpIfNot { cond: addr, jump }) .with_span(span)?; } - AssemblyInst::JumpIfBranch { - addr, - branch, - label, - } => { - let jump = label - .jump() - .ok_or(ErrorKind::MissingLabelLocation { - name: label.name, - index: label.index, - }) - .with_span(span)?; - - write!(comment, "label:{}", label)?; - - storage - .encode(Inst::JumpIfBranch { - branch: addr, - value: branch, - jump, - }) - .with_span(span)?; - } AssemblyInst::IterNext { addr, label, out } => { let jump = label .jump() diff --git a/crates/rune/src/compile/v1/assemble.rs b/crates/rune/src/compile/v1/assemble.rs index 49a57ac97..7c2155a10 100644 --- a/crates/rune/src/compile/v1/assemble.rs +++ b/crates/rune/src/compile/v1/assemble.rs @@ -1,4 +1,5 @@ use core::fmt; +use core::mem::take; use core::slice; use crate::alloc::prelude::*; @@ -2683,7 +2684,6 @@ fn expr_select_inner<'a, 'hir>( let linear = converge!(exprs(cx, span, hir.exprs)?); - let branch_addr = cx.scopes.alloc(span)?; let mut value_addr = cx.scopes.alloc(span)?; let select_label = cx.asm.new_label("select"); @@ -2693,19 +2693,15 @@ fn expr_select_inner<'a, 'hir>( Inst::Select { addr: linear.addr(), len: hir.exprs.len(), - branch: branch_addr.output(), value: value_addr.output(), }, span, )?; - for (branch, (label, _)) in cx.select_branches.iter().enumerate() { - cx.asm - .jump_if_branch(branch_addr.addr(), branch as i64, label, span)?; + for (label, _) in &cx.select_branches { + cx.asm.jump(label, span)?; } - branch_addr.free()?; - if let Some((_, label)) = &default_branch { cx.asm.jump(label, span)?; } else { @@ -2719,10 +2715,12 @@ fn expr_select_inner<'a, 'hir>( )?; } - cx.asm.jump(&end_label, span)?; + if !cx.select_branches.is_empty() || default_branch.is_some() { + cx.asm.jump(&end_label, span)?; + } } - let mut branches = core::mem::take(&mut cx.select_branches); + let mut branches = take(&mut cx.select_branches); for (label, branch) in branches.drain(..) { cx.asm.label(&label)?; diff --git a/crates/rune/src/runtime/awaited.rs b/crates/rune/src/runtime/awaited.rs index 011828da8..137730077 100644 --- a/crates/rune/src/runtime/awaited.rs +++ b/crates/rune/src/runtime/awaited.rs @@ -6,7 +6,7 @@ pub(crate) enum Awaited { /// A future to be awaited. Future(Future, Output), /// A select to be awaited. - Select(Select, Output, Output), + Select(Select, Output), } impl Awaited { @@ -17,9 +17,9 @@ impl Awaited { let value = vm_try!(future.await.with_vm(vm)); vm_try!(out.store(vm.stack_mut(), value)); } - Self::Select(select, branch_addr, value_addr) => { - let (branch, value) = vm_try!(select.await.with_vm(vm)); - vm_try!(branch_addr.store(vm.stack_mut(), || branch)); + Self::Select(select, value_addr) => { + let (ip, value) = vm_try!(select.await.with_vm(vm)); + vm.set_ip(ip); vm_try!(value_addr.store(vm.stack_mut(), || value)); } } diff --git a/crates/rune/src/runtime/inst.rs b/crates/rune/src/runtime/inst.rs index e0d581a49..3ec87b7b4 100644 --- a/crates/rune/src/runtime/inst.rs +++ b/crates/rune/src/runtime/inst.rs @@ -364,27 +364,20 @@ pub enum Inst { /// Whether the produced value from the await should be kept or not. out: Output, }, - /// Select over `len` futures on the stack. Sets the `branch` register to - /// the index of the branch that completed. And pushes its value on the - /// stack. - /// - /// This operation will block the VM until at least one of the underlying - /// futures complete. + /// Select over `len` futures stored at address `addr`. /// - /// # Operation + /// Once a branch has been matched, will store the branch that matched in + /// the branch register and perform a jump by the index of the branch that + /// matched. /// - /// ```text - /// - /// => - /// ``` + /// Will also store the output if the future into `value`. If no branch + /// matched, the empty value will be stored. #[musli(packed)] Select { /// The base address of futures being waited on. addr: InstAddress, /// The number of futures to poll. len: usize, - /// Where to store the branch value. - branch: Output, /// Where to store the value produced by the future that completed. value: Output, }, @@ -517,24 +510,6 @@ pub enum Inst { /// The offset to jump if the condition is true. jump: usize, }, - /// Compares the `branch` register with the top of the stack, and if they - /// match pops the top of the stack and performs the jump to offset. - /// - /// # Operation - /// - /// ```text - /// - /// => *nothing* - /// ``` - #[musli(packed)] - JumpIfBranch { - /// Where the branch value is stored. - branch: InstAddress, - /// The branch value to compare against. - value: i64, - /// The offset to jump. - jump: usize, - }, /// Construct a push a vector value onto the stack. The number of elements /// in the vector are determined by `count` and are popped from the stack. /// diff --git a/crates/rune/src/runtime/select.rs b/crates/rune/src/runtime/select.rs index f55fe2f27..c08370e68 100644 --- a/crates/rune/src/runtime/select.rs +++ b/crates/rune/src/runtime/select.rs @@ -11,18 +11,18 @@ use crate::runtime::{Future, Mut, Value, VmResult}; /// A stored select. #[derive(Debug)] pub struct Select { - futures: FuturesUnordered>>, + futures: FuturesUnordered>>, } impl Select { /// Construct a new stored select. - pub(crate) fn new(futures: FuturesUnordered>>) -> Self { + pub(crate) fn new(futures: FuturesUnordered>>) -> Self { Self { futures } } } impl future::Future for Select { - type Output = VmResult<(i64, Value)>; + type Output = VmResult<(usize, Value)>; fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { let poll = Pin::new(&mut self.futures).poll_next(cx); diff --git a/crates/rune/src/runtime/vm.rs b/crates/rune/src/runtime/vm.rs index dea3af882..6650baee8 100644 --- a/crates/rune/src/runtime/vm.rs +++ b/crates/rune/src/runtime/vm.rs @@ -1612,7 +1612,6 @@ impl Vm { &mut self, addr: InstAddress, len: usize, - branch: Output, value: Output, ) -> VmResult> { let futures = futures_util::stream::FuturesUnordered::new(); @@ -1621,13 +1620,13 @@ impl Vm { let future = vm_try!(value.clone().into_future_mut()); if !future.is_completed() { - futures.push(SelectFuture::new(branch as i64, future)); + futures.push(SelectFuture::new(self.ip + branch, future)); } } if futures.is_empty() { vm_try!(value.store(&mut self.stack, ())); - vm_try!(branch.store(&mut self.stack, -1i64)); + self.ip = self.ip.wrapping_add(len); return VmResult::Ok(None); } @@ -1699,19 +1698,6 @@ impl Vm { VmResult::Ok(()) } - /// Perform a branch-conditional jump operation. - #[cfg_attr(feature = "bench", inline(never))] - fn op_jump_if_branch(&mut self, branch: InstAddress, value: i64, jump: usize) -> VmResult<()> { - let branch = vm_try!(self.stack.at(branch)); - - if matches!(*vm_try!(branch.borrow_kind_ref()), ValueKind::Integer(branch) if branch == value) - { - self.ip = vm_try!(self.unit.translate(jump)); - } - - VmResult::Ok(()) - } - /// Construct a new vec. #[cfg_attr(feature = "bench", inline(never))] fn op_vec(&mut self, addr: InstAddress, count: usize, out: Output) -> VmResult<()> { @@ -3361,16 +3347,9 @@ impl Vm { let future = vm_try!(self.op_await(addr)); return VmResult::Ok(VmHalt::Awaited(Awaited::Future(future, out))); } - Inst::Select { - addr, - len, - branch, - value, - } => { - if let Some(select) = vm_try!(self.op_select(addr, len, branch, value)) { - return VmResult::Ok(VmHalt::Awaited(Awaited::Select( - select, branch, value, - ))); + Inst::Select { addr, len, value } => { + if let Some(select) = vm_try!(self.op_select(addr, len, value)) { + return VmResult::Ok(VmHalt::Awaited(Awaited::Select(select, value))); } } Inst::LoadFn { hash, out } => { @@ -3400,13 +3379,6 @@ impl Vm { Inst::JumpIfNot { cond, jump } => { vm_try!(self.op_jump_if_not(cond, jump)); } - Inst::JumpIfBranch { - branch, - value, - jump, - } => { - vm_try!(self.op_jump_if_branch(branch, value, jump)); - } Inst::Vec { addr, count, out } => { vm_try!(self.op_vec(addr, count, out)); }