@@ -922,6 +922,33 @@ impl CodeBuilder<'_> {
922
922
self . allocs . operands . push ( ty) ;
923
923
}
924
924
925
+ fn pop_label_types ( & mut self , module : & Module , target : u32 ) {
926
+ let target = usize:: try_from ( target) . unwrap ( ) ;
927
+ let control = & self . allocs . controls [ self . allocs . controls . len ( ) - 1 - target] ;
928
+ debug_assert ! ( self . label_types_on_stack( module, control) ) ;
929
+ self . allocs
930
+ . operands
931
+ . truncate ( self . allocs . operands . len ( ) - control. label_types ( ) . len ( ) ) ;
932
+ }
933
+
934
+ fn push_label_types ( & mut self , target : u32 ) {
935
+ let target = usize:: try_from ( target) . unwrap ( ) ;
936
+ let control = & self . allocs . controls [ self . allocs . controls . len ( ) - 1 - target] ;
937
+ self . allocs
938
+ . operands
939
+ . extend ( control. label_types ( ) . iter ( ) . copied ( ) . map ( Some ) ) ;
940
+ }
941
+
942
+ /// Pop the target label types, and then push them again.
943
+ ///
944
+ /// This is not a no-op due to subtyping: if we have a `T <: U` on the
945
+ /// stack, and the target label's type is `[U]`, then this will erase the
946
+ /// information about `T` and subsequent operations may only operate on `U`.
947
+ fn pop_push_label_types ( & mut self , module : & Module , target : u32 ) {
948
+ self . pop_label_types ( module, target) ;
949
+ self . push_label_types ( target)
950
+ }
951
+
925
952
fn label_types_on_stack ( & self , module : & Module , to_check : & Control ) -> bool {
926
953
self . types_on_stack ( module, to_check. label_types ( ) )
927
954
}
@@ -1710,10 +1737,9 @@ fn br(
1710
1737
. filter ( |( _, l) | builder. label_types_on_stack ( module, l) )
1711
1738
. nth ( i)
1712
1739
. unwrap ( ) ;
1713
- let control = & builder. allocs . controls [ builder. allocs . controls . len ( ) - 1 - target] ;
1714
- let tys = control. label_types ( ) . to_vec ( ) ;
1715
- builder. pop_operands ( module, & tys) ;
1716
- instructions. push ( Instruction :: Br ( target as u32 ) ) ;
1740
+ let target = u32:: try_from ( target) . unwrap ( ) ;
1741
+ builder. pop_label_types ( module, target) ;
1742
+ instructions. push ( Instruction :: Br ( target) ) ;
1717
1743
Ok ( ( ) )
1718
1744
}
1719
1745
@@ -1757,7 +1783,9 @@ fn br_if(
1757
1783
. filter ( |( _, l) | builder. label_types_on_stack ( module, l) )
1758
1784
. nth ( i)
1759
1785
. unwrap ( ) ;
1760
- instructions. push ( Instruction :: BrIf ( target as u32 ) ) ;
1786
+ let target = u32:: try_from ( target) . unwrap ( ) ;
1787
+ builder. pop_push_label_types ( module, target) ;
1788
+ instructions. push ( Instruction :: BrIf ( target) ) ;
1761
1789
Ok ( ( ) )
1762
1790
}
1763
1791
@@ -2203,13 +2231,15 @@ fn br_on_null(
2203
2231
. filter ( |( _, l) | builder. label_types_on_stack ( module, l) )
2204
2232
. nth ( i)
2205
2233
. unwrap ( ) ;
2234
+ let target = u32:: try_from ( target) . unwrap ( ) ;
2206
2235
2236
+ builder. pop_push_label_types ( module, target) ;
2207
2237
builder. push_operands ( & [ ValType :: Ref ( RefType {
2208
2238
nullable : false ,
2209
2239
heap_type,
2210
2240
} ) ] ) ;
2211
2241
2212
- instructions. push ( Instruction :: BrOnNull ( u32 :: try_from ( target) . unwrap ( ) ) ) ;
2242
+ instructions. push ( Instruction :: BrOnNull ( target) ) ;
2213
2243
Ok ( ( ) )
2214
2244
}
2215
2245
@@ -2270,9 +2300,11 @@ fn br_on_non_null(
2270
2300
. filter ( |( _, l) | is_valid_br_on_non_null_control ( module, l, builder) )
2271
2301
. nth ( i)
2272
2302
. unwrap ( ) ;
2303
+ let target = u32:: try_from ( target) . unwrap ( ) ;
2273
2304
2305
+ builder. pop_push_label_types ( module, target) ;
2274
2306
builder. pop_ref_type ( ) ;
2275
- instructions. push ( Instruction :: BrOnNonNull ( u32 :: try_from ( target) . unwrap ( ) ) ) ;
2307
+ instructions. push ( Instruction :: BrOnNonNull ( target) ) ;
2276
2308
Ok ( ( ) )
2277
2309
}
2278
2310
@@ -2354,6 +2386,7 @@ fn br_on_cast(
2354
2386
. unwrap ( ) ;
2355
2387
let relative_depth = u32:: try_from ( relative_depth) . unwrap ( ) ;
2356
2388
2389
+ let num_label_types = control. label_types ( ) . len ( ) ;
2357
2390
let to_ref_type = match control. label_types ( ) . last ( ) {
2358
2391
Some ( ValType :: Ref ( r) ) => * r,
2359
2392
_ => unreachable ! ( ) ,
@@ -2363,6 +2396,15 @@ fn br_on_cast(
2363
2396
let from_ref_type = from_ref_type. unwrap_or ( to_ref_type) ;
2364
2397
let from_ref_type = module. arbitrary_super_type_of_ref_type ( u, from_ref_type) ?;
2365
2398
2399
+ // Do `pop_push_label_types` but without its debug assert that the types are
2400
+ // on the stack, since we know that we have a `from_ref_type` but the label
2401
+ // requires a `to_ref_type`.
2402
+ for _ in 0 ..num_label_types {
2403
+ builder. pop_operand ( ) ;
2404
+ }
2405
+ builder. push_label_types ( relative_depth) ;
2406
+
2407
+ // Replace the label's `to_ref_type` with the type difference.
2366
2408
builder. pop_operand ( ) ;
2367
2409
builder. push_operands ( & [ ValType :: Ref ( ref_type_difference (
2368
2410
from_ref_type,
@@ -2433,7 +2475,7 @@ fn br_on_cast_fail(
2433
2475
debug_assert ! ( n > 0 ) ;
2434
2476
2435
2477
let i = u. int_in_range ( 0 ..=n - 1 ) ?;
2436
- let ( target , control) = builder
2478
+ let ( relative_depth , control) = builder
2437
2479
. allocs
2438
2480
. controls
2439
2481
. iter ( )
@@ -2442,6 +2484,7 @@ fn br_on_cast_fail(
2442
2484
. filter ( |( _, l) | is_valid_br_on_cast_fail_control ( module, builder, l, from_ref_type) )
2443
2485
. nth ( i)
2444
2486
. unwrap ( ) ;
2487
+ let relative_depth = u32:: try_from ( relative_depth) . unwrap ( ) ;
2445
2488
2446
2489
let from_ref_type =
2447
2490
from_ref_type. unwrap_or_else ( || match control. label_types ( ) . last ( ) . unwrap ( ) {
@@ -2450,13 +2493,16 @@ fn br_on_cast_fail(
2450
2493
} ) ;
2451
2494
let to_ref_type = module. arbitrary_matching_ref_type ( u, from_ref_type) ?;
2452
2495
2496
+ // Pop-push the label types and then replace its last reference type with
2497
+ // our `to_ref_type`.
2498
+ builder. pop_push_label_types ( module, relative_depth) ;
2453
2499
builder. pop_operand ( ) ;
2454
2500
builder. push_operand ( Some ( ValType :: Ref ( to_ref_type) ) ) ;
2455
2501
2456
2502
instructions. push ( Instruction :: BrOnCastFail {
2457
2503
from_ref_type,
2458
2504
to_ref_type,
2459
- relative_depth : u32 :: try_from ( target ) . unwrap ( ) ,
2505
+ relative_depth,
2460
2506
} ) ;
2461
2507
Ok ( ( ) )
2462
2508
}
0 commit comments