@@ -3,8 +3,45 @@ use super::*;
33struct Unbudgeted ;
44struct Bounded ;
55
6- type UnbudgetedHandler = for <' store > fn ( & mut Executor < ' store > , & [ Instruction ] , usize , Instruction ) -> ExecResult < ( ) > ;
7- type BoundedHandler = for <' store > fn ( & mut Executor < ' store > , usize , Instruction , u32 ) -> ExecResult < ( ) > ;
6+ // Between two handlers only what the calling convention passes in registers stays out of memory,
7+ // so the handlers' convention depends on the target:
8+ // - x86-64: the Rust ABI passes six integer arguments in registers on System V but four on
9+ // Windows, which would put the Instruction on the stack. `rust-preserve-none`
10+ // passes twelve on every OS and keeps only RSP and RBP callee-saved, so a handler saves at most
11+ // RBP, and only when it uses it.
12+ // - arm64_32 (watchOS): the Rust ABI passes an aggregate larger than a pointer, the 8-byte
13+ // `Instruction`, by reference, so every dispatch would store it and the next handler load it
14+ // back. The C convention passes it in a register; `C-unwind` still lets a host function's
15+ // panic unwind.
16+ // - elsewhere, the Rust ABI (arm64 passes 8 integer arguments in registers).
17+ macro_rules! handler_fn {
18+ ( $( #[ $meta: meta] ) * fn $( $rest: tt) * ) => {
19+ #[ cfg( target_arch = "x86_64" ) ]
20+ $( #[ $meta] ) * extern "rust-preserve-none" fn $( $rest) *
21+ #[ cfg( all( target_arch = "aarch64" , target_pointer_width = "32" ) ) ]
22+ #[ allow( improper_ctypes_definitions) ]
23+ $( #[ $meta] ) * extern "C-unwind" fn $( $rest) *
24+ #[ cfg( not( any( target_arch = "x86_64" , all( target_arch = "aarch64" , target_pointer_width = "32" ) ) ) ) ]
25+ $( #[ $meta] ) * fn $( $rest) *
26+ } ;
27+ }
28+
29+ macro_rules! handler_types {
30+ ( $( $abi: literal) ?) => {
31+ // Both sides are Rust, so the C convention's view of these types need not be FFI-safe.
32+ #[ allow( improper_ctypes_definitions) ]
33+ type UnbudgetedHandler =
34+ for <' store> $( extern $abi) ? fn ( & mut Executor <' store>, & [ Instruction ] , usize , Instruction ) -> ExecResult <( ) >;
35+ #[ allow( improper_ctypes_definitions) ]
36+ type BoundedHandler = for <' store> $( extern $abi) ? fn ( & mut Executor <' store>, usize , Instruction , u32 ) -> ExecResult <( ) >;
37+ } ;
38+ }
39+ #[ cfg( target_arch = "x86_64" ) ]
40+ handler_types ! ( "rust-preserve-none" ) ;
41+ #[ cfg( all( target_arch = "aarch64" , target_pointer_width = "32" ) ) ]
42+ handler_types ! ( "C-unwind" ) ;
43+ #[ cfg( not( any( target_arch = "x86_64" , all( target_arch = "aarch64" , target_pointer_width = "32" ) ) ) ) ]
44+ handler_types ! ( ) ;
845
946macro_rules! define_unbudgeted_tail_dispatch {
1047 ( $executor: ident, $instr_ptr: ident, $dispatch_next: ident, $dispatch_flow: ident;
@@ -19,7 +56,7 @@ macro_rules! define_unbudgeted_tail_dispatch {
1956 HANDLERS [ opcode as usize ]
2057 }
2158
22- $(
59+ $( handler_fn! {
2360 #[ allow( non_snake_case, unreachable_code, unused_imports, unused_macros, unused_variables) ]
2461 fn $variant(
2562 $executor: & mut Executor <' _>,
@@ -59,7 +96,7 @@ macro_rules! define_unbudgeted_tail_dispatch {
5996 $body;
6097 $dispatch_next!( $instr_ptr + 1 )
6198 }
62- ) *
99+ } ) *
63100 } ;
64101}
65102
@@ -76,7 +113,7 @@ macro_rules! define_bounded_tail_dispatch {
76113 HANDLERS [ opcode as usize ]
77114 }
78115
79- $(
116+ $( handler_fn! {
80117 #[ allow( non_snake_case, unreachable_code, unused_imports, unused_macros, unused_variables) ]
81118 fn $variant(
82119 $executor: & mut Executor <' _>,
@@ -122,7 +159,7 @@ macro_rules! define_bounded_tail_dispatch {
122159 $body;
123160 $dispatch_next!( $instr_ptr + 1 )
124161 }
125- ) *
162+ } ) *
126163 } ;
127164}
128165
@@ -132,16 +169,20 @@ impl Unbudgeted {
132169 // The handlers tail-call these cold paths instead of calling them: a call would make every
133170 // handler save a stack frame.
134171
135- #[ cold]
136- #[ inline( never) ]
137- fn handler_mismatch ( _: & mut Executor < ' _ > , _: & [ Instruction ] , _: usize , _: Instruction ) -> ExecResult < ( ) > {
138- unreachable ! ( "instruction handler mismatch" )
172+ handler_fn ! {
173+ #[ cold]
174+ #[ inline( never) ]
175+ fn handler_mismatch( _: & mut Executor <' _>, _: & [ Instruction ] , _: usize , _: Instruction ) -> ExecResult <( ) > {
176+ unreachable!( "instruction handler mismatch" )
177+ }
139178 }
140179
141- #[ cold]
142- #[ inline( never) ]
143- fn invalid_instr_ptr ( _: & mut Executor < ' _ > , _: & [ Instruction ] , instr_ptr : usize , _: Instruction ) -> ExecResult < ( ) > {
144- unreachable ! ( "instruction pointer {instr_ptr} out of range, this is a bug" )
180+ handler_fn ! {
181+ #[ cold]
182+ #[ inline( never) ]
183+ fn invalid_instr_ptr( _: & mut Executor <' _>, _: & [ Instruction ] , instr_ptr: usize , _: Instruction ) -> ExecResult <( ) > {
184+ unreachable!( "instruction pointer {instr_ptr} out of range, this is a bug" )
185+ }
145186 }
146187}
147188
@@ -150,16 +191,20 @@ impl Bounded {
150191
151192 // Tail-called like `Unbudgeted`'s.
152193
153- #[ cold]
154- #[ inline( never) ]
155- fn handler_mismatch ( _: & mut Executor < ' _ > , _: usize , _: Instruction , _: u32 ) -> ExecResult < ( ) > {
156- unreachable ! ( "instruction handler mismatch" )
194+ handler_fn ! {
195+ #[ cold]
196+ #[ inline( never) ]
197+ fn handler_mismatch( _: & mut Executor <' _>, _: usize , _: Instruction , _: u32 ) -> ExecResult <( ) > {
198+ unreachable!( "instruction handler mismatch" )
199+ }
157200 }
158201
159- #[ cold]
160- #[ inline( never) ]
161- fn invalid_instr_ptr ( _: & mut Executor < ' _ > , instr_ptr : usize , _: Instruction , _: u32 ) -> ExecResult < ( ) > {
162- unreachable ! ( "instruction pointer {instr_ptr} out of range, this is a bug" )
202+ handler_fn ! {
203+ #[ cold]
204+ #[ inline( never) ]
205+ fn invalid_instr_ptr( _: & mut Executor <' _>, instr_ptr: usize , _: Instruction , _: u32 ) -> ExecResult <( ) > {
206+ unreachable!( "instruction pointer {instr_ptr} out of range, this is a bug" )
207+ }
163208 }
164209
165210 #[ inline( always) ]
0 commit comments