Skip to content

Commit e321cb0

Browse files
committed
WIP: implement proc_macro standalone backend
1 parent e100792 commit e321cb0

File tree

5 files changed

+322
-21
lines changed

5 files changed

+322
-21
lines changed

library/proc_macro/src/bridge/client.rs

Lines changed: 60 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,9 @@ use std::marker::PhantomData;
55
use std::sync::atomic::AtomicU32;
66

77
use super::*;
8+
use crate::StandaloneLevel;
9+
use crate::bridge::server::{Dispatcher, DispatcherTrait};
10+
use crate::bridge::standalone::NoRustc;
811

912
macro_rules! define_client_handles {
1013
(
@@ -141,7 +144,10 @@ macro_rules! define_client_side {
141144
api_tags::Method::$name(api_tags::$name::$method).encode(&mut buf, &mut ());
142145
$($arg.encode(&mut buf, &mut ());)*
143146

144-
buf = bridge.dispatch.call(buf);
147+
buf = match &mut bridge.dispatch {
148+
DispatchWay::Closure(f) => f.call(buf),
149+
DispatchWay::Directly(disp) => disp.dispatch(buf),
150+
};
145151

146152
let r = Result::<_, PanicMessage>::decode(&mut &buf[..], &mut ());
147153

@@ -155,13 +161,18 @@ macro_rules! define_client_side {
155161
}
156162
with_api!(self, self, define_client_side);
157163

164+
enum DispatchWay<'a> {
165+
Closure(closure::Closure<'a, Buffer, Buffer>),
166+
Directly(Dispatcher<NoRustc>),
167+
}
168+
158169
struct Bridge<'a> {
159170
/// Reusable buffer (only `clear`-ed, never shrunk), primarily
160171
/// used for making requests.
161172
cached_buffer: Buffer,
162173

163174
/// Server-side function that the client uses to make requests.
164-
dispatch: closure::Closure<'a, Buffer, Buffer>,
175+
dispatch: DispatchWay<'a>,
165176

166177
/// Provided globals for this macro expansion.
167178
globals: ExpnGlobals<Span>,
@@ -173,12 +184,33 @@ impl<'a> !Sync for Bridge<'a> {}
173184
#[allow(unsafe_code)]
174185
mod state {
175186
use std::cell::{Cell, RefCell};
187+
use std::marker::PhantomData;
176188
use std::ptr;
177189

178190
use super::Bridge;
191+
use crate::StandaloneLevel;
192+
use crate::bridge::buffer::Buffer;
193+
use crate::bridge::client::{COUNTERS, DispatchWay};
194+
use crate::bridge::server::{Dispatcher, HandleStore, MarkedTypes};
195+
use crate::bridge::{ExpnGlobals, Marked, standalone};
179196

180197
thread_local! {
181198
static BRIDGE_STATE: Cell<*const ()> = const { Cell::new(ptr::null()) };
199+
static STANDALONE: RefCell<Bridge<'static>> = RefCell::new(standalone_bridge());
200+
pub(super) static USE_STANDALONE: Cell<StandaloneLevel> = const { Cell::new(StandaloneLevel::Never) };
201+
}
202+
203+
fn standalone_bridge() -> Bridge<'static> {
204+
let mut store = HandleStore::new(&COUNTERS);
205+
let id = store.Span.alloc(Marked { value: standalone::Span::DUMMY, _marker: PhantomData });
206+
let dummy = super::Span { handle: id };
207+
let dispatcher =
208+
Dispatcher { handle_store: store, server: MarkedTypes(standalone::NoRustc) };
209+
Bridge {
210+
cached_buffer: Buffer::new(),
211+
dispatch: DispatchWay::Directly(dispatcher),
212+
globals: ExpnGlobals { call_site: dummy, def_site: dummy, mixed_site: dummy },
213+
}
182214
}
183215

184216
pub(super) fn set<'bridge, R>(state: &RefCell<Bridge<'bridge>>, f: impl FnOnce() -> R) -> R {
@@ -199,16 +231,23 @@ mod state {
199231
pub(super) fn with<R>(
200232
f: impl for<'bridge> FnOnce(Option<&RefCell<Bridge<'bridge>>>) -> R,
201233
) -> R {
202-
let state = BRIDGE_STATE.get();
203-
// SAFETY: the only place where the pointer is set is in `set`. It puts
204-
// back the previous value after the inner call has returned, so we know
205-
// that as long as the pointer is not null, it came from a reference to
206-
// a `RefCell<Bridge>` that outlasts the call to this function. Since `f`
207-
// works the same for any lifetime of the bridge, including the actual
208-
// one, we can lie here and say that the lifetime is `'static` without
209-
// anyone noticing.
210-
let bridge = unsafe { state.cast::<RefCell<Bridge<'static>>>().as_ref() };
211-
f(bridge)
234+
let level = USE_STANDALONE.get();
235+
if level == StandaloneLevel::Always
236+
|| (level == StandaloneLevel::FallbackOnly && BRIDGE_STATE.get().is_null())
237+
{
238+
STANDALONE.with(|bridge| f(Some(bridge)))
239+
} else {
240+
let state = BRIDGE_STATE.get();
241+
// SAFETY: the only place where the pointer is set is in `set`. It puts
242+
// back the previous value after the inner call has returned, so we know
243+
// that as long as the pointer is not null, it came from a reference to
244+
// a `RefCell<Bridge>` that outlasts the call to this function. Since `f`
245+
// works the same for any lifetime of the bridge, including the actual
246+
// one, we can lie here and say that the lifetime is `'static` without
247+
// anyone noticing.
248+
let bridge = unsafe { state.cast::<RefCell<Bridge<'static>>>().as_ref() };
249+
f(bridge)
250+
}
212251
}
213252
}
214253

@@ -228,6 +267,10 @@ pub(crate) fn is_available() -> bool {
228267
state::with(|s| s.is_some())
229268
}
230269

270+
pub(crate) fn enable_standalone(level: StandaloneLevel) {
271+
state::USE_STANDALONE.set(level);
272+
}
273+
231274
/// A client-side RPC entry-point, which may be using a different `proc_macro`
232275
/// from the one used by the server, but can be invoked compatibly.
233276
///
@@ -292,7 +335,11 @@ fn run_client<A: for<'a, 's> Decode<'a, 's, ()>, R: Encode<()>>(
292335
let (globals, input) = <(ExpnGlobals<Span>, A)>::decode(reader, &mut ());
293336

294337
// Put the buffer we used for input back in the `Bridge` for requests.
295-
let state = RefCell::new(Bridge { cached_buffer: buf.take(), dispatch, globals });
338+
let state = RefCell::new(Bridge {
339+
cached_buffer: buf.take(),
340+
dispatch: DispatchWay::Closure(dispatch),
341+
globals,
342+
});
296343

297344
let output = state::set(&state, || f(input));
298345

library/proc_macro/src/bridge/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -138,6 +138,7 @@ mod rpc;
138138
mod selfless_reify;
139139
#[forbid(unsafe_code)]
140140
pub mod server;
141+
pub(crate) mod standalone;
141142
#[allow(unsafe_code)]
142143
mod symbol;
143144

library/proc_macro/src/bridge/server.rs

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -12,12 +12,12 @@ macro_rules! define_server_handles {
1212
) => {
1313
#[allow(non_snake_case)]
1414
pub(super) struct HandleStore<S: Types> {
15-
$($oty: handle::OwnedStore<S::$oty>,)*
16-
$($ity: handle::InternedStore<S::$ity>,)*
15+
$(pub(super) $oty: handle::OwnedStore<S::$oty>,)*
16+
$(pub(super) $ity: handle::InternedStore<S::$ity>,)*
1717
}
1818

1919
impl<S: Types> HandleStore<S> {
20-
fn new(handle_counters: &'static client::HandleCounters) -> Self {
20+
pub(super) fn new(handle_counters: &'static client::HandleCounters) -> Self {
2121
HandleStore {
2222
$($oty: handle::OwnedStore::new(&handle_counters.$oty),)*
2323
$($ity: handle::InternedStore::new(&handle_counters.$ity),)*
@@ -119,7 +119,7 @@ macro_rules! declare_server_traits {
119119
}
120120
with_api!(Self, self_, declare_server_traits);
121121

122-
pub(super) struct MarkedTypes<S: Types>(S);
122+
pub(super) struct MarkedTypes<S: Types>(pub(super) S);
123123

124124
impl<S: Server> Server for MarkedTypes<S> {
125125
fn globals(&mut self) -> ExpnGlobals<Self::Span> {
@@ -150,9 +150,9 @@ macro_rules! define_mark_types_impls {
150150
}
151151
with_api!(Self, self_, define_mark_types_impls);
152152

153-
struct Dispatcher<S: Types> {
154-
handle_store: HandleStore<S>,
155-
server: S,
153+
pub(super) struct Dispatcher<S: Types> {
154+
pub(super) handle_store: HandleStore<MarkedTypes<S>>,
155+
pub(super) server: MarkedTypes<S>,
156156
}
157157

158158
macro_rules! define_dispatcher_impl {
@@ -167,7 +167,7 @@ macro_rules! define_dispatcher_impl {
167167
fn dispatch(&mut self, buf: Buffer) -> Buffer;
168168
}
169169

170-
impl<S: Server> DispatcherTrait for Dispatcher<MarkedTypes<S>> {
170+
impl<S: Server> DispatcherTrait for Dispatcher<S> {
171171
$(type $name = <MarkedTypes<S> as Types>::$name;)*
172172

173173
fn dispatch(&mut self, mut buf: Buffer) -> Buffer {

0 commit comments

Comments
 (0)