Skip to content

Commit b6f8dc9

Browse files
committed
proc_macro: add support for sending messages without waiting for a reply
This has minimal impact without changes from a later part, as it also requires support from the ExecutionStrategy. Messages are able to return owning handles without waiting by allocating an ID from the client thread, and passing it up to the server to fill with a response. If the server panics, it will be an ICE, and no further requests will be handled.
1 parent afc36cc commit b6f8dc9

File tree

4 files changed

+209
-98
lines changed

4 files changed

+209
-98
lines changed

library/proc_macro/src/bridge/client.rs

Lines changed: 82 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,23 @@
22
33
use super::*;
44

5+
use std::sync::atomic::Ordering;
6+
7+
trait OwnedHandle {
8+
/// Create a new handle of this type from the client side, which may be used
9+
/// later by the server.
10+
///
11+
/// Should only be called on the client.
12+
fn next_raw_handle() -> handle::Handle;
13+
14+
/// Create an instance of the owning handle object for this raw handle. The
15+
/// raw handle should've previously been created with `next_raw_handle`, and
16+
/// the corresponding message should've been sent to the server.
17+
///
18+
/// Should only be called on the client.
19+
fn from_raw_handle(handle: handle::Handle) -> Self;
20+
}
21+
522
macro_rules! define_handles {
623
(
724
'owned: $($oty:ident,)*
@@ -116,6 +133,25 @@ macro_rules! define_handles {
116133
$oty(handle::Handle::decode(r, s))
117134
}
118135
}
136+
137+
impl<S: server::Types> server::InitOwnedHandle<HandleStore<server::MarkedTypes<S>>>
138+
for Marked<S::$oty, $oty>
139+
{
140+
fn init_handle(self, raw_handle: handle::Handle, s: &mut HandleStore<server::MarkedTypes<S>>) {
141+
s.$oty.init(raw_handle, self);
142+
}
143+
}
144+
145+
impl OwnedHandle for $oty {
146+
fn next_raw_handle() -> handle::Handle {
147+
let counter = HandleCounters::get().$oty.fetch_add(1, Ordering::SeqCst);
148+
handle::Handle::new(counter as u32).expect("`proc_macro` handle counter overflowed")
149+
}
150+
151+
fn from_raw_handle(handle: handle::Handle) -> $oty {
152+
$oty(handle)
153+
}
154+
}
119155
)*
120156

121157
$(
@@ -242,27 +278,57 @@ impl fmt::Debug for Span {
242278
}
243279
}
244280

