Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 3 additions & 24 deletions compiler/rustc_expand/src/proc_macro.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,32 +11,11 @@ use {rustc_ast as ast, rustc_proc_macro as pm};
use crate::base::{self, *};
use crate::{errors, proc_macro_server};

struct MessagePipe<T> {
tx: std::sync::mpsc::SyncSender<T>,
rx: std::sync::mpsc::Receiver<T>,
}

impl<T> pm::bridge::server::MessagePipe<T> for MessagePipe<T> {
fn new() -> (Self, Self) {
let (tx1, rx1) = std::sync::mpsc::sync_channel(1);
let (tx2, rx2) = std::sync::mpsc::sync_channel(1);
(MessagePipe { tx: tx1, rx: rx2 }, MessagePipe { tx: tx2, rx: rx1 })
}

fn send(&mut self, value: T) {
self.tx.send(value).unwrap();
}

fn recv(&mut self) -> Option<T> {
self.rx.recv().ok()
}
}

fn exec_strategy(sess: &Session) -> impl pm::bridge::server::ExecutionStrategy + 'static {
pm::bridge::server::MaybeCrossThread::<MessagePipe<_>>::new(
sess.opts.unstable_opts.proc_macro_execution_strategy
pm::bridge::server::MaybeCrossThread {
cross_thread: sess.opts.unstable_opts.proc_macro_execution_strategy
== ProcMacroExecutionStrategy::CrossThread,
)
}
}

