@@ -7,7 +7,7 @@ use crate::type_of::LayoutLlvmExt;
77use crate :: va_arg:: emit_va_arg;
88use crate :: value:: Value ;
99
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 } ;
1111use rustc_codegen_ssa:: common:: { IntPredicate , TypeKind } ;
1212use rustc_codegen_ssa:: errors:: { ExpectedPointerMutability , InvalidMonomorphization } ;
1313use rustc_codegen_ssa:: mir:: operand:: OperandRef ;
@@ -452,6 +452,8 @@ fn try_intrinsic<'ll>(
452452 bx. store ( bx. const_i32 ( 0 ) , dest, ret_align) ;
453453 } else if wants_msvc_seh ( bx. sess ( ) ) {
454454 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) ;
455457 } else if bx. sess ( ) . target . os == "emscripten" {
456458 codegen_emcc_try ( bx, try_func, data, catch_func, dest) ;
457459 } else {
@@ -610,6 +612,80 @@ fn codegen_msvc_try<'ll>(
610612 bx. store ( ret, dest, i32_align) ;
611613}
612614
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+
613689// Definition of the standard `try` function for Rust using the GNU-like model
614690// of exceptions (e.g., the normal semantics of LLVM's `landingpad` and `invoke`
615691// instructions).
0 commit comments