@@ -7,7 +7,7 @@ use crate::type_of::LayoutLlvmExt;
7
7
use crate :: va_arg:: emit_va_arg;
8
8
use crate :: value:: Value ;
9
9
10
- use rustc_codegen_ssa:: base:: { compare_simd_types, wants_msvc_seh} ;
10
+ use rustc_codegen_ssa:: base:: { compare_simd_types, wants_msvc_seh, wants_wasm_eh } ;
11
11
use rustc_codegen_ssa:: common:: { IntPredicate , TypeKind } ;
12
12
use rustc_codegen_ssa:: errors:: { ExpectedPointerMutability , InvalidMonomorphization } ;
13
13
use rustc_codegen_ssa:: mir:: operand:: OperandRef ;
@@ -452,6 +452,8 @@ fn try_intrinsic<'ll>(
452
452
bx. store ( bx. const_i32 ( 0 ) , dest, ret_align) ;
453
453
} else if wants_msvc_seh ( bx. sess ( ) ) {
454
454
codegen_msvc_try ( bx, try_func, data, catch_func, dest) ;
455
+ } else if wants_wasm_eh ( bx. sess ( ) ) {
456
+ codegen_wasm_try ( bx, try_func, data, catch_func, dest) ;
455
457
} else if bx. sess ( ) . target . os == "emscripten" {
456
458
codegen_emcc_try ( bx, try_func, data, catch_func, dest) ;
457
459
} else {
@@ -610,6 +612,80 @@ fn codegen_msvc_try<'ll>(
610
612
bx. store ( ret, dest, i32_align) ;
611
613
}
612
614
615
+ // WASM's definition of the `rust_try` function.
616
+ fn codegen_wasm_try < ' ll > (
617
+ bx : & mut Builder < ' _ , ' ll , ' _ > ,
618
+ try_func : & ' ll Value ,
619
+ data : & ' ll Value ,
620
+ catch_func : & ' ll Value ,
621
+ dest : & ' ll Value ,
622
+ ) {
623
+ let ( llty, llfn) = get_rust_try_fn ( bx, & mut |mut bx| {
624
+ bx. set_personality_fn ( bx. eh_personality ( ) ) ;
625
+
626
+ let normal = bx. append_sibling_block ( "normal" ) ;
627
+ let catchswitch = bx. append_sibling_block ( "catchswitch" ) ;
628
+ let catchpad = bx. append_sibling_block ( "catchpad" ) ;
629
+ let caught = bx. append_sibling_block ( "caught" ) ;
630
+
631
+ let try_func = llvm:: get_param ( bx. llfn ( ) , 0 ) ;
632
+ let data = llvm:: get_param ( bx. llfn ( ) , 1 ) ;
633
+ let catch_func = llvm:: get_param ( bx. llfn ( ) , 2 ) ;
634
+
635
+ // We're generating an IR snippet that looks like:
636
+ //
637
+ // declare i32 @rust_try(%try_func, %data, %catch_func) {
638
+ // %slot = alloca i8*
639
+ // invoke %try_func(%data) to label %normal unwind label %catchswitch
640
+ //
641
+ // normal:
642
+ // ret i32 0
643
+ //
644
+ // catchswitch:
645
+ // %cs = catchswitch within none [%catchpad_rust] unwind to caller
646
+ //
647
+ // catchpad:
648
+ // %tok = catchpad within %cs [null]
649
+ // %ptr = call @llvm.wasm.get.exception(token %tok)
650
+ // %sel = call @llvm.wasm.get.ehselector(token %tok)
651
+ // call %catch_func(%data, %ptr)
652
+ // catchret from %tok to label %caught
653
+ //
654
+ // caught:
655
+ // ret i32 1
656
+ // }
657
+ //
658
+ let try_func_ty = bx. type_func ( & [ bx. type_i8p ( ) ] , bx. type_void ( ) ) ;
659
+ bx. invoke ( try_func_ty, None , None , try_func, & [ data] , normal, catchswitch, None ) ;
660
+
661
+ bx. switch_to_block ( normal) ;
662
+ bx. ret ( bx. const_i32 ( 0 ) ) ;
663
+
664
+ bx. switch_to_block ( catchswitch) ;
665
+ let cs = bx. catch_switch ( None , None , & [ catchpad] ) ;
666
+
667
+ bx. switch_to_block ( catchpad) ;
668
+ let null = bx. const_null ( bx. type_i8p ( ) ) ;
669
+ let funclet = bx. catch_pad ( cs, & [ null] ) ;
670
+
671
+ let ptr = bx. call_intrinsic ( "llvm.wasm.get.exception" , & [ funclet. cleanuppad ( ) ] ) ;
672
+ let _sel = bx. call_intrinsic ( "llvm.wasm.get.ehselector" , & [ funclet. cleanuppad ( ) ] ) ;
673
+
674
+ let catch_ty = bx. type_func ( & [ bx. type_i8p ( ) , bx. type_i8p ( ) ] , bx. type_void ( ) ) ;
675
+ bx. call ( catch_ty, None , None , catch_func, & [ data, ptr] , Some ( & funclet) ) ;
676
+ bx. catch_ret ( & funclet, caught) ;
677
+
678
+ bx. switch_to_block ( caught) ;
679
+ bx. ret ( bx. const_i32 ( 1 ) ) ;
680
+ } ) ;
681
+
682
+ // Note that no invoke is used here because by definition this function
683
+ // can't panic (that's what it's catching).
684
+ let ret = bx. call ( llty, None , None , llfn, & [ try_func, data, catch_func] , None ) ;
685
+ let i32_align = bx. tcx ( ) . data_layout . i32_align . abi ;
686
+ bx. store ( ret, dest, i32_align) ;
687
+ }
688
+
613
689
// Definition of the standard `try` function for Rust using the GNU-like model
614
690
// of exceptions (e.g., the normal semantics of LLVM's `landingpad` and `invoke`
615
691
// instructions).
0 commit comments