pub struct BangProcMacro {
Expand Down
2 changes: 1 addition & 1 deletion library/proc_macro/src/bridge/client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@ pub(crate) use super::symbol::Symbol;

macro_rules! define_client_side {
(
$(fn $method:ident($($arg:ident: $arg_ty:ty),* $(,)?) $(-> $ret_ty:ty)*;)*
$(fn $method:ident($($arg:ident: $arg_ty:ty),* $(,)?) $(-> $ret_ty:ty)?;)*
) => {
impl Methods {
$(pub(crate) fn $method($($arg: $arg_ty),*) $(-> $ret_ty)? {
Expand Down
2 changes: 1 addition & 1 deletion library/proc_macro/src/bridge/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -133,7 +133,7 @@ impl !Sync for BridgeConfig<'_> {}

macro_rules! declare_tags {
(
$(fn $method:ident($($arg:ident: $arg_ty:ty),* $(,)?) $(-> $ret_ty:ty)*;)*
$(fn $method:ident($($arg:ident: $arg_ty:ty),* $(,)?) $(-> $ret_ty:ty)?;)*
) => {
#[allow(non_camel_case_types)]
pub(super) enum ApiTags {
Expand Down
155 changes: 60 additions & 95 deletions library/proc_macro/src/bridge/server.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
//! Server-side traits.

use std::cell::Cell;
use std::marker::PhantomData;
use std::sync::mpsc;

use super::*;

Expand Down Expand Up @@ -53,14 +53,9 @@ impl<S: Server> Decode<'_, '_, HandleStore<S>> for MarkedSpan<S> {
}
}

struct Dispatcher<S: Server> {
handle_store: HandleStore<S>,
server: S,
}

macro_rules! define_server {
(
$(fn $method:ident($($arg:ident: $arg_ty:ty),* $(,)?) $(-> $ret_ty:ty)*;)*
$(fn $method:ident($($arg:ident: $arg_ty:ty),* $(,)?) $(-> $ret_ty:ty)?;)*
) => {
pub trait Server {
type TokenStream: 'static + Clone + Default;
Expand All @@ -81,16 +76,17 @@ macro_rules! define_server {
}
with_api!(define_server, Self::TokenStream, Self::Span, Self::Symbol);

// FIXME(eddyb) `pub` only for `ExecutionStrategy` below.
pub struct Dispatcher<S: Server> {
handle_store: HandleStore<S>,
server: S,
}

macro_rules! define_dispatcher {
(
$(fn $method:ident($($arg:ident: $arg_ty:ty),* $(,)?) $(-> $ret_ty:ty)*;)*
$(fn $method:ident($($arg:ident: $arg_ty:ty),* $(,)?) $(-> $ret_ty:ty)?;)*
) => {
// FIXME(eddyb) `pub` only for `ExecutionStrategy` below.
pub trait DispatcherTrait {
fn dispatch(&mut self, buf: Buffer) -> Buffer;
}

impl<S: Server> DispatcherTrait for Dispatcher<S> {
impl<S: Server> Dispatcher<S> {
fn dispatch(&mut self, mut buf: Buffer) -> Buffer {
let Dispatcher { handle_store, server } = self;

Expand All @@ -100,9 +96,7 @@ macro_rules! define_dispatcher {
let mut call_method = || {
$(let $arg = <$arg_ty>::decode(&mut reader, handle_store).unmark();)*
let r = server.$method($($arg),*);
$(
let r: $ret_ty = Mark::mark(r);
)*
$(let r: $ret_ty = Mark::mark(r);)?
r
};
// HACK(eddyb) don't use `panic::catch_unwind` in a panic.
Expand All @@ -127,10 +121,13 @@ macro_rules! define_dispatcher {
}
with_api!(define_dispatcher, MarkedTokenStream<S>, MarkedSpan<S>, MarkedSymbol<S>);

// This trait is currently only implemented and used once, inside of this crate.
// We keep it public to allow implementing more complex execution strategies in
// the future, such as wasm proc-macros.
pub trait ExecutionStrategy {
fn run_bridge_and_client(
&self,
dispatcher: &mut impl DispatcherTrait,
dispatcher: &mut Dispatcher<impl Server>,
input: Buffer,
run_client: extern "C" fn(BridgeConfig<'_>) -> Buffer,
force_show_panics: bool,
Expand Down Expand Up @@ -169,110 +166,78 @@ impl Drop for RunningSameThreadGuard {
}
}

pub struct MaybeCrossThread<P> {
cross_thread: bool,
marker: PhantomData<P>,
pub struct MaybeCrossThread {
pub cross_thread: bool,
}

impl<P> MaybeCrossThread<P> {
pub const fn new(cross_thread: bool) -> Self {
MaybeCrossThread { cross_thread, marker: PhantomData }
}
}
pub const SAME_THREAD: MaybeCrossThread = MaybeCrossThread { cross_thread: false };
pub const CROSS_THREAD: MaybeCrossThread = MaybeCrossThread { cross_thread: true };

impl<P> ExecutionStrategy for MaybeCrossThread<P>
where
P: MessagePipe<Buffer> + Send + 'static,
{
impl ExecutionStrategy for MaybeCrossThread {
fn run_bridge_and_client(
&self,
dispatcher: &mut impl DispatcherTrait,
dispatcher: &mut Dispatcher<impl Server>,
input: Buffer,
run_client: extern "C" fn(BridgeConfig<'_>) -> Buffer,
force_show_panics: bool,
) -> Buffer {
if self.cross_thread || ALREADY_RUNNING_SAME_THREAD.get() {
<CrossThread<P>>::new().run_bridge_and_client(
dispatcher,
input,
run_client,
force_show_panics,
)
} else {
SameThread.run_bridge_and_client(dispatcher, input, run_client, force_show_panics)
}
}
}

pub struct SameThread;

impl ExecutionStrategy for SameThread {
fn run_bridge_and_client(
&self,
dispatcher: &mut impl DispatcherTrait,
input: Buffer,
run_client: extern "C" fn(BridgeConfig<'_>) -> Buffer,
force_show_panics: bool,
) -> Buffer {
let _guard = RunningSameThreadGuard::new();

let mut dispatch = |buf| dispatcher.dispatch(buf);

run_client(BridgeConfig { input, dispatch: (&mut dispatch).into(), force_show_panics })
}
}

pub struct CrossThread<P>(PhantomData<P>);

impl<P> CrossThread<P> {
pub const fn new() -> Self {
CrossThread(PhantomData)
}
}
let (mut server, mut client) = MessagePipe::new();

let join_handle = thread::spawn(move || {
let mut dispatch = |b: Buffer| -> Buffer {
client.send(b);
client.recv().expect("server died while client waiting for reply")
};

run_client(BridgeConfig {
input,
dispatch: (&mut dispatch).into(),
force_show_panics,
})
});

while let Some(b) = server.recv() {
server.send(dispatcher.dispatch(b));
}

impl<P> ExecutionStrategy for CrossThread<P>
where
P: MessagePipe<Buffer> + Send + 'static,
{
fn run_bridge_and_client(
&self,
dispatcher: &mut impl DispatcherTrait,
input: Buffer,
run_client: extern "C" fn(BridgeConfig<'_>) -> Buffer,
force_show_panics: bool,
) -> Buffer {
let (mut server, mut client) = P::new();
join_handle.join().unwrap()
} else {
let _guard = RunningSameThreadGuard::new();

let join_handle = thread::spawn(move || {
let mut dispatch = |b: Buffer| -> Buffer {
client.send(b);
client.recv().expect("server died while client waiting for reply")
};
let mut dispatch = |buf| dispatcher.dispatch(buf);

run_client(BridgeConfig { input, dispatch: (&mut dispatch).into(), force_show_panics })
});

while let Some(b) = server.recv() {
server.send(dispatcher.dispatch(b));
}

join_handle.join().unwrap()
}
}

/// A message pipe used for communicating between server and client threads.
pub trait MessagePipe<T>: Sized {
struct MessagePipe<T> {
tx: mpsc::SyncSender<T>,
rx: mpsc::Receiver<T>,
}

impl<T> MessagePipe<T> {
/// Creates a new pair of endpoints for the message pipe.
fn new() -> (Self, Self);
fn new() -> (Self, Self) {
let (tx1, rx1) = mpsc::sync_channel(1);
let (tx2, rx2) = mpsc::sync_channel(1);
(MessagePipe { tx: tx1, rx: rx2 }, MessagePipe { tx: tx2, rx: rx1 })
}

/// Send a message to the other endpoint of this pipe.
fn send(&mut self, value: T);
fn send(&mut self, value: T) {
self.tx.send(value).unwrap();
}

/// Receive a message from the other endpoint of this pipe.
///
/// Returns `None` if the other end of the pipe has been destroyed, and no
/// message was received.
fn recv(&mut self) -> Option<T>;
fn recv(&mut self) -> Option<T> {
self.rx.recv().ok()
}
}

fn run_server<
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ impl ProcMacros {
if *trait_name == macro_name =>
{
let res = client.run(
&bridge::server::SameThread,
&bridge::server::SAME_THREAD,
S::make_server(call_site, def_site, mixed_site, callback),
macro_body,
cfg!(debug_assertions),
Expand All @@ -39,7 +39,7 @@ impl ProcMacros {
}
bridge::client::ProcMacro::Bang { name, client } if *name == macro_name => {
let res = client.run(
&bridge::server::SameThread,
&bridge::server::SAME_THREAD,
S::make_server(call_site, def_site, mixed_site, callback),
macro_body,
cfg!(debug_assertions),
Expand All @@ -48,7 +48,7 @@ impl ProcMacros {
}
bridge::client::ProcMacro::Attr { name, client } if *name == macro_name => {
let res = client.run(
&bridge::server::SameThread,
&bridge::server::SAME_THREAD,
S::make_server(call_site, def_site, mixed_site, callback),
parsed_attributes,
macro_body,
Expand Down
Loading