245-
macro_rules! define_client_side {
246-
($($name:ident {
247-
$(fn $method:ident($($arg:ident: $arg_ty:ty),* $(,)?) $(-> $ret_ty:ty)*;)*
248-
}),* $(,)?) => {
249-
$(impl $name {
250-
$(pub(crate) fn $method($($arg: $arg_ty),*) $(-> $ret_ty)* {
251-
Bridge::with(|bridge| {
252-
let mut b = bridge.cached_buffer.take();
281+
macro_rules! client_send_impl {
282+
(wait $name:ident :: $method:ident($($arg:ident),*) $(-> $ret_ty:ty)?) => {
283+
Bridge::with(|bridge| {
284+
let mut b = bridge.cached_buffer.take();
285+
286+
b.clear();
287+
api_tags::Method::$name(api_tags::$name::$method).encode(&mut b, &mut ());
288+
reverse_encode!(b; $($arg),*);
289+
290+
b = bridge.dispatch.call(b);
291+
292+
let r = Result::<_, PanicMessage>::decode(&mut &b[..], &mut ());
293+
294+
bridge.cached_buffer = b;
295+
296+
r.unwrap_or_else(|e| panic::resume_unwind(e.into()))
297+
})
298+
};
299+
300+
(nowait $name:ident :: $method:ident($($arg:ident),*) $(-> $ret_ty:ty)?) => {
301+
Bridge::with(|bridge| {
302+
let mut b = bridge.cached_buffer.take();
253303

254-
b.clear();
255-
api_tags::Method::$name(api_tags::$name::$method).encode(&mut b, &mut ());
256-
reverse_encode!(b; $($arg),*);
304+
b.clear();
305+
api_tags::Method::$name(api_tags::$name::$method).encode(&mut b, &mut ());
306+
reverse_encode!(b; $($arg),*);
257307

258-
b = bridge.dispatch.call(b);
308+
$(
309+
let raw_handle = <$ret_ty as OwnedHandle>::next_raw_handle();
310+
raw_handle.encode(&mut b, &mut ());
311+
)?
259312

260-
let r = Result::<_, PanicMessage>::decode(&mut &b[..], &mut ());
313+
b = bridge.dispatch.call(b);
261314

262-
bridge.cached_buffer = b;
315+
let r = Result::<(), PanicMessage>::decode(&mut &b[..], &mut ());
263316

264-
r.unwrap_or_else(|e| panic::resume_unwind(e.into()))
265-
})
317+
bridge.cached_buffer = b;
318+
319+
r.unwrap_or_else(|e| panic::resume_unwind(e.into()));
320+
$(<$ret_ty as OwnedHandle>::from_raw_handle(raw_handle))?
321+
})
322+
};
323+
}
324+
325+
macro_rules! define_client_side {
326+
($($name:ident {
327+
$($wait:ident fn $method:ident($($arg:ident: $arg_ty:ty),* $(,)?) $(-> $ret_ty:ty)?;)*
328+
}),* $(,)?) => {
329+
$(impl $name {
330+
$(pub(crate) fn $method($($arg: $arg_ty),*) $(-> $ret_ty)? {
331+
client_send_impl!($wait $name :: $method ($($arg),*) $(-> $ret_ty)?)
266332
})*
267333
})*
268334
}

library/proc_macro/src/bridge/handle.rs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,10 +27,14 @@ impl<T> OwnedStore<T> {
2727
pub(super) fn alloc(&mut self, x: T) -> Handle {
2828
let counter = self.counter.fetch_add(1, Ordering::SeqCst);
2929
let handle = Handle::new(counter as u32).expect("`proc_macro` handle counter overflowed");
30-
assert!(self.data.insert(handle, x).is_none());
30+
self.init(handle, x);
3131
handle
3232
}
3333

34+
pub(super) fn init(&mut self, h: Handle, x: T) {
35+
assert!(self.data.insert(h, x).is_none());
36+
}
37+
3438
pub(super) fn take(&mut self, h: Handle) -> T {
3539
self.data.remove(&h).expect("use-after-free in `proc_macro` handle")
3640
}

library/proc_macro/src/bridge/mod.rs

Lines changed: 103 additions & 78 deletions
Original file line numberDiff line numberDiff line change
@@ -28,10 +28,10 @@ use std::thread;
2828
/// // ...
2929
/// Literal {
3030
/// // ...
31-
/// fn character(ch: char) -> MySelf::Literal;
31+
/// wait fn character(ch: char) -> MySelf::Literal;
3232
/// // ...
33-
/// fn span(my_self: &MySelf::Literal) -> MySelf::Span;
34-
/// fn set_span(my_self: &mut MySelf::Literal, span: MySelf::Span);
33+
/// wait fn span(my_self: &MySelf::Literal) -> MySelf::Span;
34+
/// nowait fn set_span(my_self: &mut MySelf::Literal, span: MySelf::Span);
3535
/// },
3636
/// // ...
3737
/// }
@@ -49,119 +49,125 @@ use std::thread;
4949
/// a trait or a trait impl, where the trait has associated types
5050
/// for each of the API types. If non-associated types are desired,
5151
/// a module name (`self` in practice) can be used instead of `Self`.
52+
///
53+
/// If the `nowait` modifier is used, the server implementation may not
54+
/// panic, and the client will continue immediately without waiting for
55+
/// a response from the server when in multithreaded mode. If a return
56+
/// type is present, it must be an owning IPC handle. Other return types
57+
/// are not supported with `nowait`.
5258
macro_rules! with_api {
5359
($S:ident, $self:ident, $m:ident) => {
5460
$m! {
5561
FreeFunctions {
56-
fn drop($self: $S::FreeFunctions);
57-
fn track_env_var(var: &str, value: Option<&str>);
62+
nowait fn drop($self: $S::FreeFunctions);
63+
nowait fn track_env_var(var: &str, value: Option<&str>);
5864
},
5965
TokenStream {
60-
fn drop($self: $S::TokenStream);
61-
fn clone($self: &$S::TokenStream) -> $S::TokenStream;
62-
fn new() -> $S::TokenStream;
63-
fn is_empty($self: &$S::TokenStream) -> bool;
64-
fn from_str(src: &str) -> $S::TokenStream;
65-
fn to_string($self: &$S::TokenStream) -> String;
66-
fn from_token_tree(
66+
nowait fn drop($self: $S::TokenStream);
67+
nowait fn clone($self: &$S::TokenStream) -> $S::TokenStream;
68+
nowait fn new() -> $S::TokenStream;
69+
wait fn is_empty($self: &$S::TokenStream) -> bool;
70+
wait fn from_str(src: &str) -> $S::TokenStream;
71+
wait fn to_string($self: &$S::TokenStream) -> String;
72+
nowait fn from_token_tree(
6773
tree: TokenTree<$S::Group, $S::Punct, $S::Ident, $S::Literal>,
6874
) -> $S::TokenStream;
69-
fn into_iter($self: $S::TokenStream) -> $S::TokenStreamIter;
75+
nowait fn into_iter($self: $S::TokenStream) -> $S::TokenStreamIter;
7076
},
7177
TokenStreamBuilder {
72-
fn drop($self: $S::TokenStreamBuilder);
73-
fn new() -> $S::TokenStreamBuilder;
74-
fn push($self: &mut $S::TokenStreamBuilder, stream: $S::TokenStream);
75-
fn build($self: $S::TokenStreamBuilder) -> $S::TokenStream;
78+
nowait fn drop($self: $S::TokenStreamBuilder);
79+
nowait fn new() -> $S::TokenStreamBuilder;
80+
nowait fn push($self: &mut $S::TokenStreamBuilder, stream: $S::TokenStream);
81+
nowait fn build($self: $S::TokenStreamBuilder) -> $S::TokenStream;
7682
},
7783
TokenStreamIter {
78-
fn drop($self: $S::TokenStreamIter);
79-
fn clone($self: &$S::TokenStreamIter) -> $S::TokenStreamIter;
80-
fn next(
84+
nowait fn drop($self: $S::TokenStreamIter);
85+
nowait fn clone($self: &$S::TokenStreamIter) -> $S::TokenStreamIter;
86+
wait fn next(
8187
$self: &mut $S::TokenStreamIter,
8288
) -> Option<TokenTree<$S::Group, $S::Punct, $S::Ident, $S::Literal>>;
8389
},
8490
Group {
85-
fn drop($self: $S::Group);
86-
fn clone($self: &$S::Group) -> $S::Group;
87-
fn new(delimiter: Delimiter, stream: $S::TokenStream) -> $S::Group;
88-
fn delimiter($self: &$S::Group) -> Delimiter;
89-
fn stream($self: &$S::Group) -> $S::TokenStream;
90-
fn span($self: &$S::Group) -> $S::Span;
91-
fn span_open($self: &$S::Group) -> $S::Span;
92-
fn span_close($self: &$S::Group) -> $S::Span;
93-
fn set_span($self: &mut $S::Group, span: $S::Span);
91+
nowait fn drop($self: $S::Group);
92+
nowait fn clone($self: &$S::Group) -> $S::Group;
93+
nowait fn new(delimiter: Delimiter, stream: $S::TokenStream) -> $S::Group;
94+
wait fn delimiter($self: &$S::Group) -> Delimiter;
95+
nowait fn stream($self: &$S::Group) -> $S::TokenStream;
96+
wait fn span($self: &$S::Group) -> $S::Span;
97+
wait fn span_open($self: &$S::Group) -> $S::Span;
98+
wait fn span_close($self: &$S::Group) -> $S::Span;
99+
nowait fn set_span($self: &mut $S::Group, span: $S::Span);
94100
},
95101
Punct {
96-
fn new(ch: char, spacing: Spacing) -> $S::Punct;
97-
fn as_char($self: $S::Punct) -> char;
98-
fn spacing($self: $S::Punct) -> Spacing;
99-
fn span($self: $S::Punct) -> $S::Span;
100-
fn with_span($self: $S::Punct, span: $S::Span) -> $S::Punct;
102+
wait fn new(ch: char, spacing: Spacing) -> $S::Punct;
103+
wait fn as_char($self: $S::Punct) -> char;
104+
wait fn spacing($self: $S::Punct) -> Spacing;
105+
wait fn span($self: $S::Punct) -> $S::Span;
106+
wait fn with_span($self: $S::Punct, span: $S::Span) -> $S::Punct;
101107
},
102108
Ident {
103-
fn new(string: &str, span: $S::Span, is_raw: bool) -> $S::Ident;
104-
fn span($self: $S::Ident) -> $S::Span;
105-
fn with_span($self: $S::Ident, span: $S::Span) -> $S::Ident;
109+
wait fn new(string: &str, span: $S::Span, is_raw: bool) -> $S::Ident;
110+
wait fn span($self: $S::Ident) -> $S::Span;
111+
wait fn with_span($self: $S::Ident, span: $S::Span) -> $S::Ident;
106112
},
107113
Literal {
108-
fn drop($self: $S::Literal);
109-
fn clone($self: &$S::Literal) -> $S::Literal;
110-
fn from_str(s: &str) -> Result<$S::Literal, ()>;
111-
fn debug_kind($self: &$S::Literal) -> String;
112-
fn symbol($self: &$S::Literal) -> String;
113-
fn suffix($self: &$S::Literal) -> Option<String>;
114-
fn integer(n: &str) -> $S::Literal;
115-
fn typed_integer(n: &str, kind: &str) -> $S::Literal;
116-
fn float(n: &str) -> $S::Literal;
117-
fn f32(n: &str) -> $S::Literal;
118-
fn f64(n: &str) -> $S::Literal;
119-
fn string(string: &str) -> $S::Literal;
120-
fn character(ch: char) -> $S::Literal;
121-
fn byte_string(bytes: &[u8]) -> $S::Literal;
122-
fn span($self: &$S::Literal) -> $S::Span;
123-
fn set_span($self: &mut $S::Literal, span: $S::Span);
124-
fn subspan(
114+
nowait fn drop($self: $S::Literal);
115+
nowait fn clone($self: &$S::Literal) -> $S::Literal;
116+
wait fn from_str(s: &str) -> Result<$S::Literal, ()>;
117+
wait fn debug_kind($self: &$S::Literal) -> String;
118+
wait fn symbol($self: &$S::Literal) -> String;
119+
wait fn suffix($self: &$S::Literal) -> Option<String>;
120+
nowait fn integer(n: &str) -> $S::Literal;
121+
nowait fn typed_integer(n: &str, kind: &str) -> $S::Literal;
122+
nowait fn float(n: &str) -> $S::Literal;
123+
nowait fn f32(n: &str) -> $S::Literal;
124+
nowait fn f64(n: &str) -> $S::Literal;
125+
nowait fn string(string: &str) -> $S::Literal;
126+
nowait fn character(ch: char) -> $S::Literal;
127+
nowait fn byte_string(bytes: &[u8]) -> $S::Literal;
128+
wait fn span($self: &$S::Literal) -> $S::Span;
129+
nowait fn set_span($self: &mut $S::Literal, span: $S::Span);
130+
wait fn subspan(
125131
$self: &$S::Literal,
126132
start: Bound<usize>,
127133
end: Bound<usize>,
128134
) -> Option<$S::Span>;
129135
},
130136
SourceFile {
131-
fn drop($self: $S::SourceFile);
132-
fn clone($self: &$S::SourceFile) -> $S::SourceFile;
133-
fn eq($self: &$S::SourceFile, other: &$S::SourceFile) -> bool;
134-
fn path($self: &$S::SourceFile) -> String;
135-
fn is_real($self: &$S::SourceFile) -> bool;
137+
nowait fn drop($self: $S::SourceFile);
138+
nowait fn clone($self: &$S::SourceFile) -> $S::SourceFile;
139+
wait fn eq($self: &$S::SourceFile, other: &$S::SourceFile) -> bool;
140+
wait fn path($self: &$S::SourceFile) -> String;
141+
wait fn is_real($self: &$S::SourceFile) -> bool;
136142
},
137143
MultiSpan {
138-
fn drop($self: $S::MultiSpan);
139-
fn new() -> $S::MultiSpan;
140-
fn push($self: &mut $S::MultiSpan, span: $S::Span);
144+
nowait fn drop($self: $S::MultiSpan);
145+
nowait fn new() -> $S::MultiSpan;
146+
wait fn push($self: &mut $S::MultiSpan, span: $S::Span);
141147
},
142148
Diagnostic {
143-
fn drop($self: $S::Diagnostic);
144-
fn new(level: Level, msg: &str, span: $S::MultiSpan) -> $S::Diagnostic;
145-
fn sub(
149+
wait fn drop($self: $S::Diagnostic);
150+
wait fn new(level: Level, msg: &str, span: $S::MultiSpan) -> $S::Diagnostic;
151+
wait fn sub(
146152
$self: &mut $S::Diagnostic,
147153
level: Level,
148154
msg: &str,
149155
span: $S::MultiSpan,
150156
);
151-
fn emit($self: $S::Diagnostic);
157+
wait fn emit($self: $S::Diagnostic);
152158
},
153159
Span {
154-
fn debug($self: $S::Span) -> String;
155-
fn source_file($self: $S::Span) -> $S::SourceFile;
156-
fn parent($self: $S::Span) -> Option<$S::Span>;
157-
fn source($self: $S::Span) -> $S::Span;
158-
fn start($self: $S::Span) -> LineColumn;
159-
fn end($self: $S::Span) -> LineColumn;
160-
fn join($self: $S::Span, other: $S::Span) -> Option<$S::Span>;
161-
fn resolved_at($self: $S::Span, at: $S::Span) -> $S::Span;
162-
fn source_text($self: $S::Span) -> Option<String>;
163-
fn save_span($self: $S::Span) -> usize;
164-
fn recover_proc_macro_span(id: usize) -> $S::Span;
160+
wait fn debug($self: $S::Span) -> String;
161+
wait fn source_file($self: $S::Span) -> $S::SourceFile;
162+
wait fn parent($self: $S::Span) -> Option<$S::Span>;
163+
wait fn source($self: $S::Span) -> $S::Span;
164+
wait fn start($self: $S::Span) -> LineColumn;
165+
wait fn end($self: $S::Span) -> LineColumn;
166+
wait fn join($self: $S::Span, other: $S::Span) -> Option<$S::Span>;
167+
wait fn resolved_at($self: $S::Span, at: $S::Span) -> $S::Span;
168+
wait fn source_text($self: $S::Span) -> Option<String>;
169+
wait fn save_span($self: $S::Span) -> usize;
170+
wait fn recover_proc_macro_span(id: usize) -> $S::Span;
165171
},
166172
}
167173
};
@@ -232,9 +238,18 @@ impl<'a> !Send for BridgeConfig<'a> {}
232238
mod api_tags {
233239
use super::rpc::{DecodeMut, Encode, Reader, Writer};
234240

241+
macro_rules! should_wait_impl {
242+
(wait) => {
243+
true
244+
};
245+
(nowait) => {
246+
false
247+
};
248+
}
249+
235250
macro_rules! declare_tags {
236251
($($name:ident {
237-
$(fn $method:ident($($arg:ident: $arg_ty:ty),* $(,)?) $(-> $ret_ty:ty)*;)*
252+
$($wait:ident fn $method:ident($($arg:ident: $arg_ty:ty),* $(,)?) $(-> $ret_ty:ty)*;)*
238253
}),* $(,)?) => {
239254
$(
240255
pub(super) enum $name {
@@ -248,6 +263,16 @@ mod api_tags {
248263
$($name($name)),*
249264
}
250265
rpc_encode_decode!(enum Method { $($name(m)),* });
266+
267+
impl Method {
268+
pub(super) fn should_wait(&self) -> bool {
269+
match self {
270+
$($(
271+
Method::$name($name::$method) => should_wait_impl!($wait),
272+
)*)*
273+
}
274+
}
275+
}
251276
}
252277
}
253278
with_api!(self, self, declare_tags);

0 commit comments

Comments
 (0)