@@ -13,10 +13,12 @@ struct Bounded;
1313// On arm64_32 (watchOS) the Rust ABI passes an aggregate larger than a pointer, the 8-byte
1414// `Instruction`, by reference, so every dispatch would store it and the next handler load it back.
1515// The C convention passes it in a register; `C-unwind` still lets a host function's panic unwind.
16- // On Windows x64 the handlers use the System V convention (`sysv64-unwind`), which passes six
17- // integer arguments in registers where Windows' own passes four, so a dispatch no longer stores the
18- // height for the next handler to load back. The `Instruction` still goes through the stack there:
19- // the System V rules pass this enum in memory. Elsewhere the handlers keep the Rust ABI, which
16+ // On Windows x64 the unbudgeted handlers use the System V convention (`sysv64-unwind`), which
17+ // passes six integer arguments in registers where Windows' own passes four, so a dispatch no longer
18+ // stores the height for the next handler to load back. The `Instruction` still goes through the
19+ // stack there: the System V rules pass this enum in memory. The bounded handlers keep the Rust ABI
20+ // on Windows x64 and do not pass the height, so their four arguments, the `Instruction` among them,
21+ // stay in Windows' four argument registers. Elsewhere the handlers keep the Rust ABI, which
2022// passes eight integer arguments in registers on arm64 and six on x86-64 System V, with the
2123// `Instruction` in one of them.
2224macro_rules! handler_fn {
@@ -32,17 +34,57 @@ macro_rules! handler_fn {
3234 } ;
3335}
3436
37+ macro_rules! bounded_handler_fn {
38+ ( $( #[ $meta: meta] ) * fn $( $rest: tt) * ) => {
39+ #[ cfg( all( target_arch = "aarch64" , target_pointer_width = "32" ) ) ]
40+ #[ allow( improper_ctypes_definitions) ]
41+ $( #[ $meta] ) * extern "C-unwind" fn $( $rest) *
42+ #[ cfg( not( all( target_arch = "aarch64" , target_pointer_width = "32" ) ) ) ]
43+ $( #[ $meta] ) * fn $( $rest) *
44+ } ;
45+ }
46+
47+ /// The height a bounded handler passes on: nothing on Windows x64.
48+ #[ cfg( not( all( target_arch = "x86_64" , windows) ) ) ]
49+ type BoundedHeight = usize ;
50+ #[ cfg( all( target_arch = "x86_64" , windows) ) ]
51+ type BoundedHeight = ( ) ;
52+
53+ #[ inline( always) ]
54+ fn bounded_height ( executor : & Executor < ' _ > ) -> BoundedHeight {
55+ #[ cfg( not( all( target_arch = "x86_64" , windows) ) ) ]
56+ return executor. value_stack . stack_32 . len ( ) ;
57+ #[ cfg( all( target_arch = "x86_64" , windows) ) ]
58+ {
59+ let _ = executor;
60+ }
61+ }
62+
63+ /// Writes a passed height back to the stack.
64+ #[ inline( always) ]
65+ fn enter_bounded_height ( executor : & mut Executor < ' _ > , height32 : BoundedHeight ) {
66+ #[ cfg( not( all( target_arch = "x86_64" , windows) ) ) ]
67+ executor. value_stack . stack_32 . set_len ( height32) ;
68+ #[ cfg( all( target_arch = "x86_64" , windows) ) ]
69+ {
70+ let _ = ( executor, height32) ;
71+ }
72+ }
73+
3574macro_rules! handler_types {
3675 ( $( $abi: literal) ?) => {
3776 // Both sides are Rust, so the C convention's view of these types need not be FFI-safe.
3877 #[ allow( improper_ctypes_definitions) ]
3978 type UnbudgetedHandler =
4079 for <' store> $( extern $abi) ? fn ( & mut Executor <' store>, & [ Instruction ] , usize , Instruction , usize ) -> ExecResult <( ) >;
41- #[ allow( improper_ctypes_definitions) ]
42- type BoundedHandler = for <' store> $( extern $abi) ? fn ( & mut Executor <' store>, usize , Instruction , u32 , usize ) -> ExecResult <( ) >;
4380 } ;
4481}
4582#[ cfg( all( target_arch = "aarch64" , target_pointer_width = "32" ) ) ]
83+ #[ allow( improper_ctypes_definitions) ]
84+ type BoundedHandler = for <' store > extern "C-unwind" fn ( & mut Executor < ' store > , usize , Instruction , u32 , BoundedHeight ) -> ExecResult < ( ) > ;
85+ #[ cfg( not( all( target_arch = "aarch64" , target_pointer_width = "32" ) ) ) ]
86+ type BoundedHandler = for <' store > fn ( & mut Executor < ' store > , usize , Instruction , u32 , BoundedHeight ) -> ExecResult < ( ) > ;
87+ #[ cfg( all( target_arch = "aarch64" , target_pointer_width = "32" ) ) ]
4688handler_types ! ( "C-unwind" ) ;
4789#[ cfg( all( target_arch = "x86_64" , windows) ) ]
4890handler_types ! ( "sysv64-unwind" ) ;
@@ -122,19 +164,19 @@ macro_rules! define_bounded_tail_dispatch {
122164 HANDLERS [ opcode as usize ]
123165 }
124166
125- $( handler_fn ! {
167+ $( bounded_handler_fn ! {
126168 #[ allow( non_snake_case, unreachable_code, unused_imports, unused_macros, unused_variables) ]
127169 fn $variant(
128170 $executor: & mut Executor <' _>,
129171 $instr_ptr: usize ,
130172 instruction: Instruction ,
131173 instructions_until_checkpoint: u32 ,
132- height32: usize ,
174+ height32: BoundedHeight ,
133175 ) -> ExecResult <( ) > {
134176 macro_rules! $dispatch_next {
135177 ( $next_instr_ptr: expr) => { {
136178 let next_instr_ptr = $next_instr_ptr;
137- let height32 = $executor. value_stack . stack_32 . len ( ) ;
179+ let height32 = bounded_height ( $executor) ;
138180 if instructions_until_checkpoint == 0 {
139181 return cold!( {
140182 $executor. cf. instr_ptr = next_instr_ptr;
@@ -167,7 +209,7 @@ macro_rules! define_bounded_tail_dispatch {
167209 $( let $variant { $( $field) ,* } = & instruction else {
168210 become Self :: handler_mismatch( $executor, $instr_ptr, instruction, instructions_until_checkpoint, height32) ;
169211 } ; ) ?
170- $executor. value_stack . stack_32 . set_len ( height32) ;
212+ enter_bounded_height ( $executor, height32) ;
171213 $body;
172214 $dispatch_next!( $instr_ptr + 1 )
173215 }
@@ -203,18 +245,18 @@ impl Bounded {
203245
204246 // Tail-called like `Unbudgeted`'s.
205247
206- handler_fn ! {
248+ bounded_handler_fn ! {
207249 #[ cold]
208250 #[ inline( never) ]
209- fn handler_mismatch( _: & mut Executor <' _>, _: usize , _: Instruction , _: u32 , _: usize ) -> ExecResult <( ) > {
251+ fn handler_mismatch( _: & mut Executor <' _>, _: usize , _: Instruction , _: u32 , _: BoundedHeight ) -> ExecResult <( ) > {
210252 unreachable!( "instruction handler mismatch" )
211253 }
212254 }
213255
214- handler_fn ! {
256+ bounded_handler_fn ! {
215257 #[ cold]
216258 #[ inline( never) ]
217- fn invalid_instr_ptr( _: & mut Executor <' _>, instr_ptr: usize , _: Instruction , _: u32 , _: usize ) -> ExecResult <( ) > {
259+ fn invalid_instr_ptr( _: & mut Executor <' _>, instr_ptr: usize , _: Instruction , _: u32 , _: BoundedHeight ) -> ExecResult <( ) > {
218260 unreachable!( "instruction pointer {instr_ptr} out of range, this is a bug" )
219261 }
220262 }
@@ -224,7 +266,7 @@ impl Bounded {
224266 let instr_ptr = executor. cf . instr_ptr ;
225267 let instruction = executor. func . instructions [ instr_ptr] ;
226268 let handler = Self :: handler_for ( instruction. opcode ( ) ) ;
227- let height32 = executor . value_stack . stack_32 . len ( ) ;
269+ let height32 = bounded_height ( executor ) ;
228270 handler ( executor, instr_ptr, instruction, CHECKPOINT_INTERVAL - 1 , height32)
229271 }
230272}
0 commit comments