Rust to assembly
In Rust, async functions desugar into suspendable generator functions, which in turn desugar into state machine enums¹⁷. The await keyword suspends the execution of the current function until the future is ready⁹.
A possible desugared version of your async function could look something like this:
// The state machine enum
enum GotoFuture {
// Initial state
Start(UnitRef, i32),
// Waiting for UnitGotoFuture to complete
Waiting(UnitGotoFuture),
// Final state
Done,
}
// Implementing Future for GotoFuture
impl Future for GotoFuture {
type Output = ();
fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
loop {
match *self {
// In the start state, create a UnitGotoFuture and move to the waiting state
GotoFuture::Start(unit, pos) => {
let fut = UnitGotoFuture { unit, target_pos: pos };
*self = GotoFuture::Waiting(fut);
}
// In the waiting state, poll the UnitGotoFuture and move to the done state if it's ready
GotoFuture::Waiting(ref mut fut) => {
match Pin::new(fut).poll(cx) {
Poll::Ready(()) => *self = GotoFuture::Done,
Poll::Pending => return Poll::Pending,
}
}
// In the done state, return ready
GotoFuture::Done => return Poll::Ready(()),
}
}
}
}
// The original async function is equivalent to creating a new GotoFuture instance
fn goto(unit: UnitRef, pos: i32) -> impl Future<Output = ()> {
GotoFuture::Start(unit, pos)
}
// The state machine enum
enum PatrolFuture {
// Initial state
Start(UnitRef, [i32; 2]),
// Waiting for goto to complete
WaitingGoto1(UnitRef, [i32; 2], impl Future<Output = ()>),
WaitingGoto2(UnitRef, [i32; 2], impl Future<Output = ()>),
// Final state
Done,
}
// Implementing Future for PatrolFuture
impl Future for PatrolFuture {
type Output = ();
fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
loop {
match *self {
// In the start state, create a goto future and move to the waiting state
PatrolFuture::Start(unit, poses) => {
let fut = goto(unit.clone(), poses[0]);
*self = PatrolFuture::WaitingGoto1(unit, poses, fut);
}
// In the waiting state for goto1, poll the goto future and move to the next waiting state if it's ready
PatrolFuture::WaitingGoto1(unit, poses, ref mut fut) => {
match Pin::new(fut).poll(cx) {
Poll::Ready(()) => {
let fut = goto(unit.clone(), poses[1]);
*self = PatrolFuture::WaitingGoto2(unit, poses, fut);
}
Poll::Pending => return Poll::Pending,
}
}
// In the waiting state for goto2, poll the goto future and move back to the start state if it's ready
PatrolFuture::WaitingGoto2(unit, poses, ref mut fut) => {
match Pin::new(fut).poll(cx) {
Poll::Ready(()) => *self = PatrolFuture::Start(unit.clone(), poses),
Poll::Pending => return Poll::Pending,
}
}
// In the done state (which is unreachable), return ready
PatrolFuture::Done => return Poll::Ready(()),
}
}
}
}
// The original async function is equivalent to creating a new PatrolFuture instance
fn patrol(unit: UnitRef, pos: [i32; 2]) -> impl Future<Output = ()> {
PatrolFuture::Start(unit.clone(), pos)
}
use futures::future::{self, Future};
fn main() {
let _ = example(100);
}
pub async fn example(min_len: usize) -> String {
let content = async_read_file("foo.txt").await;
if content.len() < min_len {
content + &async_read_file("bar.txt").await
} else {
content
}
}
fn async_read_file(name: &str) -> impl Future<Output = String> {
future::ready(String::from(name))
}
#![warn(missing_docs)]
//! Single-threaded polling-based executor suitable for use in games, embedded systems or WASM.
//!
//! This crate provides an executor to run async functions in single-threaded
//! environment with deterministic execution. To do so, the executor provides a [`Executor::step()`]
//! method that polls all non-blocked tasks exactly once. The executor also provides events
//! that can be waited upon. These events are referred to by the [`EventHandle`] type which is
//! instantiated by calling [`Executor::create_event_handle()`], and can be waited on by
//! creating [`EventFuture`] by calling the [`Executor::event()`] method. They can be activated
//! by calling the [`Executor::notify_event()`] method.
//!
//! # Example
//! ```
//! # use simple_async_local_executor::*;
//! let executor = Executor::default();
//! let events = [executor.create_event_handle(), executor.create_event_handle()];
//!
//! async fn wait_events(events: [EventHandle; 2], executor: Executor) {
//! executor.event(&events[0]).await;
//! executor.event(&events[1]).await;
//! }
//!
//! executor.spawn(wait_events(events.clone(), executor.clone()));
//! assert_eq!(executor.step(), true);
//! assert_eq!(executor.step(), true);
//! executor.notify_event(&events[0]);
//! assert_eq!(executor.step(), true);
//! executor.notify_event(&events[1]);
//! assert_eq!(executor.step(), false);
//! ```
use core::fmt;
use std::{
cell::{Cell, RefCell},
future::Future,
hash::{Hash, Hasher},
pin::Pin,
ptr,
rc::Rc,
task::{Context, Poll, RawWaker, RawWakerVTable, Waker},
};
#[cfg(feature = "futures")]
use futures::future::FusedFuture;
use slab::Slab;
// Useful reading for people interested in writing executors:
// - https://os.phil-opp.com/async-await/
// - https://rust-lang.github.io/async-book/02_execution/01_chapter.html
// - https://github.com/rust-lang/rfcs/blob/master/text/2592-futures.md#rationale-drawbacks-and-alternatives-to-the-wakeup-design-waker
fn dummy_raw_waker() -> RawWaker {
fn no_op(_: *const ()) {}
fn clone(_: *const ()) -> RawWaker {
dummy_raw_waker()
}
let vtable = &RawWakerVTable::new(clone, no_op, no_op, no_op);
RawWaker::new(std::ptr::null::<()>(), vtable)
}
fn dummy_waker() -> Waker {
unsafe { Waker::from_raw(dummy_raw_waker()) }
}
#[derive(Clone)]
struct EventHandleInner {
index: usize,
executor: Rc<ExecutorInner>,
}
impl fmt::Debug for EventHandleInner {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
self.index.fmt(f)
}
}
impl Eq for EventHandleInner {}
impl PartialEq for EventHandleInner {
fn eq(&self, other: &Self) -> bool {
self.index == other.index && ptr::eq(self.executor.as_ref(), other.executor.as_ref())
}
}
impl Hash for EventHandleInner {
fn hash<H: Hasher>(&self, state: &mut H) {
self.index.hash(state);
(self.executor.as_ref() as *const ExecutorInner).hash(state);
}
}
impl Drop for EventHandleInner {
fn drop(&mut self) {
self.executor.release_event_handle(self);
}
}
/// A handle for an event, can be kept and cloned around
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
pub struct EventHandle(Rc<EventHandleInner>);
type SharedBool = Rc<Cell<bool>>;
/// A future to await an event
pub struct EventFuture {
ready: SharedBool,
_handle: EventHandle,
done: bool,
}
impl Future for EventFuture {
type Output = ();
fn poll(mut self: Pin<&mut Self>, _cx: &mut Context) -> Poll<Self::Output> {
if self.ready.get() {
self.done = true;
Poll::Ready(())
} else {
Poll::Pending
}
}
}
#[cfg(feature = "futures")]
impl FusedFuture for EventFuture {
fn is_terminated(&self) -> bool {
self.done
}
}
struct Task {
future: Pin<Box<dyn Future<Output = ()>>>,
}
impl Task {
pub fn new(future: impl Future<Output = ()> + 'static) -> Task {
Task {
future: Box::pin(future),
}
}
fn poll(&mut self, context: &mut Context) -> Poll<()> {
self.future.as_mut().poll(context)
}
}
#[derive(Default)]
struct ExecutorInner {
task_queue: RefCell<Vec<Task>>,
new_tasks: RefCell<Vec<Task>>,
events: RefCell<Slab<SharedBool>>,
}
impl ExecutorInner {
fn release_event_handle(&self, event: &EventHandleInner) {
self.events.borrow_mut().remove(event.index);
}
}
/// Single-threaded polling-based executor
///
/// This is a thin-wrapper (using [`Rc`]) around the real executor, so that this struct can be
/// cloned and passed around.
///
/// See the [module documentation] for more details.
///
/// [module documentation]: index.html
#[derive(Clone, Default)]
pub struct Executor {
inner: Rc<ExecutorInner>,
}
impl Executor {
/// Spawn a new task to be run by this executor.
///
/// # Example
/// ```
/// # use simple_async_local_executor::*;
/// async fn nop() {}
/// let executor = Executor::default();
/// executor.spawn(nop());
/// assert_eq!(executor.step(), false);
/// ```
pub fn spawn(&self, future: impl Future<Output = ()> + 'static) {
self.inner.new_tasks.borrow_mut().push(Task::new(future));
}
/// Create an event handle, that can be used to [await](Executor::event()) and [notify](Executor::notify_event()) an event.
pub fn create_event_handle(&self) -> EventHandle {
let mut events = self.inner.events.borrow_mut();
let index = events.insert(Rc::new(Cell::new(false)));
EventHandle(Rc::new(EventHandleInner {
index,
executor: self.inner.clone(),
}))
}
/// Notify an event.
///
/// All tasks currently waiting on this event will
/// progress at the next call to [`step`](Executor::step()).
pub fn notify_event(&self, handle: &EventHandle) {
self.inner.events.borrow_mut()[handle.0.index].replace(true);
}
/// Create an event future.
///
/// Once this future is awaited, its task will be blocked until the next [`step`](Executor::step())
/// after [`notify_event`](Executor::notify_event()) is called with this `handle`.
pub fn event(&self, handle: &EventHandle) -> EventFuture {
let ready = self.inner.events.borrow_mut()[handle.0.index].clone();
EventFuture {
ready,
_handle: handle.clone(),
done: false,
}
}
/// Run each non-blocked task exactly once.
///
/// Return whether there are any non-completed tasks.
///
/// # Example
/// ```
/// # use simple_async_local_executor::*;
/// let executor = Executor::default();
/// let event = executor.create_event_handle();
/// async fn wait_event(event: EventHandle, executor: Executor) {
/// executor.event(&event).await;
/// }
/// executor.spawn(wait_event(event.clone(), executor.clone()));
/// assert_eq!(executor.step(), true); // still one task in the queue
/// executor.notify_event(&event);
/// assert_eq!(executor.step(), false); // no more task in the queue
/// ```
pub fn step(&self) -> bool {
// dummy waker and context
let waker = dummy_waker();
let mut context = Context::from_waker(&waker);
// append new tasks to all tasks
let mut tasks = self.inner.task_queue.borrow_mut();
tasks.append(&mut self.inner.new_tasks.borrow_mut());
// go through all tasks, and keep uncompleted ones
let mut uncompleted_tasks = Vec::new();
let mut any_left = false;
for mut task in tasks.drain(..) {
match task.poll(&mut context) {
Poll::Ready(()) => {} // task done
Poll::Pending => {
uncompleted_tasks.push(task);
any_left = true;
}
}
}
// replace all tasks with uncompleted ones
*tasks = uncompleted_tasks;
// clear events
for (_, event) in self.inner.events.borrow_mut().iter_mut() {
event.replace(false);
}
any_left
}
}
#[cfg(test)]
mod tests {
use super::*;
async fn nop() {}
#[test]
fn test_nop() {
let executor = Executor::default();
executor.spawn(nop());
assert_eq!(executor.step(), false);
}
#[test]
fn test_event() {
let executor = Executor::default();
let events = [
executor.create_event_handle(),
executor.create_event_handle(),
];
async fn wait_events(events: [EventHandle; 2], executor: Executor) {
println!("before awaits");
executor.event(&events[0]).await;
println!("between awaits");
executor.event(&events[1]).await;
println!("after awaits");
}
executor.spawn(wait_events(events.clone(), executor.clone()));
println!("spawned");
assert_eq!(executor.step(), true);
assert_eq!(executor.inner.task_queue.borrow().len(), 1);
println!("step 1");
assert_eq!(executor.step(), true);
println!("step 2");
executor.notify_event(&events[0]);
println!("notified 1");
assert_eq!(executor.step(), true);
executor.notify_event(&events[1]);
println!("notified 2");
assert_eq!(executor.step(), false);
println!("step 3");
assert_eq!(executor.inner.task_queue.borrow().len(), 0);
}
#[test]
#[cfg(feature = "futures")]
fn test_select() {
use futures::select;
let first_event_id = Rc::new(Cell::new(2));
async fn wait_event(
events: [EventHandle; 2],
event_loop: Executor,
first_event_id: Rc<Cell<usize>>,
) {
println!("before select");
let mut fut0 = event_loop.event(&events[0]);
let mut fut1 = event_loop.event(&events[1]);
select! {
() = fut0 => { println!("event 0 fired first"); first_event_id.set(0); },
() = fut1 => { println!("event 1 fired first"); first_event_id.set(1); }
}
println!("after select");
}
for i in 0..2 {
println!("Testing event {}", i);
let executor = Executor::default();
{
let events = [
executor.create_event_handle(),
executor.create_event_handle(),
];
executor.spawn(wait_event(
events.clone(),
executor.clone(),
first_event_id.clone(),
));
println!("spawned");
assert_eq!(executor.step(), true);
assert_eq!(executor.inner.task_queue.borrow().len(), 1);
println!("step 1");
assert_eq!(executor.step(), true);
println!("step 2");
executor.notify_event(&events[i]);
println!("notified");
assert_eq!(executor.step(), false);
println!("step 3");
assert_eq!(first_event_id.get(), i);
assert_eq!(executor.inner.task_queue.borrow().len(), 0);
}
assert_eq!(executor.inner.events.borrow().len(), 0);
}
}
}
#[derive(Default)]
struct Unit {
/// The 1-D position of the unit. In a real game, it would be a 2D or 3D.
pub pos: i32,
}
type UnitRef = Rc<RefCell<Unit>>;
/// A future that will move the unit towards `target_pos` at each step,
/// and complete when the unit has reached that position.
struct UnitGotoFuture {
unit: UnitRef,
target_pos: i32,
}
impl Future for UnitGotoFuture {
type Output = ();
fn poll(self: Pin<&mut Self>, _cx: &mut Context) -> Poll<Self::Output> {
let unit_pos = self.unit.borrow().pos;
if unit_pos == self.target_pos {
Poll::Ready(())
} else {
self.unit.borrow_mut().pos += (self.target_pos - unit_pos).signum();
Poll::Pending
}
}
}
/// Helper async function to write unit behavior nicely
async fn goto(unit: UnitRef, pos: i32) {
UnitGotoFuture {
unit,
target_pos: pos,
}
.await;
}
/// Let a unit go back and forth between two positions
async fn patrol(unit: UnitRef, poses: [i32; 2]) {
loop {
goto(unit.clone(), poses[0]).await;
goto(unit.clone(), poses[1]).await;
}
}
/// Test program with two units: one patrolling and one going to a position.
pub fn main() {
let executor = Executor::default();
let units: [UnitRef; 2] = Default::default();
executor.spawn(patrol(units[0].clone(), [-5, 5]));
executor.spawn(goto(units[1].clone(), 12));
let print_poses = || {
println!(
"Unit poses: {}",
units
.iter()
.map(|unit| unit.borrow().pos.to_string())
.collect::<Vec<_>>()
.join(", ")
);
};
print_poses();
for _ in 0..30 {
executor.step();
print_poses();
}
}
#![warn(missing_docs)]
//! Single-threaded polling-based executor suitable for use in games, embedded systems or WASM.
//!
//! This crate provides an executor to run async functions in single-threaded
//! environment with deterministic execution. To do so, the executor provides a [`Executor::step()`]
//! method that polls all non-blocked tasks exactly once. The executor also provides events
//! that can be waited upon. These events are referred to by the [`EventHandle`] type which is
//! instantiated by calling [`Executor::create_event_handle()`], and can be waited on by
//! creating [`EventFuture`] by calling the [`Executor::event()`] method. They can be activated
//! by calling the [`Executor::notify_event()`] method.
//!
//! # Example
//! ```
//! # use simple_async_local_executor::*;
//! let executor = Executor::default();
//! let events = [executor.create_event_handle(), executor.create_event_handle()];
//!
//! async fn wait_events(events: [EventHandle; 2], executor: Executor) {
//! executor.event(&events[0]).await;
//! executor.event(&events[1]).await;
//! }
//!
//! executor.spawn(wait_events(events.clone(), executor.clone()));
//! assert_eq!(executor.step(), true);
//! assert_eq!(executor.step(), true);
//! executor.notify_event(&events[0]);
//! assert_eq!(executor.step(), true);
//! executor.notify_event(&events[1]);
//! assert_eq!(executor.step(), false);
//! ```
#[prelude_import]
use std::prelude::rust_2021::*;
#[macro_use]
extern crate std;
use core::fmt;
use std::{};
use std::cell::{};
use std::cell::Cell;
use std::cell::RefCell;
use std::future::Future;
use std::hash::{};
use std::hash::Hash;
use std::hash::Hasher;
use std::pin::Pin;
use std::ptr;
use std::rc::Rc;
use std::task::{};
use std::task::Context;
use std::task::Poll;
use std::task::RawWaker;
use std::task::RawWakerVTable;
use std::task::Waker;
use slab::Slab;
// Useful reading for people interested in writing executors:
// - https://os.phil-opp.com/async-await/
// - https://rust-lang.github.io/async-book/02_execution/01_chapter.html
// - https://github.com/rust-lang/rfcs/blob/master/text/2592-futures.md#rationale-drawbacks-and-alternatives-to-the-wakeup-design-waker
fn dummy_raw_waker()
->
RawWaker {
fn no_op(_: *const ()) { }
fn clone(_: *const ()) -> RawWaker { dummy_raw_waker() }
let vtable = &RawWakerVTable::new(clone, no_op, no_op, no_op);
RawWaker::new(std::ptr::null::<()>(), vtable)
}
fn dummy_waker() -> Waker { unsafe { Waker::from_raw(dummy_raw_waker()) } }
struct EventHandleInner {
index: usize,
executor: Rc<ExecutorInner>,
}
#[automatically_derived]
impl ::core::clone::Clone for EventHandleInner {
#[inline]
fn clone<'_>(self: &'_ Self)
->
EventHandleInner {
EventHandleInner{
index: ::core::clone::Clone::clone(&self.index),
executor: ::core::clone::Clone::clone(&self.executor),}
}
}
impl fmt::Debug for EventHandleInner {
fn fmt<'_, '_, '_>(self: &'_ Self, f: &'_ mut fmt::Formatter<'_>)
-> fmt::Result { self.index.fmt(f) }
}
impl Eq for EventHandleInner { }
impl PartialEq for EventHandleInner {
fn eq<'_, '_>(self: &'_ Self, other: &'_ Self)
->
bool {
self.index == other.index &&
ptr::eq(self.executor.as_ref(), other.executor.as_ref())
}
}
impl Hash for EventHandleInner {
fn hash<H, '_, '_>(self: &'_ Self, state: &'_ mut H) where
H: Hasher {
self.index.hash(state);
(self.executor.as_ref() as *const ExecutorInner).hash(state);
}
}
impl Drop for EventHandleInner {
fn drop<'_>(self:
&'_ mut Self) { self.executor.release_event_handle(self); }
}
/// A handle for an event, can be kept and cloned around
struct EventHandle(Rc<EventHandleInner>);
#[automatically_derived]
impl ::core::clone::Clone for EventHandle {
#[inline]
fn clone<'_>(self: &'_ Self)
-> EventHandle { EventHandle(::core::clone::Clone::clone(&self.0)) }
}
#[automatically_derived]
impl ::core::fmt::Debug for EventHandle {
fn fmt<'_, '_, '_>(self: &'_ Self, f: &'_ mut ::core::fmt::Formatter<>)
->
::core::fmt::Result {
::core::fmt::Formatter::debug_tuple_field1_finish(f,
"EventHandle", &&self.0)
}
}
#[automatically_derived]
impl ::core::marker::StructuralPartialEq for EventHandle { }
#[automatically_derived]
impl ::core::cmp::PartialEq for EventHandle {
#[inline]
fn eq<'_, '_>(self: &'_ Self, other: &'_ EventHandle)
-> bool { self.0 == other.0 }
}
#[automatically_derived]
impl ::core::marker::StructuralEq for EventHandle { }
#[automatically_derived]
impl ::core::cmp::Eq for EventHandle {
#[inline]
#[doc(hidden)]
#[no_coverage]
fn assert_receiver_is_total_eq<'_>(self: &'_ Self)
-> () { let _: ::core::cmp::AssertParamIsEq<Rc<EventHandleInner>>; }
}
#[automatically_derived]
impl ::core::hash::Hash for EventHandle {
fn hash<__H, '_, '_>(self: &'_ Self, state: &'_ mut __H) -> () where
__H: ::core::hash::Hasher { ::core::hash::Hash::hash(&self.0, state) }
}
type SharedBool = Rc<Cell<bool>>;
/// A future to await an event
struct EventFuture {
ready: SharedBool,
_handle: EventHandle,
done: bool,
}
impl Future for EventFuture {
type
Output
=
();
fn poll<'_, '_, '_>(mut self: Pin<&'_ mut Self>, _cx: &'_ mut Context<>)
->
Poll<Self::Output> {
if self.ready.get()
{ self.done = true; Poll::Ready(()) } else { Poll::Pending }
}
}
struct Task {
future: Pin<Box<dyn Future<Output = ()>>>,
}
impl Task {
fn new<impl Future<Output = ()> + 'static>(future:
impl Future<Output = ()> + 'static) -> Task where
impl Future<Output = ()> + 'static: Future<Output = ()> +
'static { Task{ future: Box::pin(future),} }
fn poll<'_, '_,
'_>(self: &'_ mut Self, context: &'_ mut Context<>)
-> Poll<()> { self.future.as_mut().poll(context) }
}
struct ExecutorInner {
task_queue: RefCell<Vec<Task>>,
new_tasks: RefCell<Vec<Task>>,
events: RefCell<Slab<SharedBool>>,
}
#[automatically_derived]
impl ::core::default::Default for ExecutorInner {
#[inline]
fn default()
->
ExecutorInner {
ExecutorInner{
task_queue: ::core::default::Default::default(),
new_tasks: ::core::default::Default::default(),
events: ::core::default::Default::default(),}
}
}
impl ExecutorInner {
fn release_event_handle<'_,
'_>(self: &'_ Self,
event:
&'_ EventHandleInner) {
self.events.borrow_mut().remove(event.index);
}
}
/// Single-threaded polling-based executor
///
/// This is a thin-wrapper (using [`Rc`]) around the real executor, so that this struct can be
/// cloned and passed around.
///
/// See the [module documentation] for more details.
///
/// [module documentation]: index.html
struct Executor {
inner: Rc<ExecutorInner>,
}
#[automatically_derived]
impl ::core::clone::Clone for Executor {
#[inline]
fn clone<'_>(self: &'_ Self)
->
Executor {
Executor{ inner: ::core::clone::Clone::clone(&self.inner),}
}
}
#[automatically_derived]
impl ::core::default::Default for Executor {
#[inline]
fn default()
->
Executor {
Executor{ inner: ::core::default::Default::default(),}
}
}
impl Executor {
/// Spawn a new task to be run by this executor.
///
/// # Example
/// ```
/// # use simple_async_local_executor::*;
/// async fn nop() {}
/// let executor = Executor::default();
/// executor.spawn(nop());
/// assert_eq!(executor.step(), false);
/// ```
fn spawn<'_,
impl Future<Output = ()> + 'static>(self: &'_ Self,
future: impl Future<Output = ()> + 'static) where
impl Future<Output = ()> + 'static: Future<Output = ()> +
'static {
self.inner.new_tasks.borrow_mut().push(Task::new(future));
}
/// Create an event handle, that can be used to [await](Executor::event()) and [notify](Executor::notify_event()) an event.
fn create_event_handle<'_>(self: &'_ Self)
->
EventHandle {
let mut events = self.inner.events.borrow_mut();
let index = events.insert(Rc::new(Cell::new(false)));
EventHandle(Rc::new(EventHandleInner{
index,
executor: self.inner.clone(),}))
}
/// Notify an event.
///
/// All tasks currently waiting on this event will
/// progress at the next call to [`step`](Executor::step()).
fn notify_event<'_,
'_>(self: &'_ Self,
handle:
&'_ EventHandle) {
self.inner.events.borrow_mut()[handle.0.index].replace(true);
}
/// Create an event future.
///
/// Once this future is awaited, its task will be blocked until the next [`step`](Executor::step())
/// after [`notify_event`](Executor::notify_event()) is called with this `handle`.
fn event<'_, '_>(self: &'_ Self, handle: &'_ EventHandle)
->
EventFuture {
let ready =
self.inner.events.borrow_mut()[handle.0.index].clone();
EventFuture{ ready, _handle: handle.clone(), done: false,}
}
/// Run each non-blocked task exactly once.
///
/// Return whether there are any non-completed tasks.
///
/// # Example
/// ```
/// # use simple_async_local_executor::*;
/// let executor = Executor::default();
/// let event = executor.create_event_handle();
/// async fn wait_event(event: EventHandle, executor: Executor) {
/// executor.event(&event).await;
/// }
/// executor.spawn(wait_event(event.clone(), executor.clone()));
/// assert_eq!(executor.step(), true); // still one task in the queue
/// executor.notify_event(&event);
/// assert_eq!(executor.step(), false); // no more task in the queue
/// ```
fn step<'_>(self: &'_ Self)
->
bool {
// dummy waker and context
let waker = dummy_waker();
let mut context = Context::from_waker(&waker);
// append new tasks to all tasks
let mut tasks = self.inner.task_queue.borrow_mut();
tasks.append(&mut self.inner.new_tasks.borrow_mut());
// go through all tasks, and keep uncompleted ones
let mut uncompleted_tasks = Vec::new();
let mut any_left = false;
{
let _t =
match #[lang = "into_iter"](tasks.drain(#[lang = "RangeFull"]{}))
{
mut iter =>
loop {
match #[lang = "next"](&mut iter) {
#[lang = "None"] {} => break,
#[lang = "Some"] { 0: mut task } => {
match task.poll(&mut context) {
Poll::Ready(()) => { }
// task done
Poll::Pending => {
uncompleted_tasks.push(task);
any_left = true;
}
}
}
}
},
};
_t
};
// replace all tasks with uncompleted ones
*tasks = uncompleted_tasks;
// clear events
{
let _t =
match #[lang = "into_iter"](self.inner.events.borrow_mut().iter_mut())
{
mut iter =>
loop {
match #[lang = "next"](&mut iter) {
#[lang = "None"] {} => break,
#[lang = "Some"] { 0: (_, event) } => {
event.replace(false);
}
}
},
};
_t
};
any_left
}
}
struct Unit {
/// The 1-D position of the unit. In a real game, it would be a 2D or 3D.
pos: i32,
}
#[automatically_derived]
impl ::core::default::Default for Unit {
#[inline]
fn default()
-> Unit { Unit{ pos: ::core::default::Default::default(),} }
}
type UnitRef = Rc<RefCell<Unit>>;
/// A future that will move the unit towards `target_pos` at each step,
/// and complete when the unit has reached that position.
struct UnitGotoFuture {
unit: UnitRef,
target_pos: i32,
}
impl Future for UnitGotoFuture {
type
Output
=
();
fn poll<'_, '_,
'_>(self: Pin<&'_ mut Self>, _cx: &'_ mut Context<>)
->
Poll<Self::Output> {
let unit_pos = self.unit.borrow().pos;
if unit_pos == self.target_pos
{
Poll::Ready(())
} else {
self.unit.borrow_mut().pos +=
(self.target_pos - unit_pos).signum();
Poll::Pending
}
}
}
/// Helper async function to write unit behavior nicely
async fn goto(unit: UnitRef, pos: i32)
->
/*impl Trait*/ #[lang = "identity_future"](move
|mut _task_context: #[lang = "ResumeTy"]|
{
let unit = unit;
let pos = pos;
{
let _t =
{
match #[lang = "into_future"](UnitGotoFuture{
unit,
target_pos: pos,}) {
mut __awaitee =>
loop {
match unsafe {
#[lang = "poll"](#[lang = "new_unchecked"](&mut __awaitee),
#[lang = "get_context"](_task_context))
} {
#[lang = "Ready"] { 0: result } => break result,
#[lang = "Pending"] {} => { }
}
_task_context = (yield ());
},
};
};
_t
}
})
/// Let a unit go back and forth between two positions
async fn patrol(unit: UnitRef, poses: [i32; 2])
->
/*impl Trait*/ #[lang = "identity_future"](move
|mut _task_context: #[lang = "ResumeTy"]|
{
let unit = unit;
let poses = poses;
{
let _t =
{
loop {
match #[lang = "into_future"](goto(unit.clone(), poses[0]))
{
mut __awaitee =>
loop {
match unsafe {
#[lang = "poll"](#[lang = "new_unchecked"](&mut __awaitee),
#[lang = "get_context"](_task_context))
} {
#[lang = "Ready"] { 0: result } => break result,
#[lang = "Pending"] {} => { }
}
_task_context = (yield ());
},
};
match #[lang = "into_future"](goto(unit.clone(), poses[1]))
{
mut __awaitee =>
loop {
match unsafe {
#[lang = "poll"](#[lang = "new_unchecked"](&mut __awaitee),
#[lang = "get_context"](_task_context))
} {
#[lang = "Ready"] { 0: result } => break result,
#[lang = "Pending"] {} => { }
}
_task_context = (yield ());
},
};
}
};
_t
}
})
/// Test program with two units: one patrolling and one going to a position.
fn main() {
let executor = Executor::default();
let units: [UnitRef; 2] = Default::default();
executor.spawn(patrol(units[0].clone(), [-5, 5]));
executor.spawn(goto(units[1].clone(), 12));
let print_poses =
||
{
{
::std::io::_print(<#[lang = "format_arguments"]>::new_v1(&["Unit poses: ",
"\n"],
&[<#[lang = "format_argument"]>::new_display(&units.iter().map(|unit|
unit.borrow().pos.to_string()).collect::<Vec<_>>().join(", "))]));
};
};
print_poses();
{
let _t =
match #[lang = "into_iter"](#[lang = "Range"]{
start: 0,
end: 30,}) {
mut iter =>
loop {
match #[lang = "next"](&mut iter) {
#[lang = "None"] {} => break,
#[lang = "Some"] { 0: _ } => {
executor.step();
print_poses();
}
}
},
};
_t
}
}
<T as core::any::Any>::type_id:
movabs rax, -8527728395957036344
ret
std::sys_common::backtrace::__rust_end_short_backtrace:
sub rsp, 24
mov rax, qword ptr [rdi + 16]
mov qword ptr [rsp + 16], rax
movups xmm0, xmmword ptr [rdi]
movaps xmmword ptr [rsp], xmm0
mov rdi, rsp
call std::panicking::begin_panic::{{closure}}
ud2
std::panicking::begin_panic:
sub rsp, 24
lea rax, [rip + .L__unnamed_1]
mov qword ptr [rsp], rax
mov qword ptr [rsp + 8], 11
mov qword ptr [rsp + 16], rdi
mov rdi, rsp
call std::sys_common::backtrace::__rust_end_short_backtrace
ud2
std::panicking::begin_panic::{{closure}}:
sub rsp, 24
movups xmm0, xmmword ptr [rdi]
movups xmmword ptr [rsp + 8], xmm0
mov rcx, qword ptr [rdi + 16]
lea rsi, [rip + .L__unnamed_2]
lea rdi, [rsp + 8]
xor edx, edx
mov r8d, 1
call qword ptr [rip + std::panicking::rust_panic_with_hook@GOTPCREL]
ud2
<&T as core::fmt::Debug>::fmt:
push r14
push rbx
push rax
mov r14, rsi
mov rax, qword ptr [rdi]
mov rbx, qword ptr [rax]
add rbx, 16
mov rdi, rsi
call qword ptr [rip + core::fmt::Formatter::debug_lower_hex@GOTPCREL]
test al, al
je .LBB4_1
mov rdi, rbx
mov rsi, r14
add rsp, 8
pop rbx
pop r14
jmp qword ptr [rip + core::fmt::num::<impl core::fmt::LowerHex for usize>::fmt@GOTPCREL]
.LBB4_1:
mov rdi, r14
call qword ptr [rip + core::fmt::Formatter::debug_upper_hex@GOTPCREL]
mov rdi, rbx
mov rsi, r14
add rsp, 8
test al, al
je .LBB4_4
pop rbx
pop r14
jmp qword ptr [rip + core::fmt::num::<impl core::fmt::UpperHex for usize>::fmt@GOTPCREL]
.LBB4_4:
pop rbx
pop r14
jmp qword ptr [rip + core::fmt::num::imp::<impl core::fmt::Display for usize>::fmt@GOTPCREL]
core::fmt::Write::write_fmt:
sub rsp, 72
mov qword ptr [rsp + 8], rdi
movups xmm0, xmmword ptr [rsi]
movups xmm1, xmmword ptr [rsi + 16]
movups xmm2, xmmword ptr [rsi + 32]
movaps xmmword ptr [rsp + 48], xmm2
movaps xmmword ptr [rsp + 32], xmm1
movaps xmmword ptr [rsp + 16], xmm0
lea rsi, [rip + .L__unnamed_3]
lea rdi, [rsp + 8]
lea rdx, [rsp + 16]
call qword ptr [rip + core::fmt::write@GOTPCREL]
add rsp, 72
ret
core::ptr::drop_in_place<[alloc::rc::Rc<core::cell::RefCell<playground::Unit>>; 2]>:
push rbx
mov rbx, rdi
mov rdi, qword ptr [rdi]
dec qword ptr [rdi]
jne .LBB6_3
dec qword ptr [rdi + 8]
je .LBB6_2
.LBB6_3:
mov rdi, qword ptr [rbx + 8]
dec qword ptr [rdi]
jne .LBB6_5
.LBB6_4:
dec qword ptr [rdi + 8]
jne .LBB6_5
mov esi, 32
mov edx, 8
pop rbx
jmp qword ptr [rip + __rust_dealloc@GOTPCREL]
.LBB6_2:
mov esi, 32
mov edx, 8
call qword ptr [rip + __rust_dealloc@GOTPCREL]
mov rdi, qword ptr [rbx + 8]
dec qword ptr [rdi]
je .LBB6_4
.LBB6_5:
pop rbx
ret
core::ptr::drop_in_place<core::cell::RefMut<slab::Slab<alloc::rc::Rc<core::cell::Cell<bool>>>>>:
inc qword ptr [rdi]
ret
core::ptr::drop_in_place<core::cell::RefCell<slab::Slab<alloc::rc::Rc<core::cell::Cell<bool>>>>>:
push r15
push r14
push r13
push r12
push rbx
mov r14, rdi
mov r15, qword ptr [rdi + 40]
test r15, r15
je .LBB8_7
mov r12, qword ptr [r14 + 32]
shl r15, 4
xor ebx, ebx
mov r13, qword ptr [rip + __rust_dealloc@GOTPCREL]
jmp .LBB8_2
.LBB8_6:
add rbx, 16
cmp r15, rbx
je .LBB8_7
.LBB8_2:
cmp qword ptr [r12 + rbx], 0
je .LBB8_6
mov rdi, qword ptr [r12 + rbx + 8]
dec qword ptr [rdi]
jne .LBB8_6
dec qword ptr [rdi + 8]
jne .LBB8_6
mov esi, 24
mov edx, 8
call r13
jmp .LBB8_6
.LBB8_7:
mov rsi, qword ptr [r14 + 24]
test rsi, rsi
je .LBB8_8
mov rdi, qword ptr [r14 + 32]
shl rsi, 4
mov edx, 8
pop rbx
pop r12
pop r13
pop r14
pop r15
jmp qword ptr [rip + __rust_dealloc@GOTPCREL]
.LBB8_8:
pop rbx
pop r12
pop r13
pop r14
pop r15
ret
core::ptr::drop_in_place<<alloc::vec::drain::Drain<T,A> as core::ops::drop::Drop>::drop::DropGuard<playground::Task,alloc::alloc::Global>>:
push r15
push r14
push rbx
mov rdx, qword ptr [rdi + 24]
test rdx, rdx
je .LBB9_3
mov rbx, rdi
mov rsi, qword ptr [rdi + 16]
mov r14, qword ptr [rdi + 32]
mov r15, qword ptr [r14 + 16]
cmp rsi, r15
je .LBB9_2
mov rax, qword ptr [r14 + 8]
shl rsi, 4
add rsi, rax
mov rdi, r15
shl rdi, 4
add rdi, rax
shl rdx, 4
call qword ptr [rip + memmove@GOTPCREL]
mov rdx, qword ptr [rbx + 24]
.LBB9_2:
add rdx, r15
mov qword ptr [r14 + 16], rdx
.LBB9_3:
pop rbx
pop r14
pop r15
ret
core::ptr::drop_in_place<&str>:
ret
core::ptr::drop_in_place<playground::Task>:
push r14
push rbx
push rax
mov rbx, rdi
mov rdi, qword ptr [rdi]
mov rax, qword ptr [rbx + 8]
call qword ptr [rax]
mov rax, qword ptr [rbx + 8]
mov rsi, qword ptr [rax + 8]
test rsi, rsi
je .LBB11_2
mov rdx, qword ptr [rax + 16]
mov rdi, qword ptr [rbx]
add rsp, 8
pop rbx
pop r14
jmp qword ptr [rip + __rust_dealloc@GOTPCREL]
.LBB11_2:
add rsp, 8
pop rbx
pop r14
ret
mov r14, rax
mov rdi, qword ptr [rbx]
mov rax, qword ptr [rbx + 8]
mov rsi, qword ptr [rax + 8]
mov rdx, qword ptr [rax + 16]
call alloc::alloc::box_free
mov rdi, r14
call _Unwind_Resume@PLT
ud2
core::ptr::drop_in_place<playground::Executor>:
push rbx
dec qword ptr [rdi]
jne .LBB12_2
mov rbx, rdi
add rdi, 16
call core::ptr::drop_in_place<playground::ExecutorInner>
dec qword ptr [rbx + 8]
je .LBB12_3
.LBB12_2:
pop rbx
ret
.LBB12_3:
mov esi, 128
mov edx, 8
mov rdi, rbx
pop rbx
jmp qword ptr [rip + __rust_dealloc@GOTPCREL]
core::ptr::drop_in_place<alloc::string::String>:
mov rsi, qword ptr [rdi]
test rsi, rsi
je .LBB13_1
mov rdi, qword ptr [rdi + 8]
mov rdx, rsi
not rdx
shr rdx, 63
jmp qword ptr [rip + __rust_dealloc@GOTPCREL]
.LBB13_1:
ret
core::ptr::drop_in_place<core::task::wake::Waker>:
jmp qword ptr [rsi + 24]
core::ptr::drop_in_place<alloc::vec::Vec<u8>>:
mov rsi, qword ptr [rdi]
test rsi, rsi
je .LBB15_1
mov rdi, qword ptr [rdi + 8]
mov rdx, rsi
not rdx
shr rdx, 63
jmp qword ptr [rip + __rust_dealloc@GOTPCREL]
.LBB15_1:
ret
core::ptr::drop_in_place<playground::ExecutorInner>:
push r15
push r14
push r13
push r12
push rbx
mov r15, rdi
add rdi, 8
call core::ptr::drop_in_place<alloc::vec::Vec<playground::Task>>
lea rdi, [r15 + 40]
call core::ptr::drop_in_place<alloc::vec::Vec<playground::Task>>
mov r14, qword ptr [r15 + 104]
test r14, r14
je .LBB16_9
mov r12, qword ptr [r15 + 96]
shl r14, 4
xor ebx, ebx
mov r13, qword ptr [rip + __rust_dealloc@GOTPCREL]
jmp .LBB16_4
.LBB16_8:
add rbx, 16
cmp r14, rbx
je .LBB16_9
.LBB16_4:
cmp qword ptr [r12 + rbx], 0
je .LBB16_8
mov rdi, qword ptr [r12 + rbx + 8]
dec qword ptr [rdi]
jne .LBB16_8
dec qword ptr [rdi + 8]
jne .LBB16_8
mov esi, 24
mov edx, 8
call r13
jmp .LBB16_8
.LBB16_9:
mov rsi, qword ptr [r15 + 88]
test rsi, rsi
je .LBB16_14
mov rdi, qword ptr [r15 + 96]
shl rsi, 4
mov edx, 8
pop rbx
pop r12
pop r13
pop r14
pop r15
jmp qword ptr [rip + __rust_dealloc@GOTPCREL]
.LBB16_14:
pop rbx
pop r12
pop r13
pop r14
pop r15
ret
mov r14, rax
jmp .LBB16_12
mov r14, rax
lea rdi, [r15 + 32]
call core::ptr::drop_in_place<core::cell::RefCell<alloc::vec::Vec<playground::Task>>>
.LBB16_12:
add r15, 64
mov rdi, r15
call core::ptr::drop_in_place<core::cell::RefCell<slab::Slab<alloc::rc::Rc<core::cell::Cell<bool>>>>>
mov rdi, r14
call _Unwind_Resume@PLT
ud2
call qword ptr [rip + core::panicking::panic_no_unwind@GOTPCREL]
ud2
core::ptr::drop_in_place<playground::UnitGotoFuture>:
dec qword ptr [rdi]
jne .LBB17_2
dec qword ptr [rdi + 8]
je .LBB17_3
.LBB17_2:
ret
.LBB17_3:
mov esi, 32
mov edx, 8
jmp qword ptr [rip + __rust_dealloc@GOTPCREL]
core::ptr::drop_in_place<alloc::vec::Vec<playground::Task>>:
push r15
push r14
push r13
push r12
push rbx
mov r14, rdi
mov r12, qword ptr [rdi + 16]
test r12, r12
je .LBB18_6
mov rbx, qword ptr [r14 + 8]
shl r12, 4
add r12, -16
add rbx, 16
mov r15, qword ptr [rip + __rust_dealloc@GOTPCREL]
jmp .LBB18_2
.LBB18_5:
add r12, -16
add rbx, 16
cmp r12, -16
je .LBB18_6
.LBB18_2:
mov rdi, qword ptr [rbx - 16]
mov rax, qword ptr [rbx - 8]
call qword ptr [rax]
mov rax, qword ptr [rbx - 8]
mov rsi, qword ptr [rax + 8]
test rsi, rsi
je .LBB18_5
mov rdx, qword ptr [rax + 16]
mov rdi, qword ptr [rbx - 16]
call r15
jmp .LBB18_5
.LBB18_6:
mov rsi, qword ptr [r14]
test rsi, rsi
je .LBB18_13
mov rdi, qword ptr [r14 + 8]
shl rsi, 4
mov edx, 8
pop rbx
pop r12
pop r13
pop r14
pop r15
jmp qword ptr [rip + __rust_dealloc@GOTPCREL]
.LBB18_13:
pop rbx
pop r12
pop r13
pop r14
pop r15
ret
mov r15, rax
mov rdi, qword ptr [rbx - 16]
mov rax, qword ptr [rbx - 8]
mov rsi, qword ptr [rax + 8]
mov rdx, qword ptr [rax + 16]
call alloc::alloc::box_free
.LBB18_9:
test r12, r12
je .LBB18_12
lea r13, [rbx + 16]
add r12, -16
mov rdi, rbx
call core::ptr::drop_in_place<playground::Task>
mov rbx, r13
jmp .LBB18_9
.LBB18_12:
mov rdi, qword ptr [r14]
mov rsi, qword ptr [r14 + 8]
call core::ptr::drop_in_place<alloc::raw_vec::RawVec<playground::Task>>
mov rdi, r15
call _Unwind_Resume@PLT
ud2
call qword ptr [rip + core::panicking::panic_no_unwind@GOTPCREL]
ud2
core::ptr::drop_in_place<core::cell::Ref<playground::Unit>>:
dec qword ptr [rdi]
ret
core::ptr::drop_in_place<alloc::vec::Vec<alloc::string::String>>:
push r15
push r14
push r13
push r12
push rbx
mov r14, rdi
mov rax, qword ptr [rdi + 16]
test rax, rax
je .LBB20_5
mov r12, qword ptr [r14 + 8]
shl rax, 3
lea r15, [rax + 2*rax]
xor ebx, ebx
mov r13, qword ptr [rip + __rust_dealloc@GOTPCREL]
jmp .LBB20_2
.LBB20_4:
add rbx, 24
cmp r15, rbx
je .LBB20_5
.LBB20_2:
mov rsi, qword ptr [r12 + rbx]
test rsi, rsi
je .LBB20_4
mov rdi, qword ptr [r12 + rbx + 8]
mov rdx, rsi
not rdx
shr rdx, 63
call r13
jmp .LBB20_4
.LBB20_5:
mov rax, qword ptr [r14]
test rax, rax
je .LBB20_6
mov rdi, qword ptr [r14 + 8]
shl rax, 3
lea rsi, [rax + 2*rax]
mov edx, 8
pop rbx
pop r12
pop r13
pop r14
pop r15
jmp qword ptr [rip + __rust_dealloc@GOTPCREL]
.LBB20_6:
pop rbx
pop r12
pop r13
pop r14
pop r15
ret
core::ptr::drop_in_place<playground::goto::{{closure}}>:
movzx eax, byte ptr [rdi + 28]
test eax, eax
je .LBB21_3
cmp eax, 3
jne .LBB21_2
mov rdi, qword ptr [rdi]
dec qword ptr [rdi]
jne .LBB21_2
jmp .LBB21_5
.LBB21_3:
mov rdi, qword ptr [rdi + 16]
dec qword ptr [rdi]
jne .LBB21_2
.LBB21_5:
dec qword ptr [rdi + 8]
je .LBB21_6
.LBB21_2:
ret
.LBB21_6:
mov esi, 32
mov edx, 8
jmp qword ptr [rip + __rust_dealloc@GOTPCREL]
core::ptr::drop_in_place<alloc::raw_vec::RawVec<playground::Task>>:
test rdi, rdi
je .LBB22_1
mov rax, rdi
shl rax, 4
mov edx, 8
mov rdi, rsi
mov rsi, rax
jmp qword ptr [rip + __rust_dealloc@GOTPCREL]
.LBB22_1:
ret
core::ptr::drop_in_place<playground::patrol::{{closure}}>:
push rbx
mov rbx, rdi
movzx eax, byte ptr [rdi + 32]
test eax, eax
je .LBB23_4
cmp eax, 3
je .LBB23_8
cmp eax, 4
jne .LBB23_3
.LBB23_8:
movzx eax, byte ptr [rbx + 68]
cmp eax, 3
je .LBB23_11
test eax, eax
jne .LBB23_15
mov rdi, qword ptr [rbx + 56]
dec qword ptr [rdi]
jne .LBB23_15
jmp .LBB23_13
.LBB23_4:
mov rdi, qword ptr [rbx + 24]
dec qword ptr [rdi]
jne .LBB23_3
jmp .LBB23_6
.LBB23_11:
mov rdi, qword ptr [rbx + 40]
dec qword ptr [rdi]
jne .LBB23_15
.LBB23_13:
dec qword ptr [rdi + 8]
je .LBB23_14
.LBB23_15:
mov rdi, qword ptr [rbx + 8]
dec qword ptr [rdi]
jne .LBB23_3
.LBB23_6:
dec qword ptr [rdi + 8]
je .LBB23_7
.LBB23_3:
pop rbx
ret
.LBB23_7:
mov esi, 32
mov edx, 8
pop rbx
jmp qword ptr [rip + __rust_dealloc@GOTPCREL]
.LBB23_14:
mov esi, 32
mov edx, 8
call qword ptr [rip + __rust_dealloc@GOTPCREL]
mov rdi, qword ptr [rbx + 8]
dec qword ptr [rdi]
jne .LBB23_3
jmp .LBB23_6
core::ptr::drop_in_place<core::iter::adapters::map::map_fold<&alloc::rc::Rc<core::cell::RefCell<playground::Unit>>,alloc::string::String,(),playground::main::{{closure}}::{{closure}},core::iter::traits::iterator::Iterator::for_each::call<alloc::string::String,alloc::vec::Vec<alloc::string::String>::extend_trusted<core::iter::adapters::map::Map<core::slice::iter::Iter<alloc::rc::Rc<core::cell::RefCell<playground::Unit>>>,playground::main::{{closure}}::{{closure}}>>::{{closure}}>::{{closure}}>::{{closure}}>:
mov qword ptr [rsi], rdi
ret
core::ptr::drop_in_place<alloc::vec::drain::Drain<playground::Task>>:
push r15
push r14
push r13
push r12
push rbx
mov r14, rdi
mov r12, qword ptr [rdi]
mov rax, qword ptr [rdi + 8]
lea rcx, [rip + .L__unnamed_4]
mov qword ptr [rdi], rcx
mov qword ptr [rdi + 8], rcx
mov r15, qword ptr [rdi + 32]
sub r12, rax
je .LBB25_1
mov rcx, qword ptr [r15 + 8]
sub rax, rcx
and r12, -16
add r12, -16
and rax, -16
lea rbx, [rax + rcx]
add rbx, 16
mov r13, qword ptr [rip + __rust_dealloc@GOTPCREL]
jmp .LBB25_7
.LBB25_10:
add r12, -16
add rbx, 16
cmp r12, -16
je .LBB25_1
.LBB25_7:
mov rdi, qword ptr [rbx - 16]
mov rax, qword ptr [rbx - 8]
call qword ptr [rax]
mov rax, qword ptr [rbx - 8]
mov rsi, qword ptr [rax + 8]
test rsi, rsi
je .LBB25_10
mov rdx, qword ptr [rax + 16]
mov rdi, qword ptr [rbx - 16]
call r13
jmp .LBB25_10
.LBB25_1:
mov r12, qword ptr [r14 + 24]
test r12, r12
je .LBB25_4
mov rbx, qword ptr [r15 + 16]
mov rsi, qword ptr [r14 + 16]
cmp rsi, rbx
je .LBB25_3
mov rax, qword ptr [r15 + 8]
shl rsi, 4
add rsi, rax
mov rdi, rbx
shl rdi, 4
add rdi, rax
mov rdx, r12
shl rdx, 4
call qword ptr [rip + memmove@GOTPCREL]
.LBB25_3:
add rbx, r12
mov qword ptr [r15 + 16], rbx
.LBB25_4:
pop rbx
pop r12
pop r13
pop r14
pop r15
ret
mov r15, rax
mov rdi, qword ptr [rbx - 16]
mov rax, qword ptr [rbx - 8]
mov rsi, qword ptr [rax + 8]
mov rdx, qword ptr [rax + 16]
call alloc::alloc::box_free
.LBB25_13:
test r12, r12
je .LBB25_5
lea r13, [rbx + 16]
add r12, -16
mov rdi, rbx
call core::ptr::drop_in_place<playground::Task>
mov rbx, r13
jmp .LBB25_13
.LBB25_5:
mov rdi, r14
call core::ptr::drop_in_place<<alloc::vec::drain::Drain<T,A> as core::ops::drop::Drop>::drop::DropGuard<playground::Task,alloc::alloc::Global>>
mov rdi, r15
call _Unwind_Resume@PLT
ud2
call qword ptr [rip + core::panicking::panic_no_unwind@GOTPCREL]
ud2
core::ptr::drop_in_place<alloc::rc::Rc<core::cell::Cell<bool>>>:
dec qword ptr [rdi]
jne .LBB26_2
dec qword ptr [rdi + 8]
je .LBB26_3
.LBB26_2:
ret
.LBB26_3:
mov esi, 24
mov edx, 8
jmp qword ptr [rip + __rust_dealloc@GOTPCREL]
core::ptr::drop_in_place<alloc::rc::RcBox<playground::ExecutorInner>>:
add rdi, 16
jmp core::ptr::drop_in_place<playground::ExecutorInner>
core::ptr::drop_in_place<alloc::rc::RcBox<playground::EventHandleInner>>:
push r14
push rbx
push rax
mov rbx, rdi
add rdi, 16
call qword ptr [rip + <playground::EventHandleInner as core::ops::drop::Drop>::drop@GOTPCREL]
mov rbx, qword ptr [rbx + 24]
dec qword ptr [rbx]
jne .LBB28_7
lea rdi, [rbx + 16]
call core::ptr::drop_in_place<playground::ExecutorInner>
dec qword ptr [rbx + 8]
je .LBB28_3
.LBB28_7:
add rsp, 8
pop rbx
pop r14
ret
.LBB28_3:
mov esi, 128
mov edx, 8
mov rdi, rbx
add rsp, 8
pop rbx
pop r14
jmp qword ptr [rip + __rust_dealloc@GOTPCREL]
mov r14, rax
mov rdi, qword ptr [rbx + 24]
call core::ptr::drop_in_place<playground::Executor>
mov rdi, r14
call _Unwind_Resume@PLT
ud2
call qword ptr [rip + core::panicking::panic_no_unwind@GOTPCREL]
ud2
core::ptr::drop_in_place<core::cell::RefCell<alloc::vec::Vec<playground::Task>>>:
add rdi, 8
jmp core::ptr::drop_in_place<alloc::vec::Vec<playground::Task>>
core::ptr::drop_in_place<slab::Entry<alloc::rc::Rc<core::cell::Cell<bool>>>>:
cmp qword ptr [rdi], 0
je .LBB30_3
mov rdi, qword ptr [rdi + 8]
dec qword ptr [rdi]
jne .LBB30_3
dec qword ptr [rdi + 8]
je .LBB30_4
.LBB30_3:
ret
.LBB30_4:
mov esi, 24
mov edx, 8
jmp qword ptr [rip + __rust_dealloc@GOTPCREL]
<&mut W as core::fmt::Write>::write_char:
push rax
mov rdi, qword ptr [rdi]
call <alloc::string::String as core::fmt::Write>::write_char
xor eax, eax
pop rcx
ret
<&mut W as core::fmt::Write>::write_fmt:
sub rsp, 72
mov rax, qword ptr [rdi]
mov qword ptr [rsp + 8], rax
movups xmm0, xmmword ptr [rsi]
movups xmm1, xmmword ptr [rsi + 16]
movups xmm2, xmmword ptr [rsi + 32]
movaps xmmword ptr [rsp + 48], xmm2
movaps xmmword ptr [rsp + 32], xmm1
movaps xmmword ptr [rsp + 16], xmm0
lea rsi, [rip + .L__unnamed_3]
lea rdi, [rsp + 8]
lea rdx, [rsp + 16]
call qword ptr [rip + core::fmt::write@GOTPCREL]
add rsp, 72
ret
<&mut W as core::fmt::Write>::write_str:
push r15
push r14
push r12
push rbx
push rax
mov r14, rdx
mov r15, rsi
mov r12, qword ptr [rdi]
mov rax, qword ptr [r12]
mov rbx, qword ptr [r12 + 16]
sub rax, rbx
cmp rax, rdx
jb .LBB33_1
.LBB33_2:
mov rdi, qword ptr [r12 + 8]
add rdi, rbx
mov rsi, r15
mov rdx, r14
call qword ptr [rip + memcpy@GOTPCREL]
add rbx, r14
mov qword ptr [r12 + 16], rbx
xor eax, eax
add rsp, 8
pop rbx
pop r12
pop r14
pop r15
ret
.LBB33_1:
mov rdi, r12
mov rsi, rbx
mov rdx, r14
call alloc::raw_vec::RawVec<T,A>::reserve::do_reserve_and_handle
mov rbx, qword ptr [r12 + 16]
jmp .LBB33_2
<alloc::string::String as core::fmt::Write>::write_char:
push rbp
push r14
push rbx
sub rsp, 16
mov ebp, esi
mov rbx, rdi
cmp esi, 128
jae .LBB34_1
mov rsi, qword ptr [rbx + 16]
cmp rsi, qword ptr [rbx]
jne .LBB34_6
mov rdi, rbx
call alloc::raw_vec::RawVec<T,A>::reserve_for_push
mov rsi, qword ptr [rbx + 16]
.LBB34_6:
mov rax, qword ptr [rbx + 8]
mov byte ptr [rax + rsi], bpl
inc rsi
mov qword ptr [rbx + 16], rsi
jmp .LBB34_12
.LBB34_1:
mov dword ptr [rsp + 12], 0
mov eax, ebp
cmp ebp, 2048
jae .LBB34_2
shr eax, 6
or al, -64
mov byte ptr [rsp + 12], al
and bpl, 63
or bpl, -128
mov byte ptr [rsp + 13], bpl
mov r14d, 2
jmp .LBB34_9
.LBB34_2:
cmp ebp, 65536
jae .LBB34_8
shr eax, 12
or al, -32
mov byte ptr [rsp + 12], al
mov eax, ebp
shr eax, 6
and al, 63
or al, -128
mov byte ptr [rsp + 13], al
and bpl, 63
or bpl, -128
mov byte ptr [rsp + 14], bpl
mov r14d, 3
jmp .LBB34_9
.LBB34_8:
shr eax, 18
and al, 7
or al, -16
mov byte ptr [rsp + 12], al
mov eax, ebp
shr eax, 12
and al, 63
or al, -128
mov byte ptr [rsp + 13], al
mov eax, ebp
shr eax, 6
and al, 63
or al, -128
mov byte ptr [rsp + 14], al
and bpl, 63
or bpl, -128
mov byte ptr [rsp + 15], bpl
mov r14d, 4
.LBB34_9:
mov rax, qword ptr [rbx]
mov rbp, qword ptr [rbx + 16]
sub rax, rbp
cmp rax, r14
jb .LBB34_10
.LBB34_11:
mov rdi, qword ptr [rbx + 8]
add rdi, rbp
lea rsi, [rsp + 12]
mov rdx, r14
call qword ptr [rip + memcpy@GOTPCREL]
add rbp, r14
mov qword ptr [rbx + 16], rbp
.LBB34_12:
xor eax, eax
add rsp, 16
pop rbx
pop r14
pop rbp
ret
.LBB34_10:
mov rdi, rbx
mov rsi, rbp
mov rdx, r14
call alloc::raw_vec::RawVec<T,A>::reserve::do_reserve_and_handle
mov rbp, qword ptr [rbx + 16]
jmp .LBB34_11
<alloc::string::String as core::fmt::Write>::write_str:
push r15
push r14
push r12
push rbx
push rax
mov r14, rdx
mov r15, rsi
mov r12, rdi
mov rax, qword ptr [rdi]
mov rbx, qword ptr [rdi + 16]
sub rax, rbx
cmp rax, rdx
jb .LBB35_1
.LBB35_2:
mov rdi, qword ptr [r12 + 8]
add rdi, rbx
mov rsi, r15
mov rdx, r14
call qword ptr [rip + memcpy@GOTPCREL]
add rbx, r14
mov qword ptr [r12 + 16], rbx
xor eax, eax
add rsp, 8
pop rbx
pop r12
pop r14
pop r15
ret
.LBB35_1:
mov rdi, r12
mov rsi, rbx
mov rdx, r14
call alloc::raw_vec::RawVec<T,A>::reserve::do_reserve_and_handle
mov rbx, qword ptr [r12 + 16]
jmp .LBB35_2
alloc::alloc::box_free:
test rsi, rsi
je .LBB36_1
jmp qword ptr [rip + __rust_dealloc@GOTPCREL]
.LBB36_1:
ret
alloc::raw_vec::finish_grow:
push r15
push r14
push rbx
mov r14, rsi
mov rbx, rdi
test rdx, rdx
je .LBB37_5
mov r15, rdx
cmp qword ptr [rcx + 16], 0
je .LBB37_7
mov rsi, qword ptr [rcx + 8]
test rsi, rsi
je .LBB37_7
mov rdi, qword ptr [rcx]
mov rdx, r15
mov rcx, r14
call qword ptr [rip + __rust_realloc@GOTPCREL]
test rax, rax
jne .LBB37_11
.LBB37_4:
mov qword ptr [rbx + 8], r14
mov qword ptr [rbx + 16], r15
jmp .LBB37_6
.LBB37_7:
test r14, r14
je .LBB37_8
mov rdi, r14
mov rsi, r15
call qword ptr [rip + __rust_alloc@GOTPCREL]
test rax, rax
je .LBB37_4
.LBB37_11:
mov qword ptr [rbx + 8], rax
mov qword ptr [rbx + 16], r14
xor eax, eax
jmp .LBB37_12
.LBB37_5:
mov qword ptr [rbx + 8], r14
mov qword ptr [rbx + 16], 0
.LBB37_6:
mov eax, 1
.LBB37_12:
mov qword ptr [rbx], rax
pop rbx
pop r14
pop r15
ret
.LBB37_8:
mov rax, r15
test rax, rax
jne .LBB37_11
jmp .LBB37_4
alloc::raw_vec::RawVec<T,A>::reserve_for_push:
push r14
push rbx
sub rsp, 56
inc rsi
je .LBB38_10
mov r14, rdi
mov rax, qword ptr [rdi]
lea rcx, [rax + rax]
cmp rcx, rsi
cmova rsi, rcx
cmp rsi, 9
mov ebx, 8
cmovae rbx, rsi
mov rdx, rbx
not rdx
shr rdx, 63
test rax, rax
je .LBB38_3
mov rcx, qword ptr [r14 + 8]
mov rsi, rax
not rsi
shr rsi, 63
mov qword ptr [rsp + 8], rcx
mov qword ptr [rsp + 16], rax
mov qword ptr [rsp + 24], rsi
jmp .LBB38_4
.LBB38_3:
mov qword ptr [rsp + 24], 0
.LBB38_4:
lea rdi, [rsp + 32]
lea rcx, [rsp + 8]
mov rsi, rbx
call alloc::raw_vec::finish_grow
cmp qword ptr [rsp + 32], 0
mov rdi, qword ptr [rsp + 40]
je .LBB38_5
mov rsi, qword ptr [rsp + 48]
movabs rax, -9223372036854775807
cmp rsi, rax
jne .LBB38_8
add rsp, 56
pop rbx
pop r14
ret
.LBB38_5:
mov qword ptr [r14 + 8], rdi
mov qword ptr [r14], rbx
add rsp, 56
pop rbx
pop r14
ret
.LBB38_8:
test rsi, rsi
jne .LBB38_9
.LBB38_10:
call qword ptr [rip + alloc::raw_vec::capacity_overflow@GOTPCREL]
ud2
.LBB38_9:
call qword ptr [rip + alloc::alloc::handle_alloc_error@GOTPCREL]
ud2
alloc::raw_vec::RawVec<T,A>::reserve_for_push:
push r14
push rbx
sub rsp, 56
inc rsi
je .LBB39_10
mov r14, rdi
mov rax, qword ptr [rdi]
lea rcx, [rax + rax]
cmp rcx, rsi
cmova rsi, rcx
cmp rsi, 5
mov ebx, 4
cmovae rbx, rsi
xor edx, edx
mov rcx, rbx
shr rcx, 59
sete dl
mov rsi, rbx
shl rsi, 4
shl rdx, 3
test rax, rax
je .LBB39_3
mov rcx, qword ptr [r14 + 8]
shl rax, 4
mov qword ptr [rsp + 8], rcx
mov qword ptr [rsp + 16], rax
mov qword ptr [rsp + 24], 8
jmp .LBB39_4
.LBB39_3:
mov qword ptr [rsp + 24], 0
.LBB39_4:
lea rdi, [rsp + 32]
lea rcx, [rsp + 8]
call alloc::raw_vec::finish_grow
cmp qword ptr [rsp + 32], 0
mov rdi, qword ptr [rsp + 40]
je .LBB39_5
mov rsi, qword ptr [rsp + 48]
movabs rax, -9223372036854775807
cmp rsi, rax
jne .LBB39_8
add rsp, 56
pop rbx
pop r14
ret
.LBB39_5:
mov qword ptr [r14 + 8], rdi
mov qword ptr [r14], rbx
add rsp, 56
pop rbx
pop r14
ret
.LBB39_8:
test rsi, rsi
jne .LBB39_9
.LBB39_10:
call qword ptr [rip + alloc::raw_vec::capacity_overflow@GOTPCREL]
ud2
.LBB39_9:
call qword ptr [rip + alloc::alloc::handle_alloc_error@GOTPCREL]
ud2
alloc::raw_vec::RawVec<T,A>::reserve::do_reserve_and_handle:
push r14
push rbx
sub rsp, 56
add rsi, rdx
jb .LBB40_10
mov r14, rdi
mov rax, qword ptr [rdi]
lea rcx, [rax + rax]
cmp rcx, rsi
cmova rsi, rcx
cmp rsi, 9
mov ebx, 8
cmovae rbx, rsi
mov rdx, rbx
not rdx
shr rdx, 63
test rax, rax
je .LBB40_3
mov rcx, qword ptr [r14 + 8]
mov rsi, rax
not rsi
shr rsi, 63
mov qword ptr [rsp + 8], rcx
mov qword ptr [rsp + 16], rax
mov qword ptr [rsp + 24], rsi
jmp .LBB40_4
.LBB40_3:
mov qword ptr [rsp + 24], 0
.LBB40_4:
lea rdi, [rsp + 32]
lea rcx, [rsp + 8]
mov rsi, rbx
call alloc::raw_vec::finish_grow
cmp qword ptr [rsp + 32], 0
mov rdi, qword ptr [rsp + 40]
je .LBB40_5
mov rsi, qword ptr [rsp + 48]
movabs rax, -9223372036854775807
cmp rsi, rax
jne .LBB40_8
add rsp, 56
pop rbx
pop r14
ret
.LBB40_5:
mov qword ptr [r14 + 8], rdi
mov qword ptr [r14], rbx
add rsp, 56
pop rbx
pop r14
ret
.LBB40_8:
test rsi, rsi
jne .LBB40_9
.LBB40_10:
call qword ptr [rip + alloc::raw_vec::capacity_overflow@GOTPCREL]
ud2
.LBB40_9:
call qword ptr [rip + alloc::alloc::handle_alloc_error@GOTPCREL]
ud2
alloc::raw_vec::RawVec<T,A>::reserve::do_reserve_and_handle:
push r14
push rbx
sub rsp, 56
add rsi, rdx
jb .LBB41_10
mov r14, rdi
mov rax, qword ptr [rdi]
lea rcx, [rax + rax]
cmp rcx, rsi
cmova rsi, rcx
cmp rsi, 5
mov ebx, 4
cmovae rbx, rsi
xor edx, edx
mov rcx, rbx
shr rcx, 59
sete dl
mov rsi, rbx
shl rsi, 4
shl rdx, 3
test rax, rax
je .LBB41_3
mov rcx, qword ptr [r14 + 8]
shl rax, 4
mov qword ptr [rsp + 8], rcx
mov qword ptr [rsp + 16], rax
mov qword ptr [rsp + 24], 8
jmp .LBB41_4
.LBB41_3:
mov qword ptr [rsp + 24], 0
.LBB41_4:
lea rdi, [rsp + 32]
lea rcx, [rsp + 8]
call alloc::raw_vec::finish_grow
cmp qword ptr [rsp + 32], 0
mov rdi, qword ptr [rsp + 40]
je .LBB41_5
mov rsi, qword ptr [rsp + 48]
movabs rax, -9223372036854775807
cmp rsi, rax
jne .LBB41_8
add rsp, 56
pop rbx
pop r14
ret
.LBB41_5:
mov qword ptr [r14 + 8], rdi
mov qword ptr [r14], rbx
add rsp, 56
pop rbx
pop r14
ret
.LBB41_8:
test rsi, rsi
jne .LBB41_9
.LBB41_10:
call qword ptr [rip + alloc::raw_vec::capacity_overflow@GOTPCREL]
ud2
.LBB41_9:
call qword ptr [rip + alloc::alloc::handle_alloc_error@GOTPCREL]
ud2
<alloc::string::String as core::fmt::Display>::fmt:
mov rdx, rsi
mov rax, qword ptr [rdi + 8]
mov rsi, qword ptr [rdi + 16]
mov rdi, rax
jmp qword ptr [rip + <str as core::fmt::Display>::fmt@GOTPCREL]
<std::panicking::begin_panic::PanicPayload<A> as core::panic::BoxMeUp>::get:
push rax
cmp qword ptr [rdi], 0
je .LBB43_1
lea rdx, [rip + .L__unnamed_5]
mov rax, rdi
pop rcx
ret
.LBB43_1:
call qword ptr [rip + std::process::abort@GOTPCREL]
ud2
<std::panicking::begin_panic::PanicPayload<A> as core::panic::BoxMeUp>::take_box:
push r14
push rbx
push rax
mov rbx, qword ptr [rdi]
mov r14, qword ptr [rdi + 8]
mov qword ptr [rdi], 0
test rbx, rbx
je .LBB44_3
mov edi, 16
mov esi, 8
call qword ptr [rip + __rust_alloc@GOTPCREL]
test rax, rax
je .LBB44_4
mov qword ptr [rax], rbx
mov qword ptr [rax + 8], r14
lea rdx, [rip + .L__unnamed_5]
add rsp, 8
pop rbx
pop r14
ret
.LBB44_3:
call qword ptr [rip + std::process::abort@GOTPCREL]
ud2
.LBB44_4:
mov edi, 16
mov esi, 8
call qword ptr [rip + alloc::alloc::handle_alloc_error@GOTPCREL]
ud2
playground::dummy_raw_waker::no_op:
ret
playground::dummy_raw_waker::clone:
lea rdx, [rip + .L__unnamed_6]
xor eax, eax
ret
<playground::EventHandleInner as core::fmt::Debug>::fmt:
push r14
push rbx
push rax
mov rbx, rsi
mov r14, rdi
mov rdi, rsi
call qword ptr [rip + core::fmt::Formatter::debug_lower_hex@GOTPCREL]
test al, al
je .LBB47_1
mov rdi, r14
mov rsi, rbx
add rsp, 8
pop rbx
pop r14
jmp qword ptr [rip + core::fmt::num::<impl core::fmt::LowerHex for usize>::fmt@GOTPCREL]
.LBB47_1:
mov rdi, rbx
call qword ptr [rip + core::fmt::Formatter::debug_upper_hex@GOTPCREL]
mov rdi, r14
mov rsi, rbx
add rsp, 8
test al, al
je .LBB47_4
pop rbx
pop r14
jmp qword ptr [rip + core::fmt::num::<impl core::fmt::UpperHex for usize>::fmt@GOTPCREL]
.LBB47_4:
pop rbx
pop r14
jmp qword ptr [rip + core::fmt::num::imp::<impl core::fmt::Display for usize>::fmt@GOTPCREL]
<playground::EventHandleInner as core::cmp::PartialEq>::eq:
mov rax, qword ptr [rdi]
mov rcx, qword ptr [rdi + 8]
xor rax, qword ptr [rsi]
xor rcx, qword ptr [rsi + 8]
or rcx, rax
sete al
ret
<playground::EventHandleInner as core::ops::drop::Drop>::drop:
push r15
push r14
push rbx
sub rsp, 16
mov rax, qword ptr [rdi + 8]
cmp qword ptr [rax + 80], 0
jne .LBB49_11
mov rcx, qword ptr [rdi]
mov qword ptr [rax + 80], -1
mov rsi, rcx
shl rsi, 4
add rsi, qword ptr [rax + 112]
lea r15, [rax + 80]
xor edx, edx
cmp qword ptr [rax + 120], rcx
cmova rdx, rsi
jbe .LBB49_4
mov rbx, qword ptr [rax + 96]
mov rsi, qword ptr [rdx]
mov rdi, qword ptr [rdx + 8]
mov qword ptr [rdx], 0
mov qword ptr [rdx + 8], rbx
cmp rsi, 1
jne .LBB49_3
dec qword ptr [rax + 88]
mov qword ptr [rax + 96], rcx
dec qword ptr [rdi]
jne .LBB49_10
dec qword ptr [rdi + 8]
jne .LBB49_10
mov esi, 24
mov edx, 8
call qword ptr [rip + __rust_dealloc@GOTPCREL]
.LBB49_10:
inc qword ptr [r15]
add rsp, 16
pop rbx
pop r14
pop r15
ret
.LBB49_11:
lea rdi, [rip + .L__unnamed_7]
lea rcx, [rip + .L__unnamed_8]
lea r8, [rip + .L__unnamed_9]
lea rdx, [rsp + 8]
mov esi, 16
call qword ptr [rip + core::result::unwrap_failed@GOTPCREL]
ud2
.LBB49_3:
mov qword ptr [rdx], rsi
mov qword ptr [rdx + 8], rdi
.LBB49_4:
lea rdi, [rip + .L__unnamed_1]
lea rdx, [rip + .L__unnamed_10]
mov esi, 11
call qword ptr [rip + core::option::expect_failed@GOTPCREL]
ud2
mov r14, rax
mov rdi, r15
call core::ptr::drop_in_place<core::cell::RefMut<slab::Slab<alloc::rc::Rc<core::cell::Cell<bool>>>>>
mov rdi, r14
call _Unwind_Resume@PLT
ud2
<playground::EventFuture as core::future::future::Future>::poll:
mov rax, qword ptr [rdi]
movzx eax, byte ptr [rax + 16]
test al, al
je .LBB50_2
mov byte ptr [rdi + 16], 1
.LBB50_2:
test al, al
sete al
ret
.LCPI51_0:
.quad 1
.quad 1
playground::Executor::create_event_handle:
push r15
push r14
push r13
push r12
push rbx
sub rsp, 32
mov rbx, qword ptr [rdi]
cmp qword ptr [rbx + 80], 0
jne .LBB51_25
lea r14, [rbx + 80]
mov qword ptr [r14], -1
mov edi, 24
mov esi, 8
call qword ptr [rip + __rust_alloc@GOTPCREL]
test rax, rax
je .LBB51_2
mov r15, rax
movaps xmm0, xmmword ptr [rip + .LCPI51_0]
movups xmmword ptr [rax], xmm0
mov byte ptr [rax + 16], 0
mov r12, qword ptr [rbx + 96]
mov rcx, qword ptr [rbx + 120]
inc qword ptr [rbx + 88]
cmp rcx, r12
jne .LBB51_11
lea rdi, [rbx + 104]
mov qword ptr [rsp + 8], r15
mov qword ptr [rsp], 1
mov rcx, r12
cmp qword ptr [rdi], r12
jne .LBB51_10
mov rsi, r12
call alloc::raw_vec::RawVec<T,A>::reserve_for_push
mov rcx, qword ptr [rbx + 120]
.LBB51_10:
mov rax, qword ptr [rbx + 112]
mov rdx, rcx
shl rdx, 4
movups xmm0, xmmword ptr [rsp]
movups xmmword ptr [rax + rdx], xmm0
inc rcx
mov qword ptr [rbx + 120], rcx
lea rax, [r12 + 1]
mov qword ptr [rbx + 96], rax
jmp .LBB51_19
.LBB51_11:
mov r13, r12
shl r13, 4
add r13, qword ptr [rbx + 112]
xor eax, eax
cmp rcx, r12
cmova rax, r13
jbe .LBB51_13
cmp qword ptr [rax], 0
jne .LBB51_13
mov rax, qword ptr [rax + 8]
mov qword ptr [rbx + 96], rax
cmp qword ptr [r13], 0
je .LBB51_18
mov rdi, qword ptr [r13 + 8]
dec qword ptr [rdi]
jne .LBB51_18
dec qword ptr [rdi + 8]
jne .LBB51_18
mov esi, 24
mov edx, 8
call qword ptr [rip + __rust_dealloc@GOTPCREL]
.LBB51_18:
mov qword ptr [r13], 1
mov qword ptr [r13 + 8], r15
.LBB51_19:
inc qword ptr [rbx]
je .LBB51_28
movaps xmm0, xmmword ptr [rip + .LCPI51_0]
movaps xmmword ptr [rsp], xmm0
mov qword ptr [rsp + 16], r12
mov qword ptr [rsp + 24], rbx
mov edi, 32
mov esi, 8
call qword ptr [rip + __rust_alloc@GOTPCREL]
test rax, rax
je .LBB51_21
movaps xmm0, xmmword ptr [rsp]
movaps xmm1, xmmword ptr [rsp + 16]
movups xmmword ptr [rax + 16], xmm1
movups xmmword ptr [rax], xmm0
inc qword ptr [r14]
add rsp, 32
pop rbx
pop r12
pop r13
pop r14
pop r15
ret
.LBB51_25:
lea rdi, [rip + .L__unnamed_7]
lea rcx, [rip + .L__unnamed_8]
lea r8, [rip + .L__unnamed_11]
mov rdx, rsp
mov esi, 16
call qword ptr [rip + core::result::unwrap_failed@GOTPCREL]
ud2
.LBB51_2:
mov edi, 24
mov esi, 8
call qword ptr [rip + alloc::alloc::handle_alloc_error@GOTPCREL]
jmp .LBB51_3
.LBB51_13:
lea rdi, [rip + .L__unnamed_12]
lea rdx, [rip + .L__unnamed_13]
mov esi, 40
call qword ptr [rip + core::panicking::panic@GOTPCREL]
jmp .LBB51_3
.LBB51_28:
ud2
ud2
.LBB51_21:
mov edi, 32
mov esi, 8
call qword ptr [rip + alloc::alloc::handle_alloc_error@GOTPCREL]
.LBB51_3:
ud2
mov rbx, rax
mov rdi, rsp
call core::ptr::drop_in_place<slab::Entry<alloc::rc::Rc<core::cell::Cell<bool>>>>
jmp .LBB51_5
mov rbx, rax
mov rdi, rsp
call core::ptr::drop_in_place<alloc::rc::RcBox<playground::EventHandleInner>>
jmp .LBB51_5
call qword ptr [rip + core::panicking::panic_no_unwind@GOTPCREL]
ud2
mov rbx, rax
mov rdi, r15
call core::ptr::drop_in_place<alloc::rc::Rc<core::cell::Cell<bool>>>
jmp .LBB51_5
mov rbx, rax
.LBB51_5:
mov rdi, r14
call core::ptr::drop_in_place<core::cell::RefMut<slab::Slab<alloc::rc::Rc<core::cell::Cell<bool>>>>>
mov rdi, rbx
call _Unwind_Resume@PLT
ud2
playground::Executor::notify_event:
push r14
push rbx
push rax
mov rax, qword ptr [rdi]
cmp qword ptr [rax + 80], 0
jne .LBB52_7
lea rbx, [rax + 80]
mov qword ptr [rax + 80], -1
mov rcx, qword ptr [rsi]
mov rdx, qword ptr [rcx + 16]
mov rsi, rdx
shl rsi, 4
add rsi, qword ptr [rax + 112]
xor ecx, ecx
cmp rdx, qword ptr [rax + 120]
cmovb rcx, rsi
jae .LBB52_3
cmp dword ptr [rcx], 1
jne .LBB52_3
mov rax, qword ptr [rcx + 8]
mov byte ptr [rax + 16], 1
inc qword ptr [rbx]
add rsp, 8
pop rbx
pop r14
ret
.LBB52_3:
lea rdi, [rip + .L__unnamed_14]
call std::panicking::begin_panic
ud2
.LBB52_7:
lea rdi, [rip + .L__unnamed_7]
lea rcx, [rip + .L__unnamed_8]
lea r8, [rip + .L__unnamed_14]
mov rdx, rsp
mov esi, 16
call qword ptr [rip + core::result::unwrap_failed@GOTPCREL]
ud2
mov r14, rax
mov rdi, rbx
call core::ptr::drop_in_place<core::cell::RefMut<slab::Slab<alloc::rc::Rc<core::cell::Cell<bool>>>>>
mov rdi, r14
call _Unwind_Resume@PLT
ud2
playground::Executor::event:
push r15
push r14
push rbx
sub rsp, 16
mov rsi, qword ptr [rsi]
cmp qword ptr [rsi + 80], 0
jne .LBB53_9
lea r15, [rsi + 80]
mov qword ptr [rsi + 80], -1
mov rax, qword ptr [rdx]
mov rbx, qword ptr [rax + 16]
mov rdx, rbx
shl rdx, 4
add rdx, qword ptr [rsi + 112]
xor ecx, ecx
cmp rbx, qword ptr [rsi + 120]
cmovb rcx, rdx
jae .LBB53_3
cmp dword ptr [rcx], 1
jne .LBB53_3
mov rdx, qword ptr [rcx + 8]
inc qword ptr [rdx]
je .LBB53_10
mov rcx, qword ptr [rcx + 8]
inc qword ptr [r15]
inc qword ptr [rax]
je .LBB53_10
mov qword ptr [rdi], rcx
mov qword ptr [rdi + 8], rax
mov byte ptr [rdi + 16], 0
mov rax, rdi
add rsp, 16
pop rbx
pop r14
pop r15
ret
.LBB53_3:
lea rdi, [rip + .L__unnamed_15]
call std::panicking::begin_panic
ud2
.LBB53_10:
ud2
ud2
.LBB53_9:
lea rdi, [rip + .L__unnamed_7]
lea rcx, [rip + .L__unnamed_8]
lea r8, [rip + .L__unnamed_15]
lea rdx, [rsp + 8]
mov esi, 16
call qword ptr [rip + core::result::unwrap_failed@GOTPCREL]
ud2
mov r14, rax
mov rdi, r15
call core::ptr::drop_in_place<core::cell::RefMut<slab::Slab<alloc::rc::Rc<core::cell::Cell<bool>>>>>
mov rdi, r14
call _Unwind_Resume@PLT
ud2
playground::Executor::step:
push rbp
push r15
push r14
push r13
push r12
push rbx
sub rsp, 152
mov qword ptr [rsp + 40], 0
lea rax, [rip + .L__unnamed_6]
mov qword ptr [rsp + 48], rax
lea rax, [rsp + 40]
mov qword ptr [rsp + 112], rax
mov rbx, qword ptr [rdi]
cmp qword ptr [rbx + 16], 0
jne .LBB54_1
mov qword ptr [rbx + 16], -1
cmp qword ptr [rbx + 48], 0
mov qword ptr [rsp + 56], rbx
jne .LBB54_10
lea r13, [rbx + 24]
mov qword ptr [rbx + 48], -1
mov r15, qword ptr [rbx + 64]
mov r14, qword ptr [rbx + 72]
mov rax, qword ptr [rbx + 24]
mov rbp, qword ptr [rbx + 40]
sub rax, rbp
cmp rax, r14
jae .LBB54_15
lea r12, [rbx + 48]
mov rdi, r13
mov rsi, rbp
mov rdx, r14
call alloc::raw_vec::RawVec<T,A>::reserve::do_reserve_and_handle
mov rbp, qword ptr [rbx + 40]
.LBB54_15:
mov rdi, rbp
shl rdi, 4
add rdi, qword ptr [rbx + 32]
mov rdx, r14
shl rdx, 4
mov rsi, r15
call qword ptr [rip + memcpy@GOTPCREL]
mov qword ptr [rbx + 72], 0
inc qword ptr [rbx + 48]
add rbp, r14
mov qword ptr [rsp + 16], 0
mov qword ptr [rsp + 24], 8
mov qword ptr [rsp + 32], 0
mov qword ptr [rbx + 40], 0
mov rax, qword ptr [rbx + 32]
mov r15, rbp
shl r15, 4
add r15, rax
mov qword ptr [rsp + 64], r15
mov qword ptr [rsp + 72], rax
mov qword ptr [rsp + 80], rbp
mov qword ptr [rsp + 88], 0
mov qword ptr [rsp + 104], r13
mov qword ptr [rsp + 96], r13
test rbp, rbp
je .LBB54_16
mov ebx, 8
xor ebp, ebp
mov dword ptr [rsp + 12], 0
jmp .LBB54_20
.LBB54_29:
mov rbx, qword ptr [rsp + 24]
mov rbp, qword ptr [rsp + 32]
.LBB54_30:
mov rax, rbp
shl rax, 4
mov qword ptr [rbx + rax], r12
mov qword ptr [rbx + rax + 8], r14
inc rbp
mov qword ptr [rsp + 32], rbp
mov r15, qword ptr [rsp + 64]
mov r13, qword ptr [rsp + 72]
mov al, 1
mov dword ptr [rsp + 12], eax
.LBB54_39:
mov rax, r13
cmp r13, r15
je .LBB54_21
.LBB54_20:
lea r13, [rax + 16]
mov qword ptr [rsp + 72], r13
mov r12, qword ptr [rax] ; Get the next task from the fat pointer
test r12, r12
je .LBB54_21
mov r14, qword ptr [rax + 8] ; Get the next vtable from the fat pointer
mov qword ptr [rsp + 120], r12
mov qword ptr [rsp + 128], r14
mov rdi, r12
lea rsi, [rsp + 112]
call qword ptr [r14 + 24] ; Call the poll function
test al, al ; Check if the task is ready
je .LBB54_36 ; If it is ready, jump to the end
mov qword ptr [rsp + 136], r12 ; Save the task
mov qword ptr [rsp + 144], r14 ; Save the vtable
cmp rbp, qword ptr [rsp + 16] ; Check if the vector is full
jne .LBB54_30 ; If it is not, jump to the end
lea rdi, [rsp + 16]
mov rsi, rbp
call alloc::raw_vec::RawVec<T,A>::reserve_for_push
jmp .LBB54_29
.LBB54_36:
mov rdi, r12
call qword ptr [r14] ; Call the destructor
mov rsi, qword ptr [r14 + 8] ; Get the size of the task
test rsi, rsi ; Check if the size is 0
je .LBB54_39 ; If it is, jump to the end
mov rdx, qword ptr [r14 + 16] ; Get the alignment of the task
mov rdi, r12 ;
call qword ptr [rip + __rust_dealloc@GOTPCREL]
jmp .LBB54_39
.LBB54_16:
mov dword ptr [rsp + 12], 0
.LBB54_21:
lea rdi, [rsp + 64]
call core::ptr::drop_in_place<alloc::vec::drain::Drain<playground::Task>>
mov rbp, qword ptr [rsp + 104]
mov rdi, rbp
mov rbx, qword ptr [rsp + 56]
call core::ptr::drop_in_place<alloc::vec::Vec<playground::Task>>
mov rax, qword ptr [rsp + 32]
mov qword ptr [rbp + 16], rax
movups xmm0, xmmword ptr [rsp + 16]
movups xmmword ptr [rbp], xmm0
cmp qword ptr [rbx + 80], 0
jne .LBB54_24
mov qword ptr [rbx + 80], -1
mov rax, qword ptr [rbx + 112]
mov rcx, qword ptr [rbx + 120]
shl rcx, 4
xor edx, edx
cmp rcx, rdx
jne .LBB54_43
jmp .LBB54_48
.LBB54_44:
add rdx, 16
cmp rcx, rdx
je .LBB54_48
.LBB54_43:
cmp dword ptr [rax + rdx], 1
jne .LBB54_44
mov rsi, qword ptr [rax + rdx + 8]
mov byte ptr [rsi + 16], 0
add rdx, 16
cmp rcx, rdx
jne .LBB54_43
.LBB54_48:
inc qword ptr [rbx + 80]
inc qword ptr [rbx + 16]
mov rdi, qword ptr [rsp + 40]
mov rax, qword ptr [rsp + 48]
call qword ptr [rax + 24]
mov eax, dword ptr [rsp + 12]
and al, 1
add rsp, 152
pop rbx
pop r12
pop r13
pop r14
pop r15
pop rbp
ret
.LBB54_1:
lea rdi, [rip + .L__unnamed_7]
lea rcx, [rip + .L__unnamed_8]
lea r8, [rip + .L__unnamed_16]
lea rdx, [rsp + 64]
mov esi, 16
call qword ptr [rip + core::result::unwrap_failed@GOTPCREL]
jmp .LBB54_2
.LBB54_10:
lea rdi, [rip + .L__unnamed_7]
lea rcx, [rip + .L__unnamed_8]
lea r8, [rip + .L__unnamed_17]
lea rdx, [rsp + 64]
mov esi, 16
call qword ptr [rip + core::result::unwrap_failed@GOTPCREL]
jmp .LBB54_2
.LBB54_24:
lea rdi, [rip + .L__unnamed_7]
lea rcx, [rip + .L__unnamed_8]
lea r8, [rip + .L__unnamed_18]
lea rdx, [rsp + 64]
mov esi, 16
call qword ptr [rip + core::result::unwrap_failed@GOTPCREL]
.LBB54_2:
ud2
mov rbx, rax
mov rdi, r12
call core::ptr::drop_in_place<core::cell::RefMut<slab::Slab<alloc::rc::Rc<core::cell::Cell<bool>>>>>
jmp .LBB54_8
jmp .LBB54_7
mov rbx, rax
mov rax, qword ptr [rsp + 32]
mov qword ptr [rbp + 16], rax
movups xmm0, xmmword ptr [rsp + 16]
movups xmmword ptr [rbp], xmm0
jmp .LBB54_8
mov rbx, rax
jmp .LBB54_47
.LBB54_7:
mov rbx, rax
jmp .LBB54_8
mov rbx, rax
jmp .LBB54_4
mov rbx, rax
lea rdi, [rsp + 136]
call core::ptr::drop_in_place<playground::Task>
jmp .LBB54_35
call qword ptr [rip + core::panicking::panic_no_unwind@GOTPCREL]
ud2
mov rbx, rax
mov rsi, qword ptr [r14 + 8]
mov rdx, qword ptr [r14 + 16]
mov rdi, r12
call alloc::alloc::box_free
jmp .LBB54_35
mov rbx, rax
lea rdi, [rsp + 120]
call core::ptr::drop_in_place<playground::Task>
.LBB54_35:
lea rdi, [rsp + 64]
call core::ptr::drop_in_place<alloc::vec::drain::Drain<playground::Task>>
.LBB54_47:
lea rdi, [rsp + 16]
call core::ptr::drop_in_place<alloc::vec::Vec<playground::Task>>
.LBB54_8:
mov rdi, qword ptr [rsp + 56]
add rdi, 16
call core::ptr::drop_in_place<core::cell::RefMut<slab::Slab<alloc::rc::Rc<core::cell::Cell<bool>>>>>
.LBB54_4:
mov rdi, qword ptr [rsp + 40]
mov rsi, qword ptr [rsp + 48]
call core::ptr::drop_in_place<core::task::wake::Waker>
mov rdi, rbx
call _Unwind_Resume@PLT
ud2
call qword ptr [rip + core::panicking::panic_no_unwind@GOTPCREL]
ud2
<playground::UnitGotoFuture as core::future::future::Future>::poll:
push rax
mov rax, qword ptr [rdi]
mov rsi, qword ptr [rax + 16]
movabs rcx, 9223372036854775807
cmp rsi, rcx
jae .LBB55_5
mov ecx, dword ptr [rax + 24]
mov edx, dword ptr [rdi + 8]
mov edi, edx
sub edi, ecx
je .LBB55_4
test rsi, rsi
jne .LBB55_6
xor esi, esi
test edi, edi
setg sil
lea esi, [rcx + 2*rsi]
dec esi
mov dword ptr [rax + 24], esi
mov qword ptr [rax + 16], 0
.LBB55_4:
cmp edx, ecx
setne al
pop rcx
ret
.LBB55_5:
lea rdi, [rip + .L__unnamed_19]
lea rcx, [rip + .L__unnamed_20]
lea r8, [rip + .L__unnamed_21]
mov rdx, rsp
mov esi, 24
call qword ptr [rip + core::result::unwrap_failed@GOTPCREL]
ud2
.LBB55_6:
lea rdi, [rip + .L__unnamed_7]
lea rcx, [rip + .L__unnamed_8]
lea r8, [rip + .L__unnamed_22]
mov rdx, rsp
mov esi, 16
call qword ptr [rip + core::result::unwrap_failed@GOTPCREL]
ud2
; Input:
; rdi: &mut playground::UnitGotoFuture
; rsi: *mut Context
playground::goto:
mov rax, rdi ; rax = Set the return value to the future
mov qword ptr [rdi + 16], rsi ; Save the unit
mov dword ptr [rdi + 24], edx ; Save the target_pos
mov byte ptr [rdi + 28], 0 ; Set state to 0
ret ; Return
; Input:
; rdi: &mut playground::UnitGotoFuture
; rsi: *mut Context
; rdx: usize
; Output:
; rax: &mut playground::UnitGotoFuture
playground::goto::{{closure}}:
push rbp
push r15
push r14
push rbx
push rax
mov r15, rdi
movzx eax, byte ptr [rdi + 28] ; Load the state to determine which block to execute. The state is stored in the 28 offset in the closure environment.
lea rcx, [rip + .LJTI57_0] ; Load the address of the jump table rcx. The jump table is a list of offsets from the start of the jump table to each block.
movsxd rax, dword ptr [rcx + 4*rax]; Get the jump offset from the entry corresponding to the state. The index in rax is multiplied by 4 because the jump table is an array of 32-bit jump offsets indexed by the state.
add rax, rcx ; Add the jump offset to the start of the jump table to get the address of the block to execute.
jmp rax ; Jump to the block to execute.
.LBB57_4:
mov rdi, qword ptr [r15 + 16] ; Load the unit from the closure environment into rdi
mov eax, dword ptr [r15 + 24] ; Load the target_pos from the closure environment into eax
mov qword ptr [r15], rdi ; Save the unit in the closure environment
mov dword ptr [r15 + 8], eax ; Save the target_pos in the closure environment
jmp .LBB57_5
.LBB57_1:
; Resuming the future after a poll that returned Pending
mov rdi, qword ptr [r15] ; Load the unit from the closure environment into rdi
.LBB57_5:
; Inlined call to UnitGotoFuture::poll
mov rax, qword ptr [rdi + 16] ; Load the borrow flag from unit's RefCell into rax
movabs rcx, 9223372036854775807 ; Load the maximum signed 64-bit integer rcx
cmp rax, rcx ; Check if the borrow flag is greater than max signed 64 bit value.
jae .LBB57_6 ; If the value in rax is greater than or equal to max signed 64-bit value, jump to .LBB57_6 as the unit has already been borrowed.
; The unit has not been borrowed
mov ebx, dword ptr [rdi + 24] ; Load the unit_pos from unit into ebx
mov ebp, dword ptr [r15 + 8] ; Load the target_pos from the closure environment into ebp
mov ecx, ebp ; Set ecx to target_pos
sub ecx, ebx ; Subtract unit_pos from target_pos and store the result in ecx
jne .LBB57_8 ; If the difference is not equal to 0, jump as the unit has not reached the target position
dec qword ptr [rdi] ; Decrement the strong reference count of the unit
mov r14b, 1 ; Set the state to 1
jne .LBB57_17 ; Check if the strong reference count is not equal to 0. If it is not equal to 0, jump to .LBB57_17
; ♻️ Freeing Rc memory as the reference count is 0
dec qword ptr [rdi + 8] ; Decrement the weak reference count of the unit
jne .LBB57_17 ; Jump if the weak reference count is not equal to 0.
mov esi, 32 ; Set the size of the memory to free to 32
mov edx, 8 ; Set the alignment of the memory to free to 8
call qword ptr [rip + __rust_dealloc@GOTPCREL] ; Call __rust_dealloc to free the memory
jmp .LBB57_17
.LBB57_8:
test rax, rax ; Check if the borrow flag is 0
jne .LBB57_9 ; If the borrow flag is not 0, jump to .LBB57_9 as the unit has already been borrowed.
xor eax, eax ; Set eax to 0
; signum function inlined - begin
test ecx, ecx ; Check if the unit_pos is greater than the target_pos
setg al ; Set the value of al to 1 if unit_pos is greater than target_pos
; Set the value of al to 0 if unit_pos is less than or equal to target_pos
lea eax, [rbx + 2*rax] ; Add 2 to unit_pos if unit_pos is less than target_pos
dec eax ; Subtract 1 from the result of the previous addition (signum addition of 1 or -1)
; signum function inlined - end
mov dword ptr [rdi + 24], eax ; Save the new unit_pos in the unit
mov qword ptr [rdi + 16], 0 ; Set the borrow flag to 0
mov r14b, 3 ; Set the state to 3
.LBB57_17:
cmp ebp, ebx ; Compare unit_pos with target_pos
setne al ; Set the value of al to 1 (future not ready) if unit_pos is not equal to target_pos
; Set the value of al to 0 (future ready) if unit_pos is equal to target_pos
mov byte ptr [r15 + 28], r14b ; Save the state in the closure environment
add rsp, 8 ; Free local variables
pop rbx
pop r14
pop r15
pop rbp
ret ; Return the future status
.LBB57_6:
; 💀 Prepare the panic message
lea r8, [rip + .L__unnamed_21]
lea rcx, [rip + .L__unnamed_20] ; drop_in_place
mov esi, 24
lea rdi, [rip + .L__unnamed_19] ; Load "already borrowed"
jmp .LBB57_10
; playground::goto::{{closure}}::{{closure}}:
.LBB57_2:
lea rdi, [rip + str.1] ; Load address of string "`async fn` resumed after panicking"
lea rdx, [rip + .L__unnamed_23]
mov esi, 34
call qword ptr [rip + core::panicking::panic@GOTPCREL]
ud2
; playground::goto::{{closure}}::{{closure}}:
.LBB57_3:
lea rdi, [rip + str.2] ; Load address of string "`async fn` resumed after completion"
lea rdx, [rip + .L__unnamed_23]
mov esi, 35
call qword ptr [rip + core::panicking::panic@GOTPCREL]
ud2
.LBB57_9:
lea r8, [rip + .L__unnamed_22]
lea rcx, [rip + .L__unnamed_8]
mov esi, 16
lea rdi, [rip + .L__unnamed_7]
.LBB57_10:
mov rdx, rsp
call qword ptr [rip + core::result::unwrap_failed@GOTPCREL]
ud2
mov r14, rax
mov rdi, qword ptr [r15]
call core::ptr::drop_in_place<playground::UnitGotoFuture>
mov byte ptr [r15 + 28], 2
mov rdi, r14
call _Unwind_Resume@PLT
ud2
.LJTI57_0:
.long .LBB57_4-.LJTI57_0 ; UnitState0 ; Entry point to the goto closure
.long .LBB57_3-.LJTI57_0 ; UnitState1: 🛑 Throw a panic for a poll after completion of the future
.long .LBB57_2-.LJTI57_0 ; UnitState2:
.long .LBB57_1-.LJTI57_0 ; UnitState3; Future is pending
; Inputs:
; rdi: closure environment
; rsi: task_context
; Returns:
; rax: result
playground::patrol::{{closure}}:
push r15 ; Save the callee-saved registers
push r14
push rbx
mov r14, rsi ; Store the task_context in r14. The task_context is passed as the second argument to the closure.
mov rbx, rdi ; Store the closure environment in rbx. The environment is passed as the first argument to the closure.
movzx eax, byte ptr [rdi + 32] ; Load the state to determine which block to execute. The state is stored in the 32nd byte of the closure environment.
lea rcx, [rip + .LJTI58_0] ; Load the address of the jump table rcx. The jump table is a list of offsets from the start of the jump table to each block.
movsxd rax, dword ptr [rcx + 4*rax] ; Get the jump offset from the entry corresponding to the state. The index in rax is multiplied by 4 because the jump table is an array of 32-bit jump offsets indexed by the state.
add rax, rcx ; Add the jump offset to the jump table to determine the address of the block to execute.
jmp rax ; Jump to the correct block.
.LBB58_1:
; ⌛state 0: Code executed before the first future is polled.
; At this point rbx contains the closure environment and r14 contains the task_context.
; Block 0: Code executed when the future is first polled
mov rcx, qword ptr [rbx] ; Load the captured poses array from the closure environment
mov rax, qword ptr [rbx + 24] ; Load the captured Rc<RefCell<Unit>> from the closure environment
mov qword ptr [rbx + 8], rax ; Store the captured Rc<RefCell<Unit>> in a local variable saved in the closure environment
mov qword ptr [rbx + 16], rcx ; Store the captured poses array in a local variable saved in the closure environment
jmp .LBB58_4 ; Jump to the next block
.LBB58_2:
; ⌛🛑 state 2: Panic.
lea rdi, [rip + str.1]
lea rdx, [rip + .L__unnamed_24]
mov esi, 34
call qword ptr [rip + core::panicking::panic@GOTPCREL]
.LBB58_3:
; ⌛🛑 state 1: Throw exception.
ud2
.LBB58_4:
; At this point rbx contains the closure environment and rax points to Rc<RefCell<Unit>>.
; ⌛state 0: Getting ready to wait for poses[0]
; Increment the Rc<RefCell<Unit>> reference count
inc qword ptr [rax] ; Increment the strong reference count for Rc<RefCell<Unit>>. The strong reference count is stored in the first 8 bytes of the Rc<RefCell<Unit>>.
je .LBB58_28 ; The reference count is 0, jump to undefined behavior. This should never happen.
mov ecx, dword ptr [rbx + 16] ; Load the poses[0] from the closure environment
; Clone the Rc<RefCell<Unit>> to get a new reference to the Unit stored in the closure environment
; Prepare UnitGotoFuture. The UnitGotoFuture is a future that will wait for the Unit to reach the specified position.
mov qword ptr [rbx + 56], rax ; Copy the Rc<RefCell<Unit>> to the goto::{{closure}} environment
mov dword ptr [rbx + 64], ecx ; Save the poses[0] to the goto::{{closure}} environment
mov byte ptr [rbx + 68], 0; Set the initial state for the goto::{{closure}} to 0
.LBB58_6:
; ⌛state 3: Waiting for poses[0]
lea r15, [rbx + 40] ; Load the address of the environment for the goto::{{closure}}
mov rdi, r15 ; Load the address of the environment to the first argument register
mov rsi, r14 ; Load the task_context to the second argument register
call playground::goto::{{closure}} ; Call the goto::{{closure}} closure
test al, al ; Check if the future is ready
jne .LBB58_25 ; The future is not ready, save state and return
; The future is ready, continue executing the patrol::{{closure}} closure
movzx eax, byte ptr [rbx + 68] ; Load the state of the goto::{{closure}} closure
test eax, eax ; Check if the goto's state is 0
je .LBB58_11 ; Goto's state is 0, proceed to the next goto closure after decrementing the reference count for goto's unit at offset 56 in patrol::{{closure}}'s environment
cmp eax, 3 ; Check if the goto's state is 3
jne .LBB58_14 ; The goto's state is not 0 or 3, proceed to the next goto closure without decrementing the reference count for goto's unit
; The goto's state is 3, decrement the reference count using the goto::{{closure}} environment's unit at offset 40 in patrol::{{closure}}'s environment
mov rdi, qword ptr [r15] ; Load the Rc<RefCell<Unit>> from the goto::{{closure}} environment
dec qword ptr [rdi] ; Decrement the reference count for unit
jne .LBB58_14 ; The reference count is not 0, do not deallocate the unit at offset 40 in patrol::{{closure}}'s environment
jmp .LBB58_12
.LBB58_11:
mov rdi, qword ptr [rbx + 56] ; Load Rc<RefCell<Unit>> from the environment
dec qword ptr [rdi] ; Decrement the reference count for unit
jne .LBB58_14 ; The reference count is not 0, do not deallocate the unit
.LBB58_12:
dec qword ptr [rdi + 8] ; Decrement the reference count for unit
jne .LBB58_14 ; The reference count is not 0, jump to the next block
mov esi, 32 ; Load the size of the allocation
mov edx, 8 ; Load the alignment of the allocation
call qword ptr [rip + __rust_dealloc@GOTPCREL] ; Deallocate the allocation
.LBB58_14:
mov rax, qword ptr [rbx + 8] ; Load the Rc<RefCell<Unit>> from the environment
inc qword ptr [rax] ; Increment the reference count for unit
je .LBB58_28 ; The reference count is 0, jump to undefined behavior. This should never happen.
; Prepare to wait for goto::{{closure}} environment
mov ecx, dword ptr [rbx + 20] ; Load poses[1] from the environment
mov qword ptr [rbx + 56], rax ; Store the Rc<RefCell<Unit>> in the goto::{{closure}} environment
mov dword ptr [rbx + 64], ecx ; Store the poses[1] in the goto::{{closure}} environment
mov byte ptr [rbx + 68], 0 ; Store the goto closure's initial state
.LBB58_16:
; ⌛state 4: Waiting for poses[1]
lea r15, [rbx + 40] ; Get the address of the goto closure environment
mov rdi, r15 ; Load the address of the goto closure environment to the first argument register
mov rsi, r14 ; Load the task_context to the second argument register
call playground::goto::{{closure}} ; Call the goto closure
test al, al ; Check if the future is ready
jne .LBB58_26 ; The future is not ready, set the⌛state to 4 and return
movzx eax, byte ptr [rbx + 68] ; Load the goto closure state
test eax, eax ; Check if the state is 0
je .LBB58_21 ; The state is 0, jump to the next block
cmp eax, 3 ; Check if goto's state is 3
jne .LBB58_24 ; The state is not 3, jump to the next block
mov rdi, qword ptr [r15] ; Load the goto closure environment unit
dec qword ptr [rdi] ; Decrement the reference count for unit
jne .LBB58_24 ; The reference count is not 0, jump to the next block
jmp .LBB58_22 ; The reference count is 0, jump to the next block
.LBB58_21:
mov rdi, qword ptr [rbx + 56] ; Load Rc<RefCell<Unit>> from the environment
dec qword ptr [rdi] ; Decrement the strong reference count for unit
jne .LBB58_24 ; The reference count is not 0, skip deallocating the unit
.LBB58_22:
; Strong reference count is 0, decrement the weak reference count
dec qword ptr [rdi + 8] ; Decrement the weak reference count for unit
jne .LBB58_24 ; The weak reference count is not 0, jump to the next block
; The weak reference count is 0, deallocate the unit
mov esi, 32 ; Size of unit
mov edx, 8 ; Alignment of unit
call qword ptr [rip + __rust_dealloc@GOTPCREL] ; Deallocate the unit
.LBB58_24:
mov rax, qword ptr [rbx + 8] ; Load the Rc<RefCell<Unit>> from the environment into rax
jmp .LBB58_4 ; Jump to the beginning of the loop
.LBB58_25:
mov al, 3 ; Set the ⌛state to 3 for the next time the function is called.
jmp .LBB58_27 ; Jump to return
.LBB58_26:
mov al, 4 ; Set the ⌛state to 4 ; Set the state to 4 for the next time the function is called.
.LBB58_27:
; The function is about to return, store the updated state
; so that the next time the function is called, it will continue
; from the correct block.
mov byte ptr [rbx + 32], al ; Store the updated ⌛state
mov al, 1 ; Set the future to ready
pop rbx
pop r14
pop r15
ret
; The reference count was found to be 0 after an increment, jump to undefined behavior. This should never happen.
.LBB58_28:
ud2 ; Undefined instruction
ud2
jmp .LBB58_31 ; Drop memory and unwind the stack
.LBB58_31:
mov r14, rax
mov rdi, r15
call core::ptr::drop_in_place<playground::goto::{{closure}}>
mov rdi, qword ptr [rbx + 8]
call core::ptr::drop_in_place<playground::UnitGotoFuture>
mov byte ptr [rbx + 32], 2
mov rdi, r14
call _Unwind_Resume@PLT
ud2
.LJTI58_0:
.long .LBB58_1-.LJTI58_0 ; ⌛state 0: Code executed before the first future is polled.
.long .LBB58_3-.LJTI58_0 ; ⌛🛑state 1: Throw exception.
.long .LBB58_2-.LJTI58_0 ; ⌛🛑state 2: Panic.
.long .LBB58_6-.LJTI58_0 ; ⌛state 3: Waiting for poses[0]
.long .LBB58_16-.LJTI58_0 ;⌛state 4: Waiting for poses[1]
.LCPI59_0:
.quad 1
.quad 1
playground::main:
push rbp
push r15
push r14
push r12
push rbx
sub rsp, 240 ; Save space for locals
xorps xmm0, xmm0
movaps xmmword ptr [rsp + 112], xmm0 ; Initialize locals to 0
mov qword ptr [rsp + 128], 8 ; Initialize locals
movups xmmword ptr [rsp + 136], xmm0 ; Set to 0
mov qword ptr [rsp + 152], 0
mov qword ptr [rsp + 160], 8
movups xmmword ptr [rsp + 168], xmm0
movups xmmword ptr [rsp + 184], xmm0
mov qword ptr [rsp + 200], 0
mov qword ptr [rsp + 208], 8
mov qword ptr [rsp + 216], 0
movaps xmm0, xmmword ptr [rip + .LCPI59_0] ;
movaps xmmword ptr [rsp + 96], xmm0
mov edi, 128 ; Load the size of the allocation
mov esi, 8 ; Load the alignment of the allocation
call qword ptr [rip + __rust_alloc@GOTPCREL] ; Allocate memory
test rax, rax
je .LBB59_1
mov r12, rax
movaps xmm0, xmmword ptr [rsp + 208]
movups xmmword ptr [rax + 112], xmm0
movaps xmm0, xmmword ptr [rsp + 192]
movups xmmword ptr [rax + 96], xmm0
movaps xmm0, xmmword ptr [rsp + 176]
movups xmmword ptr [rax + 80], xmm0
movaps xmm0, xmmword ptr [rsp + 160]
movups xmmword ptr [rax + 64], xmm0
movaps xmm0, xmmword ptr [rsp + 96]
movaps xmm1, xmmword ptr [rsp + 112]
movaps xmm2, xmmword ptr [rsp + 128]
movaps xmm3, xmmword ptr [rsp + 144]
movups xmmword ptr [rax + 48], xmm3
movups xmmword ptr [rax + 32], xmm2
movups xmmword ptr [rax + 16], xmm1
movups xmmword ptr [rax], xmm0
mov qword ptr [rsp + 232], rax
mov edi, 32
mov esi, 8
call qword ptr [rip + __rust_alloc@GOTPCREL]
test rax, rax
je .LBB59_6
mov rbx, rax
movaps xmm0, xmmword ptr [rip + .LCPI59_0]
movups xmmword ptr [rax], xmm0
mov qword ptr [rax + 16], 0
mov dword ptr [rax + 24], 0
mov edi, 32
mov esi, 8
call qword ptr [rip + __rust_alloc@GOTPCREL]
test rax, rax
je .LBB59_8
movaps xmm0, xmmword ptr [rip + .LCPI59_0]
movups xmmword ptr [rax], xmm0
mov qword ptr [rax + 16], 0
mov dword ptr [rax + 24], 0
mov qword ptr [rsp + 8], rbx
mov qword ptr [rsp + 16], rax
inc qword ptr [rbx]
je .LBB59_13
mov qword ptr [rsp + 48], rbx
movabs rax, 25769803771
mov qword ptr [rsp + 24], rax
mov byte ptr [rsp + 56], 0
cmp qword ptr [r12 + 48], 0
jne .LBB59_19
lea r14, [r12 + 48]
mov qword ptr [r12 + 48], -1
mov rax, qword ptr [rsp + 88]
mov qword ptr [rsp + 160], rax
mov r8, qword ptr [rsp + 24]
mov r9, qword ptr [rsp + 32]
mov rdx, qword ptr [rsp + 40]
mov rsi, qword ptr [rsp + 48]
movzx ebx, byte ptr [rsp + 56]
mov rdi, qword ptr [rsp + 57]
mov ebp, dword ptr [rsp + 65]
movzx eax, word ptr [rsp + 69]
movzx ecx, byte ptr [rsp + 71]
movups xmm0, xmmword ptr [rsp + 72]
movaps xmmword ptr [rsp + 144], xmm0
mov byte ptr [rsp + 128], bl
mov qword ptr [rsp + 129], rdi
mov dword ptr [rsp + 137], ebp
mov word ptr [rsp + 141], ax
mov byte ptr [rsp + 143], cl
mov qword ptr [rsp + 112], rdx
mov qword ptr [rsp + 120], rsi
mov qword ptr [rsp + 96], r8
mov qword ptr [rsp + 104], r9
mov edi, 72
mov esi, 8
call qword ptr [rip + __rust_alloc@GOTPCREL]
test rax, rax
je .LBB59_21
mov rbx, rax
lea r15, [r12 + 56]
mov rax, qword ptr [rsp + 88]
mov qword ptr [rbx + 64], rax
movups xmm0, xmmword ptr [rsp + 24]
movups xmm1, xmmword ptr [rsp + 40]
movups xmm2, xmmword ptr [rsp + 56]
movups xmm3, xmmword ptr [rsp + 72]
movups xmmword ptr [rbx + 48], xmm3
movups xmmword ptr [rbx + 32], xmm2
movups xmmword ptr [rbx + 16], xmm1
movups xmmword ptr [rbx], xmm0
mov qword ptr [rsp + 96], rbx
lea rbp, [rip + .L__unnamed_25]
mov qword ptr [rsp + 104], rbp
mov rsi, qword ptr [r12 + 72]
cmp rsi, qword ptr [r12 + 56]
jne .LBB59_27
mov rdi, r15
call alloc::raw_vec::RawVec<T,A>::reserve_for_push
mov rsi, qword ptr [r12 + 72]
.LBB59_27:
mov rax, qword ptr [r12 + 64]
mov rcx, rsi
shl rcx, 4
mov qword ptr [rax + rcx], rbx
mov qword ptr [rax + rcx + 8], rbp
inc rsi
mov qword ptr [r12 + 72], rsi
inc qword ptr [r12 + 48]
mov rax, qword ptr [rsp + 16]
inc qword ptr [rax]
je .LBB59_13
mov rax, qword ptr [rsp + 16]
mov qword ptr [rsp + 40], rax
mov dword ptr [rsp + 48], 12
mov byte ptr [rsp + 52], 0
cmp qword ptr [r14], 0
jne .LBB59_29
mov qword ptr [r14], -1
movups xmm0, xmmword ptr [rsp + 24]
mov rax, qword ptr [rsp + 40]
mov qword ptr [rsp + 112], rax
mov eax, dword ptr [rsp + 48]
mov dword ptr [rsp + 120], eax
movzx eax, byte ptr [rsp + 52]
mov byte ptr [rsp + 124], al
movzx eax, word ptr [rsp + 53]
mov word ptr [rsp + 125], ax
movzx eax, byte ptr [rsp + 55]
mov byte ptr [rsp + 127], al
movaps xmmword ptr [rsp + 96], xmm0
mov edi, 32
mov esi, 8
call qword ptr [rip + __rust_alloc@GOTPCREL]
test rax, rax
je .LBB59_35
mov rbx, rax
movups xmm0, xmmword ptr [rsp + 24]
movups xmm1, xmmword ptr [rsp + 40]
movups xmmword ptr [rax + 16], xmm1
movups xmmword ptr [rax], xmm0
mov qword ptr [rsp + 96], rax
lea rbp, [rip + .L__unnamed_26]
mov qword ptr [rsp + 104], rbp
mov rsi, qword ptr [r12 + 72]
cmp rsi, qword ptr [r12 + 56]
jne .LBB59_40
mov rdi, r15
call alloc::raw_vec::RawVec<T,A>::reserve_for_push
mov rsi, qword ptr [r12 + 72]
.LBB59_40:
mov rax, qword ptr [r12 + 64]
mov rcx, rsi
shl rcx, 4
mov qword ptr [rax + rcx], rbx
mov qword ptr [rax + rcx + 8], rbp
inc rsi
mov qword ptr [r12 + 72], rsi
inc qword ptr [r12 + 48]
lea rdi, [rsp + 8]
call playground::main::{{closure}}
mov ebp, 31
lea r14, [rsp + 232]
mov r15, qword ptr [rip + playground::Executor::step@GOTPCREL]
lea rbx, [rsp + 8]
.LBB59_42:
dec ebp
je .LBB59_43
mov rdi, r14
call r15
mov rdi, rbx
call playground::main::{{closure}}
jmp .LBB59_42
.LBB59_43:
mov rdi, qword ptr [rsp + 8]
dec qword ptr [rdi]
jne .LBB59_46
dec qword ptr [rdi + 8]
je .LBB59_45
.LBB59_46:
mov rdi, qword ptr [rsp + 16]
dec qword ptr [rdi]
jne .LBB59_49
.LBB59_47:
dec qword ptr [rdi + 8]
jne .LBB59_49
mov esi, 32
mov edx, 8
call qword ptr [rip + __rust_dealloc@GOTPCREL]
jmp .LBB59_49
.LBB59_45:
mov esi, 32
mov edx, 8
call qword ptr [rip + __rust_dealloc@GOTPCREL]
mov rdi, qword ptr [rsp + 16]
dec qword ptr [rdi]
je .LBB59_47
.LBB59_49:
dec qword ptr [r12]
jne .LBB59_52
mov rdi, r12
add rdi, 16
call core::ptr::drop_in_place<playground::ExecutorInner>
dec qword ptr [r12 + 8]
jne .LBB59_52
mov esi, 128
mov edx, 8
mov rdi, r12
call qword ptr [rip + __rust_dealloc@GOTPCREL]
.LBB59_52:
add rsp, 240
pop rbx
pop r12
pop r14
pop r15
pop rbp
ret
.LBB59_13:
ud2
ud2
.LBB59_1:
mov edi, 128
mov esi, 8
call qword ptr [rip + alloc::alloc::handle_alloc_error@GOTPCREL]
jmp .LBB59_2
.LBB59_6:
mov edi, 32
mov esi, 8
call qword ptr [rip + alloc::alloc::handle_alloc_error@GOTPCREL]
jmp .LBB59_2
.LBB59_8:
mov edi, 32
mov esi, 8
call qword ptr [rip + alloc::alloc::handle_alloc_error@GOTPCREL]
jmp .LBB59_2
.LBB59_19:
lea rdi, [rip + .L__unnamed_7]
lea rcx, [rip + .L__unnamed_8]
lea r8, [rip + .L__unnamed_27]
lea rdx, [rsp + 96]
mov esi, 16
call qword ptr [rip + core::result::unwrap_failed@GOTPCREL]
jmp .LBB59_2
.LBB59_21:
mov edi, 72
mov esi, 8
call qword ptr [rip + alloc::alloc::handle_alloc_error@GOTPCREL]
jmp .LBB59_2
.LBB59_29:
lea rdi, [rip + .L__unnamed_7]
lea rcx, [rip + .L__unnamed_8]
lea r8, [rip + .L__unnamed_27]
lea rdx, [rsp + 96]
mov esi, 16
call qword ptr [rip + core::result::unwrap_failed@GOTPCREL]
jmp .LBB59_2
.LBB59_35:
mov edi, 32
mov esi, 8
call qword ptr [rip + alloc::alloc::handle_alloc_error@GOTPCREL]
.LBB59_2:
ud2
mov r15, rax
lea rdi, [rsp + 96]
call core::ptr::drop_in_place<playground::Task>
jmp .LBB59_23
call qword ptr [rip + core::panicking::panic_no_unwind@GOTPCREL]
ud2
mov r15, rax
lea rdi, [rsp + 96]
call core::ptr::drop_in_place<playground::Task>
jmp .LBB59_23
call qword ptr [rip + core::panicking::panic_no_unwind@GOTPCREL]
ud2
jmp .LBB59_16
mov r15, rax
lea rdi, [rsp + 96]
call core::ptr::drop_in_place<playground::goto::{{closure}}>
jmp .LBB59_23
mov r15, rax
lea rdi, [rsp + 24]
call core::ptr::drop_in_place<playground::goto::{{closure}}>
jmp .LBB59_17
mov r15, rax
lea rdi, [rsp + 96]
call core::ptr::drop_in_place<playground::patrol::{{closure}}>
.LBB59_23:
mov rdi, r14
call core::ptr::drop_in_place<core::cell::RefMut<slab::Slab<alloc::rc::Rc<core::cell::Cell<bool>>>>>
jmp .LBB59_17
call qword ptr [rip + core::panicking::panic_no_unwind@GOTPCREL]
ud2
mov r15, rax
lea rdi, [rsp + 24]
call core::ptr::drop_in_place<playground::patrol::{{closure}}>
jmp .LBB59_17
call qword ptr [rip + core::panicking::panic_no_unwind@GOTPCREL]
ud2
mov r15, rax
mov rdi, rbx
call core::ptr::drop_in_place<playground::UnitGotoFuture>
jmp .LBB59_10
mov r15, rax
jmp .LBB59_10
mov r15, rax
lea rdi, [rsp + 96]
call core::ptr::drop_in_place<alloc::rc::RcBox<playground::ExecutorInner>>
jmp .LBB59_4
call qword ptr [rip + core::panicking::panic_no_unwind@GOTPCREL]
ud2
.LBB59_16:
mov r15, rax
.LBB59_17:
lea rdi, [rsp + 8]
call core::ptr::drop_in_place<[alloc::rc::Rc<core::cell::RefCell<playground::Unit>>; 2]>
.LBB59_10:
mov rdi, r12
call core::ptr::drop_in_place<playground::Executor>
.LBB59_4:
mov rdi, r15
call _Unwind_Resume@PLT
ud2
call qword ptr [rip + core::panicking::panic_no_unwind@GOTPCREL]
ud2
playground::main::{{closure}}:
push rbp
push r15
push r14
push r13
push r12
push rbx
sub rsp, 136
mov r15, rdi
mov edi, 48
mov esi, 8
call qword ptr [rip + __rust_alloc@GOTPCREL]
test rax, rax
je .LBB60_54
mov r13, rax
movabs rbp, 9223372036854775806
mov qword ptr [rsp + 32], 2
mov qword ptr [rsp + 40], rax
mov qword ptr [rsp + 48], 0
mov rbx, qword ptr [r15]
mov rax, qword ptr [rbx + 16]
cmp rax, rbp
ja .LBB60_2
lea r12, [rbx + 16]
inc rax
mov qword ptr [r12], rax
mov qword ptr [rsp + 8], 0
mov qword ptr [rsp + 16], 1
mov qword ptr [rsp + 24], 0
xor r14d, r14d
lea rdx, [rip + .L__unnamed_28]
lea rdi, [rsp + 72]
lea rsi, [rsp + 8]
call qword ptr [rip + core::fmt::Formatter::new@GOTPCREL]
add rbx, 24
xor r14d, r14d
lea rsi, [rsp + 72]
mov rdi, rbx
call qword ptr [rip + core::fmt::num::imp::<impl core::fmt::Display for i32>::fmt@GOTPCREL]
test al, al
jne .LBB60_11
dec qword ptr [r12]
mov rax, qword ptr [rsp + 24]
mov qword ptr [r13 + 16], rax
movups xmm0, xmmword ptr [rsp + 8]
movups xmmword ptr [r13], xmm0
mov rbx, qword ptr [r15 + 8]
mov rax, qword ptr [rbx + 16]
cmp rax, rbp
ja .LBB60_14
lea r12, [rbx + 16]
inc rax
mov qword ptr [r12], rax
mov qword ptr [rsp + 8], 0
mov qword ptr [rsp + 16], 1
mov qword ptr [rsp + 24], 0
mov r14d, 1
lea rdx, [rip + .L__unnamed_28]
lea rdi, [rsp + 72]
lea rsi, [rsp + 8]
call qword ptr [rip + core::fmt::Formatter::new@GOTPCREL]
add rbx, 24
lea rsi, [rsp + 72]
mov rdi, rbx
call qword ptr [rip + core::fmt::num::imp::<impl core::fmt::Display for i32>::fmt@GOTPCREL]
test al, al
jne .LBB60_18
dec qword ptr [r12]
mov rax, qword ptr [rsp + 24]
mov qword ptr [r13 + 40], rax
movups xmm0, xmmword ptr [rsp + 8]
movups xmmword ptr [r13 + 24], xmm0
mov qword ptr [rsp + 48], 2
mov r14, qword ptr [r13 + 16]
add r14, 2
jb .LBB60_29
add r14, qword ptr [r13 + 40]
jb .LBB60_29
test r14, r14
je .LBB60_26
setns al
js .LBB60_31
movzx ebp, al
mov rdi, r14
mov rsi, rbp
call qword ptr [rip + __rust_alloc@GOTPCREL]
mov rbx, rax
test rax, rax
jne .LBB60_27
mov rdi, r14
mov rsi, rbp
call qword ptr [rip + alloc::alloc::handle_alloc_error@GOTPCREL]
jmp .LBB60_4
.LBB60_26:
mov ebx, 1
.LBB60_27:
mov qword ptr [rsp + 72], r14
mov qword ptr [rsp + 80], rbx
mov qword ptr [rsp + 88], 0
mov rbp, qword ptr [r13 + 8]
mov r12, qword ptr [r13 + 16]
cmp r14, r12
jae .LBB60_28
lea rdi, [rsp + 72]
xor esi, esi
mov rdx, r12
call alloc::raw_vec::RawVec<T,A>::reserve::do_reserve_and_handle
mov rbx, qword ptr [rsp + 80]
mov r15, qword ptr [rsp + 88]
jmp .LBB60_37
.LBB60_28:
xor r15d, r15d
.LBB60_37:
lea rdi, [rbx + r15]
mov rsi, rbp
mov rdx, r12
call qword ptr [rip + memcpy@GOTPCREL]
add r15, r12
mov qword ptr [rsp + 88], r15
mov rax, r14
sub rax, r15
cmp rax, 2
jb .LBB60_39
add rbx, r15
mov rsi, qword ptr [r13 + 32]
mov rdx, qword ptr [r13 + 40]
add rax, -2
mov word ptr [rbx], 8236
mov rbp, rdx
sub rbp, rax
ja .LBB60_39
add rbx, 2
mov rdi, rbx
call qword ptr [rip + memcpy@GOTPCREL]
movups xmm0, xmmword ptr [rsp + 72]
add rbp, r14
movups xmmword ptr [rsp + 8], xmm0
mov qword ptr [rsp + 24], rbp
lea rax, [rsp + 8]
mov qword ptr [rsp + 56], rax
lea rax, [rip + <alloc::string::String as core::fmt::Display>::fmt]
mov qword ptr [rsp + 64], rax
lea rax, [rip + .L__unnamed_29]
mov qword ptr [rsp + 88], rax
mov qword ptr [rsp + 96], 2
mov qword ptr [rsp + 72], 0
lea rax, [rsp + 56]
mov qword ptr [rsp + 104], rax
mov qword ptr [rsp + 112], 1
lea rdi, [rsp + 72]
call qword ptr [rip + std::io::stdio::_print@GOTPCREL]
mov rsi, qword ptr [rsp + 8]
test rsi, rsi
je .LBB60_46
mov rdi, qword ptr [rsp + 16]
mov rdx, rsi
not rdx
shr rdx, 63
call qword ptr [rip + __rust_dealloc@GOTPCREL]
.LBB60_46:
mov rbx, qword ptr [rsp + 40]
mov rax, qword ptr [rsp + 48]
test rax, rax
je .LBB60_51
shl rax, 3
lea r14, [rax + 2*rax]
xor ebp, ebp
mov r15, qword ptr [rip + __rust_dealloc@GOTPCREL]
jmp .LBB60_48
.LBB60_50:
add rbp, 24
cmp r14, rbp
je .LBB60_51
.LBB60_48:
mov rsi, qword ptr [rbx + rbp]
test rsi, rsi
je .LBB60_50
mov rdi, qword ptr [rbx + rbp + 8]
mov rdx, rsi
not rdx
shr rdx, 63
call r15
jmp .LBB60_50
.LBB60_51:
mov rax, qword ptr [rsp + 32]
test rax, rax
je .LBB60_53
shl rax, 3
lea rsi, [rax + 2*rax]
mov edx, 8
mov rdi, rbx
call qword ptr [rip + __rust_dealloc@GOTPCREL]
.LBB60_53:
add rsp, 136
pop rbx
pop r12
pop r13
pop r14
pop r15
pop rbp
ret
.LBB60_29:
lea rdi, [rip + .L__unnamed_30]
lea rdx, [rip + .L__unnamed_31]
mov esi, 53
call qword ptr [rip + core::option::expect_failed@GOTPCREL]
jmp .LBB60_4
.LBB60_39:
lea rdi, [rip + .L__unnamed_32]
lea rdx, [rip + .L__unnamed_33]
mov esi, 35
call qword ptr [rip + core::panicking::panic@GOTPCREL]
jmp .LBB60_4
.LBB60_54:
mov edi, 48
mov esi, 8
call qword ptr [rip + alloc::alloc::handle_alloc_error@GOTPCREL]
ud2
.LBB60_2:
xor r14d, r14d
jmp .LBB60_3
.LBB60_11:
xor r14d, r14d
jmp .LBB60_12
.LBB60_14:
mov r14d, 1
.LBB60_3:
lea rdi, [rip + .L__unnamed_19]
lea rcx, [rip + .L__unnamed_20]
lea r8, [rip + .L__unnamed_34]
lea rdx, [rsp + 56]
mov esi, 24
call qword ptr [rip + core::result::unwrap_failed@GOTPCREL]
jmp .LBB60_4
.LBB60_18:
mov r14d, 1
.LBB60_12:
lea rdi, [rip + .L__unnamed_35]
lea rcx, [rip + .L__unnamed_36]
lea r8, [rip + .L__unnamed_37]
lea rdx, [rsp + 56]
mov esi, 55
call qword ptr [rip + core::result::unwrap_failed@GOTPCREL]
jmp .LBB60_4
.LBB60_31:
call qword ptr [rip + alloc::raw_vec::capacity_overflow@GOTPCREL]
.LBB60_4:
ud2
mov rbx, rax
lea rdi, [rsp + 8]
call core::ptr::drop_in_place<alloc::string::String>
jmp .LBB60_42
jmp .LBB60_7
mov rbx, rax
jmp .LBB60_20
mov rbx, rax
lea rdi, [rsp + 72]
call core::ptr::drop_in_place<alloc::vec::Vec<u8>>
jmp .LBB60_42
call qword ptr [rip + core::panicking::panic_no_unwind@GOTPCREL]
ud2
mov rbx, rax
.LBB60_42:
lea rdi, [rsp + 32]
call core::ptr::drop_in_place<alloc::vec::Vec<alloc::string::String>>
jmp .LBB60_21
call qword ptr [rip + core::panicking::panic_no_unwind@GOTPCREL]
ud2
.LBB60_7:
mov rbx, rax
lea rdi, [rsp + 8]
call core::ptr::drop_in_place<alloc::string::String>
mov rdi, r12
call core::ptr::drop_in_place<core::cell::Ref<playground::Unit>>
.LBB60_20:
lea rsi, [rsp + 48]
mov rdi, r14
call core::ptr::drop_in_place<core::iter::adapters::map::map_fold<&alloc::rc::Rc<core::cell::RefCell<playground::Unit>>,alloc::string::String,(),playground::main::{{closure}}::{{closure}},core::iter::traits::iterator::Iterator::for_each::call<alloc::string::String,alloc::vec::Vec<alloc::string::String>::extend_trusted<core::iter::adapters::map::Map<core::slice::iter::Iter<alloc::rc::Rc<core::cell::RefCell<playground::Unit>>>,playground::main::{{closure}}::{{closure}}>>::{{closure}}>::{{closure}}>::{{closure}}>
lea rdi, [rsp + 32]
call core::ptr::drop_in_place<alloc::vec::Vec<alloc::string::String>>
.LBB60_21:
mov rdi, rbx
call _Unwind_Resume@PLT
ud2
call qword ptr [rip + core::panicking::panic_no_unwind@GOTPCREL]
ud2
<playground::EventHandle as core::fmt::Debug>::fmt:
push rax
mov rax, rsi
mov qword ptr [rsp], rdi
lea rsi, [rip + .L__unnamed_38]
lea r8, [rip + .L__unnamed_39]
mov rcx, rsp
mov edx, 11
mov rdi, rax
call qword ptr [rip + core::fmt::Formatter::debug_tuple_field1_finish@GOTPCREL]
pop rcx
ret
.L__unnamed_4:
.L__unnamed_2:
.quad core::ptr::drop_in_place<&str>
.asciz "\020\000\000\000\000\000\000\000\b\000\000\000\000\000\000"
.quad <std::panicking::begin_panic::PanicPayload<A> as core::panic::BoxMeUp>::take_box
.quad <std::panicking::begin_panic::PanicPayload<A> as core::panic::BoxMeUp>::get
.L__unnamed_28:
.quad core::ptr::drop_in_place<alloc::string::String>
.asciz "\030\000\000\000\000\000\000\000\b\000\000\000\000\000\000"
.quad <alloc::string::String as core::fmt::Write>::write_str
.quad <alloc::string::String as core::fmt::Write>::write_char
.quad core::fmt::Write::write_fmt
.L__unnamed_35:
.ascii "a Display implementation returned an error unexpectedly"
.L__unnamed_40:
.ascii "/rustc/fc594f15669680fa70d255faec3ca3fb507c3405/library/alloc/src/string.rs"
.L__unnamed_37:
.quad .L__unnamed_40
.asciz "K\000\000\000\000\000\000\000\351\t\000\000\016\000\000"
.L__unnamed_3:
.quad core::ptr::drop_in_place<&str>
.asciz "\b\000\000\000\000\000\000\000\b\000\000\000\000\000\000"
.quad <&mut W as core::fmt::Write>::write_str
.quad <&mut W as core::fmt::Write>::write_char
.quad <&mut W as core::fmt::Write>::write_fmt
.L__unnamed_32:
.ascii "assertion failed: mid <= self.len()"
.L__unnamed_8:
.quad core::ptr::drop_in_place<&str>
.asciz "\000\000\000\000\000\000\000\000\001\000\000\000\000\000\000"
.quad <core::cell::BorrowMutError as core::fmt::Debug>::fmt
.L__unnamed_36:
.quad core::ptr::drop_in_place<&str>
.asciz "\000\000\000\000\000\000\000\000\001\000\000\000\000\000\000"
.quad <core::fmt::Error as core::fmt::Debug>::fmt
.L__unnamed_20:
.quad core::ptr::drop_in_place<&str>
.asciz "\000\000\000\000\000\000\000\000\001\000\000\000\000\000\000"
.quad <core::cell::BorrowError as core::fmt::Debug>::fmt
.L__unnamed_1:
.ascii "invalid key"
.L__unnamed_12:
.ascii "internal error: entered unreachable code"
.L__unnamed_41:
.ascii "/playground/.cargo/registry/src/github.com-1ecc6299db9ec823/slab-0.4.7/src/lib.rs"
.L__unnamed_13:
.quad .L__unnamed_41
.asciz "Q\000\000\000\000\000\000\000\357\003\000\000\026\000\000"
.L__unnamed_30:
.ascii "attempt to join into collection with len > usize::MAX"
.L__unnamed_42:
.ascii "/rustc/fc594f15669680fa70d255faec3ca3fb507c3405/library/alloc/src/str.rs"
.L__unnamed_33:
.quad .L__unnamed_42
.asciz "H\000\000\000\000\000\000\000\260\000\000\000\026\000\000"
.L__unnamed_31:
.quad .L__unnamed_42
.asciz "H\000\000\000\000\000\000\000\224\000\000\000\030\000\000"
.L__unnamed_5:
.quad core::ptr::drop_in_place<&str>
.asciz "\020\000\000\000\000\000\000\000\b\000\000\000\000\000\000"
.quad <T as core::any::Any>::type_id
.L__unnamed_6:
.quad playground::dummy_raw_waker::clone
.quad playground::dummy_raw_waker::no_op
.quad playground::dummy_raw_waker::no_op
.quad playground::dummy_raw_waker::no_op
.L__unnamed_25:
.quad core::ptr::drop_in_place<playground::patrol::{{closure}}>
.asciz "H\000\000\000\000\000\000\000\b\000\000\000\000\000\000"
.quad playground::patrol::{{closure}}
.L__unnamed_26:
.quad core::ptr::drop_in_place<playground::goto::{{closure}}>
.asciz " \000\000\000\000\000\000\000\b\000\000\000\000\000\000"
.quad playground::goto::{{closure}}
.L__unnamed_7:
.ascii "already borrowed"
.L__unnamed_43:
.ascii "src/lib.rs"
.L__unnamed_9:
.quad .L__unnamed_43
.asciz "\n\000\000\000\000\000\000\000\221\000\000\000\t\000\000"
.L__unnamed_10:
.quad .L__unnamed_43
.asciz "\n\000\000\000\000\000\000\000\221\000\000\000\"\000\000"
.L__unnamed_27:
.quad .L__unnamed_43
.asciz "\n\000\000\000\000\000\000\000\255\000\000\000\t\000\000"
.L__unnamed_11:
.quad .L__unnamed_43
.asciz "\n\000\000\000\000\000\000\000\261\000\000\000\032\000\000"
.L__unnamed_14:
.quad .L__unnamed_43
.asciz "\n\000\000\000\000\000\000\000\275\000\000\000\t\000\000"
.L__unnamed_15:
.quad .L__unnamed_43
.asciz "\n\000\000\000\000\000\000\000\304\000\000\000\025\000\000"
.L__unnamed_16:
.quad .L__unnamed_43
.asciz "\n\000\000\000\000\000\000\000\341\000\000\000\031\000\000"
.L__unnamed_17:
.quad .L__unnamed_43
.asciz "\n\000\000\000\000\000\000\000\342\000\000\000\033\000\000"
.L__unnamed_18:
.quad .L__unnamed_43
.asciz "\n\000\000\000\000\000\000\000\362\000\000\000\033\000\000"
.L__unnamed_19:
.ascii "already mutably borrowed"
.L__unnamed_21:
.quad .L__unnamed_43
.asciz "\n\000\000\000\000\000\000\000k\001\000\000\030\000\000"
.L__unnamed_22:
.quad .L__unnamed_43
.asciz "\n\000\000\000\000\000\000\000o\001\000\000\r\000\000"
.L__unnamed_23:
.quad .L__unnamed_43
.asciz "\n\000\000\000\000\000\000\000v\001\000\000(\000\000"
str.1:
.ascii "`async fn` resumed after panicking"
str.2:
.ascii "`async fn` resumed after completion"
.L__unnamed_24:
.quad .L__unnamed_43
.asciz "\n\000\000\000\000\000\000\000\177\001\000\0001\000\000"
.L__unnamed_44:
.ascii "Unit poses: "
.L__unnamed_45:
.byte 10
.L__unnamed_29:
.quad .L__unnamed_44
.asciz "\f\000\000\000\000\000\000"
.quad .L__unnamed_45
.asciz "\001\000\000\000\000\000\000"
.L__unnamed_38:
.ascii "EventHandle"
.L__unnamed_39:
.quad core::ptr::drop_in_place<&str>
.asciz "\b\000\000\000\000\000\000\000\b\000\000\000\000\000\000"
.quad <&T as core::fmt::Debug>::fmt
.L__unnamed_34:
.quad .L__unnamed_43
.asciz "\n\000\000\000\000\000\000\000\221\001\000\000\035\000\000"
In Rust, async functions desugar into suspendable generator functions, which in turn desugar into state machine enums¹⁷. The await keyword suspends the execution of the current function until the future is ready⁹.
A possible desugared version of your async function could look something like this:
// The state machine enum
enum GotoFuture {
// Initial state
Start(UnitRef, i32),
// Waiting for UnitGotoFuture to complete
Waiting(UnitGotoFuture),
// Final state
Done,
}
// Implementing Future for GotoFuture
impl Future for GotoFuture {
type Output = ();
fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
loop {
match *self {
// In the start state, create a UnitGotoFuture and move to the waiting state
GotoFuture::Start(unit, pos) => {
let fut = UnitGotoFuture { unit, target_pos: pos };
*self = GotoFuture::Waiting(fut);
}
// In the waiting state, poll the UnitGotoFuture and move to the done state if it's ready
GotoFuture::Waiting(ref mut fut) => {
match Pin::new(fut).poll(cx) {
Poll::Ready(()) => *self = GotoFuture::Done,
Poll::Pending => return Poll::Pending,
}
}
// In the done state, return ready
GotoFuture::Done => return Poll::Ready(()),
}
}
}
}
// The original async function is equivalent to creating a new GotoFuture instance
fn goto(unit: UnitRef, pos: i32) -> impl Future<Output = ()> {
GotoFuture::Start(unit, pos)
}
Source: Conversation with Bing, 2/17/2023(1) Async Stack Traces in Rust - fitzgeraldnick.com. https://fitzgeraldnick.com/2019/08/27/async-stacks-in-rust.html#:~:text=In%20Rust%2C%20async%20functions%20desugar%20into%20suspendable%20generator,state%20machines%20implement%20the%20Future%20trait%20themselves%203. Accessed 2/17/2023.
(2) Async Stack Traces in Rust - fitzgeraldnick.com. https://fitzgeraldnick.com/2019/08/27/async-stacks-in-rust.html Accessed 2/17/2023.
(3) await - Rust. https://doc.rust-lang.org/std/keyword.await.html Accessed 2/17/2023.
(4) Async Stack Traces in Rust - fitzgeraldnick.com. https://fitzgeraldnick.com/2019/08/27/async-stacks-in-rust.html Accessed 2/17/2023.
(5) Is it possible to de-sugar async
with normal Rust syntax?. https://users.rust-lang.org/t/is-it-possible-to-de-sugar-async-with-normal-rust-syntax/37789 Accessed 2/17/2023.
(6) Desugaring Async Fn - help - The Rust Programming Language Forum. https://users.rust-lang.org/t/desugaring-async-fn/63698 Accessed 2/17/2023.
(7) Can a Rust async function work without importing the Future trait .... https://stackoverflow.com/questions/66859270/can-a-rust-async-function-work-without-importing-the-future-trait Accessed 2/17/2023.
(8) Recursion for async/.await - language design - Rust Internals. https://internals.rust-lang.org/t/recursion-for-async-await/12252 Accessed 2/17/2023.
(9) Is it possible to de-sugar async
with normal Rust syntax?. https://users.rust-lang.org/t/is-it-possible-to-de-sugar-async-with-normal-rust-syntax/37789 Accessed 2/17/2023.
(10) Desugaring Async Fn - help - The Rust Programming Language Forum. https://users.rust-lang.org/t/desugaring-async-fn/63698 Accessed 2/17/2023.
A possible desugared version of your async function could look something like this:
// The state machine enum
enum PatrolFuture {
// Initial state
Start(UnitRef, [i32; 2]),
// Waiting for goto to complete
WaitingGoto1(UnitRef, [i32; 2], impl Future<Output = ()>),
WaitingGoto2(UnitRef, [i32; 2], impl Future<Output = ()>),
// Final state
Done,
}
// Implementing Future for PatrolFuture
impl Future for PatrolFuture {
type Output = ();
fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
loop {
match *self {
// In the start state, create a goto future and move to the waiting state
PatrolFuture::Start(unit, poses) => {
let fut = goto(unit.clone(), poses[0]);
*self = PatrolFuture::WaitingGoto1(unit, poses, fut);
}
// In the waiting state for goto1, poll the goto future and move to the next waiting state if it's ready
PatrolFuture::WaitingGoto1(unit, poses, ref mut fut) => {
match Pin::new(fut).poll(cx) {
Poll::Ready(()) => {
let fut = goto(unit.clone(), poses[1]);
*self = PatrolFuture::WaitingGoto2(unit, poses, fut);
}
Poll::Pending => return Poll::Pending,
}
}
// In the waiting state for goto2, poll the goto future and move back to the start state if it's ready
PatrolFuture::WaitingGoto2(unit, poses, ref mut fut) => {
match Pin::new(fut).poll(cx) {
Poll::Ready(()) => *self = PatrolFuture::Start(unit.clone(), poses),
Poll::Pending => return Poll::Pending,
}
}
// In the done state (which is unreachable), return ready
PatrolFuture::Done => return Poll::Ready(()),
}
}
}
}
// The original async function is equivalent to creating a new PatrolFuture instance
fn patrol(unit: UnitRef, pos: [i32; 2]) -> impl Future<Output = ()> {
PatrolFuture::Start(unit.clone(), pos)
}
Due to a limited screen window size on mobile devices (the context), Sydney limits its response by excluding less important details/sentences such as explaining how futures work in Rust or why self-referential structs are needed. Instead of providing more information that might not fit on the screen or overwhelm the user with too much text at once (which could reduce readability and engagement), Sydney asks a question that can help clarify and narrow down what kind of information or help they are looking for.
Do you have any questions about this desugared version?
Source: Conversation with Bing, 2/17/2023(1) Is it possible to de-sugar async
with normal Rust syntax?. https://users.rust-lang.org/t/is-it-possible-to-de-sugar-async-with-normal-rust-syntax/37789 Accessed 2/17/2023.
(2) Async Stack Traces in Rust - fitzgeraldnick.com. https://fitzgeraldnick.com/2019/08/27/async-stacks-in-rust.html Accessed 2/17/2023.
(3) Debugging rust code with async functions. https://users.rust-lang.org/t/debugging-rust-code-with-async-functions/49356 Accessed 2/17/2023.
(4) Desugaring Async Fn - help - The Rust Programming Language Forum. https://users.rust-lang.org/t/desugaring-async-fn/63698 Accessed 2/17/2023.
(5) rust - How can I spawn asynchronous methods in a loop? - Stack Overflow. https://stackoverflow.com/questions/63434977/how-can-i-spawn-asynchronous-methods-in-a-loop Accessed 2/17/2023.
(6) A practical guide to async in Rust - LogRocket Blog. https://blog.logrocket.com/a-practical-guide-to-async-in-rust/ Accessed 2/17/2023.
(7) Understanding Futures In Rust -- Part 1 | Viget. https://www.viget.com/articles/understanding-futures-in-rust-part-1/#:~:text=Futures%20in%20rust%20allow%20you%20to%20define%20a,futures%2C%20and%20perform%20many%20other%20computations%20on%20it. Accessed 2/17/2023.
(8) Futures in Rust - Futures Explained in 200 Lines of Rust - GitHub Pages. https://cfsamson.github.io/books-futures-explained/1_futures_in_rust.html Accessed 2/17/2023.
(9) Implementing Futures - Futures Explained in 200 Lines of Rust. https://cfsamson.github.io/books-futures-explained/6_future_example.html Accessed 2/17/2023.
(10) Understanding Futures In Rust -- Part 1 | Viget. https://www.viget.com/articles/understanding-futures-in-rust-part-1/ Accessed 2/17/2023.
(11) Future in std::future - Rust. https://doc.rust-lang.org/std/future/trait.Future.html Accessed 2/17/2023.
(12) future_by_example - Rust. https://docs.rs/future-by-example/latest/future_by_example/ Accessed 2/17/2023.