diff --git a/library/proc_macro/src/bridge/client.rs b/library/proc_macro/src/bridge/client.rs index c38457ac6712d..8587332a24a54 100644 --- a/library/proc_macro/src/bridge/client.rs +++ b/library/proc_macro/src/bridge/client.rs @@ -9,42 +9,6 @@ macro_rules! define_handles { 'owned: $($oty:ident,)* 'interned: $($ity:ident,)* ) => { - #[repr(C)] - #[allow(non_snake_case)] - pub struct HandleCounters { - $($oty: AtomicUsize,)* - $($ity: AtomicUsize,)* - } - - impl HandleCounters { - // FIXME(eddyb) use a reference to the `static COUNTERS`, instead of - // a wrapper `fn` pointer, once `const fn` can reference `static`s. - extern "C" fn get() -> &'static Self { - static COUNTERS: HandleCounters = HandleCounters { - $($oty: AtomicUsize::new(1),)* - $($ity: AtomicUsize::new(1),)* - }; - &COUNTERS - } - } - - // FIXME(eddyb) generate the definition of `HandleStore` in `server.rs`. - #[repr(C)] - #[allow(non_snake_case)] - pub(super) struct HandleStore { - $($oty: handle::OwnedStore,)* - $($ity: handle::InternedStore,)* - } - - impl HandleStore { - pub(super) fn new(handle_counters: &'static HandleCounters) -> Self { - HandleStore { - $($oty: handle::OwnedStore::new(&handle_counters.$oty),)* - $($ity: handle::InternedStore::new(&handle_counters.$ity),)* - } - } - } - $( #[repr(C)] pub(crate) struct $oty { @@ -73,53 +37,18 @@ macro_rules! define_handles { } } - impl DecodeMut<'_, '_, HandleStore>> - for Marked - { - fn decode(r: &mut Reader<'_>, s: &mut HandleStore>) -> Self { - s.$oty.take(handle::Handle::decode(r, &mut ())) - } - } - impl Encode for &$oty { fn encode(self, w: &mut Writer, s: &mut S) { self.handle.encode(w, s); } } - impl<'s, S: server::Types> Decode<'_, 's, HandleStore>> - for &'s Marked - { - fn decode(r: &mut Reader<'_>, s: &'s HandleStore>) -> Self { - &s.$oty[handle::Handle::decode(r, &mut ())] - } - } - impl Encode for &mut $oty { fn encode(self, w: &mut Writer, s: &mut S) { self.handle.encode(w, s); } } - impl<'s, S: server::Types> DecodeMut<'_, 's, HandleStore>> - for &'s mut Marked - { - fn decode( - r: &mut Reader<'_>, - s: &'s mut HandleStore> - ) -> Self { - &mut s.$oty[handle::Handle::decode(r, &mut ())] - } - } - - impl Encode>> - for Marked - { - fn encode(self, w: &mut Writer, s: &mut HandleStore>) { - s.$oty.alloc(self).encode(w, s); - } - } - impl DecodeMut<'_, '_, S> for $oty { fn decode(r: &mut Reader<'_>, s: &mut S) -> Self { $oty { @@ -147,22 +76,6 @@ macro_rules! define_handles { } } - impl DecodeMut<'_, '_, HandleStore>> - for Marked - { - fn decode(r: &mut Reader<'_>, s: &mut HandleStore>) -> Self { - s.$ity.copy(handle::Handle::decode(r, &mut ())) - } - } - - impl Encode>> - for Marked - { - fn encode(self, w: &mut Writer, s: &mut HandleStore>) { - s.$ity.alloc(self).encode(w, s); - } - } - impl DecodeMut<'_, '_, S> for $ity { fn decode(r: &mut Reader<'_>, s: &mut S) -> Self { $ity { @@ -174,23 +87,7 @@ macro_rules! define_handles { )* } } -define_handles! { - 'owned: - FreeFunctions, - TokenStream, - TokenStreamBuilder, - TokenStreamIter, - Group, - Literal, - SourceFile, - MultiSpan, - Diagnostic, - - 'interned: - Punct, - Ident, - Span, -} +with_api_types!(define_handles); // FIXME(eddyb) generate these impls by pattern-matching on the // names of methods - also could use the presence of `fn drop` @@ -323,27 +220,6 @@ impl Bridge<'_> { }) } - fn enter(self, f: impl FnOnce() -> R) -> R { - let force_show_panics = self.force_show_panics; - // Hide the default panic output within `proc_macro` expansions. - // NB. the server can't do this because it may use a different libstd. - static HIDE_PANICS_DURING_EXPANSION: Once = Once::new(); - HIDE_PANICS_DURING_EXPANSION.call_once(|| { - let prev = panic::take_hook(); - panic::set_hook(Box::new(move |info| { - let show = BridgeState::with(|state| match state { - BridgeState::NotConnected => true, - BridgeState::Connected(_) | BridgeState::InUse => force_show_panics, - }); - if show { - prev(info) - } - })); - }); - - BRIDGE_STATE.with(|state| state.set(BridgeState::Connected(self), f)) - } - fn with(f: impl FnOnce(&mut Bridge<'_>) -> R) -> R { BridgeState::with(|state| match state { BridgeState::NotConnected => { @@ -370,10 +246,6 @@ impl Bridge<'_> { /// and forcing the use of APIs that take/return `S::TokenStream`, server-side. #[repr(C)] pub struct Client { - // FIXME(eddyb) use a reference to the `static COUNTERS`, instead of - // a wrapper `fn` pointer, once `const fn` can reference `static`s. - pub(super) get_handle_counters: extern "C" fn() -> &'static HandleCounters, - pub(super) run: extern "C" fn(Bridge<'_>) -> Buffer, pub(super) _marker: PhantomData O>, @@ -388,7 +260,6 @@ impl Clone for Client { /// Client-side helper for handling client panics, entering the bridge, /// deserializing input and serializing output. -// FIXME(eddyb) maybe replace `Bridge::enter` with this? fn run_client DecodeMut<'a, 's, ()>, R: Encode<()>>( mut bridge: Bridge<'_>, f: impl FnOnce(A) -> R, @@ -397,29 +268,48 @@ fn run_client DecodeMut<'a, 's, ()>, R: Encode<()>>( let mut buf = bridge.cached_buffer.take(); panic::catch_unwind(panic::AssertUnwindSafe(|| { - bridge.enter(|| { - let reader = &mut &buf[..]; - let input = A::decode(reader, &mut ()); - - // Put the `cached_buffer` back in the `Bridge`, for requests. - Bridge::with(|bridge| bridge.cached_buffer = buf.take()); - - let output = f(input); - - // Take the `cached_buffer` back out, for the output value. - buf = Bridge::with(|bridge| bridge.cached_buffer.take()); - - // HACK(eddyb) Separate encoding a success value (`Ok(output)`) - // from encoding a panic (`Err(e: PanicMessage)`) to avoid - // having handles outside the `bridge.enter(|| ...)` scope, and - // to catch panics that could happen while encoding the success. - // - // Note that panics should be impossible beyond this point, but - // this is defensively trying to avoid any accidental panicking - // reaching the `extern "C"` (which should `abort` but might not - // at the moment, so this is also potentially preventing UB). - buf.clear(); - Ok::<_, ()>(output).encode(&mut buf, &mut ()); + let force_show_panics = bridge.force_show_panics; + // Hide the default panic output within `proc_macro` expansions. + // NB. the server can't do this because it may use a different libstd. + static HIDE_PANICS_DURING_EXPANSION: Once = Once::new(); + HIDE_PANICS_DURING_EXPANSION.call_once(|| { + let prev = panic::take_hook(); + panic::set_hook(Box::new(move |info| { + let show = BridgeState::with(|state| match state { + BridgeState::NotConnected => true, + BridgeState::Connected(_) | BridgeState::InUse => force_show_panics, + }); + if show { + prev(info) + } + })); + }); + + BRIDGE_STATE.with(|state| { + state.set(BridgeState::Connected(bridge), || { + let reader = &mut &buf[..]; + let input = A::decode(reader, &mut ()); + + // Put the `cached_buffer` back in the `Bridge`, for requests. + Bridge::with(|bridge| bridge.cached_buffer = buf.take()); + + let output = f(input); + + // Take the `cached_buffer` back out, for the output value. + buf = Bridge::with(|bridge| bridge.cached_buffer.take()); + + // HACK(eddyb) Separate encoding a success value (`Ok(output)`) + // from encoding a panic (`Err(e: PanicMessage)`) to avoid + // having handles outside the `bridge.enter(|| ...)` scope, and + // to catch panics that could happen while encoding the success. + // + // Note that panics should be impossible beyond this point, but + // this is defensively trying to avoid any accidental panicking + // reaching the `extern "C"` (which should `abort` but might not + // at the moment, so this is also potentially preventing UB). + buf.clear(); + Ok::<_, ()>(output).encode(&mut buf, &mut ()); + }) }) })) .map_err(PanicMessage::from) @@ -433,7 +323,6 @@ fn run_client DecodeMut<'a, 's, ()>, R: Encode<()>>( impl Client { pub const fn expand1(f: impl Fn(crate::TokenStream) -> crate::TokenStream + Copy) -> Self { Client { - get_handle_counters: HandleCounters::get, run: super::selfless_reify::reify_to_extern_c_fn_hrt_bridge(move |bridge| { run_client(bridge, |input| f(crate::TokenStream(input)).0) }), @@ -447,7 +336,6 @@ impl Client<(crate::TokenStream, crate::TokenStream), crate::TokenStream> { f: impl Fn(crate::TokenStream, crate::TokenStream) -> crate::TokenStream + Copy, ) -> Self { Client { - get_handle_counters: HandleCounters::get, run: super::selfless_reify::reify_to_extern_c_fn_hrt_bridge(move |bridge| { run_client(bridge, |(input, input2)| { f(crate::TokenStream(input), crate::TokenStream(input2)).0 diff --git a/library/proc_macro/src/bridge/mod.rs b/library/proc_macro/src/bridge/mod.rs index 4d3e89ba09356..897b3338c602c 100644 --- a/library/proc_macro/src/bridge/mod.rs +++ b/library/proc_macro/src/bridge/mod.rs @@ -175,6 +175,30 @@ macro_rules! with_api { }; } +// Similar to `with_api`, but only lists the types, and they are divided into +// the two storage categories. +macro_rules! with_api_types { + ($m:ident) => { + $m! { + 'owned: + FreeFunctions, + TokenStream, + TokenStreamBuilder, + TokenStreamIter, + Group, + Literal, + SourceFile, + MultiSpan, + Diagnostic, + + 'interned: + Punct, + Ident, + Span, + } + }; +} + // FIXME(eddyb) this calls `encode` for each argument, but in reverse, // to match the ordering in `reverse_decode`. macro_rules! reverse_encode { diff --git a/library/proc_macro/src/bridge/server.rs b/library/proc_macro/src/bridge/server.rs index cbddf39da44d2..cdd1b00c64020 100644 --- a/library/proc_macro/src/bridge/server.rs +++ b/library/proc_macro/src/bridge/server.rs @@ -2,8 +2,93 @@ use super::*; -// FIXME(eddyb) generate the definition of `HandleStore` in `server.rs`. -use super::client::HandleStore; +macro_rules! define_handles { + ( + 'owned: $($oty:ident,)* + 'interned: $($ity:ident,)* + ) => { + static COUNTERS: HandleCounters = HandleCounters { + $($oty: AtomicUsize::new(1),)* + $($ity: AtomicUsize::new(1),)* + }; + + #[repr(C)] + #[allow(non_snake_case)] + struct HandleCounters { + $($oty: AtomicUsize,)* + $($ity: AtomicUsize,)* + } + + #[repr(C)] + #[allow(non_snake_case)] + struct HandleStore { + $($oty: handle::OwnedStore,)* + $($ity: handle::InternedStore,)* + } + + impl HandleStore { + fn new() -> Self { + HandleStore { + $($oty: handle::OwnedStore::new(&COUNTERS.$oty),)* + $($ity: handle::InternedStore::new(&COUNTERS.$ity),)* + } + } + } + + $( + impl Encode>> + for Marked + { + fn encode(self, w: &mut Writer, s: &mut HandleStore>) { + s.$oty.alloc(self).encode(w, s); + } + } + + impl DecodeMut<'_, '_, HandleStore>> + for Marked + { + fn decode(r: &mut Reader<'_>, s: &mut HandleStore>) -> Self { + s.$oty.take(handle::Handle::decode(r, &mut ())) + } + } + + impl<'s, S: Types> Decode<'_, 's, HandleStore>> + for &'s Marked + { + fn decode(r: &mut Reader<'_>, s: &'s HandleStore>) -> Self { + &s.$oty[handle::Handle::decode(r, &mut ())] + } + } + + impl<'s, S: Types> DecodeMut<'_, 's, HandleStore>> + for &'s mut Marked + { + fn decode(r: &mut Reader<'_>, s: &'s mut HandleStore>) -> Self { + &mut s.$oty[handle::Handle::decode(r, &mut ())] + } + } + )* + + $( + impl Encode>> + for Marked + { + fn encode(self, w: &mut Writer, s: &mut HandleStore>) { + s.$ity.alloc(self).encode(w, s); + } + } + + impl DecodeMut<'_, '_, HandleStore>> + for Marked + { + fn decode(r: &mut Reader<'_>, s: &mut HandleStore>) -> Self { + s.$ity.copy(handle::Handle::decode(r, &mut ())) + } + } + )* + } +} +with_api_types!(define_handles); pub trait Types { type FreeFunctions: 'static; @@ -46,7 +131,7 @@ macro_rules! declare_server_traits { } with_api!(Self, self_, declare_server_traits); -pub(super) struct MarkedTypes(S); +struct MarkedTypes(S); macro_rules! define_mark_types_impls { ($($name:ident { @@ -257,14 +342,13 @@ fn run_server< O: for<'a, 's> DecodeMut<'a, 's, HandleStore>>, >( strategy: &impl ExecutionStrategy, - handle_counters: &'static client::HandleCounters, server: S, input: I, run_client: extern "C" fn(Bridge<'_>) -> Buffer, force_show_panics: bool, ) -> Result { let mut dispatcher = - Dispatcher { handle_store: HandleStore::new(handle_counters), server: MarkedTypes(server) }; + Dispatcher { handle_store: HandleStore::new(), server: MarkedTypes(server) }; let mut buf = Buffer::new(); input.encode(&mut buf, &mut dispatcher.handle_store); @@ -282,10 +366,9 @@ impl client::Client { input: S::TokenStream, force_show_panics: bool, ) -> Result { - let client::Client { get_handle_counters, run, _marker } = *self; + let client::Client { run, _marker } = *self; run_server( strategy, - get_handle_counters(), server, as Types>::TokenStream::mark(input), run, @@ -304,10 +387,9 @@ impl client::Client<(crate::TokenStream, crate::TokenStream), crate::TokenStream input2: S::TokenStream, force_show_panics: bool, ) -> Result { - let client::Client { get_handle_counters, run, _marker } = *self; + let client::Client { run, _marker } = *self; run_server( strategy, - get_handle_counters(), server, ( as Types>::TokenStream::mark(input),