@@ -13,7 +13,7 @@ use gccjit::{
1313 RValue ,
1414 ToRValue ,
1515 Type ,
16- UnaryOp ,
16+ UnaryOp , FunctionType ,
1717} ;
1818use rustc_codegen_ssa:: MemFlags ;
1919use rustc_codegen_ssa:: common:: { AtomicOrdering , AtomicRmwBinOp , IntPredicate , RealPredicate , SynchronizationScope } ;
@@ -372,10 +372,11 @@ impl<'tcx> FnAbiOfHelpers<'tcx> for Builder<'_, '_, 'tcx> {
372372 }
373373}
374374
375- impl < ' gcc , ' tcx > Deref for Builder < ' _ , ' gcc , ' tcx > {
375+ impl < ' a , ' gcc , ' tcx > Deref for Builder < ' a , ' gcc , ' tcx > {
376376 type Target = CodegenCx < ' gcc , ' tcx > ;
377377
378- fn deref ( & self ) -> & Self :: Target {
378+ fn deref < ' b > ( & ' b self ) -> & ' a Self :: Target
379+ {
379380 self . cx
380381 }
381382}
@@ -393,7 +394,7 @@ impl<'gcc, 'tcx> BackendTypes for Builder<'_, 'gcc, 'tcx> {
393394}
394395
395396impl < ' a , ' gcc , ' tcx > BuilderMethods < ' a , ' tcx > for Builder < ' a , ' gcc , ' tcx > {
396- fn build ( cx : & ' a CodegenCx < ' gcc , ' tcx > , block : Block < ' gcc > ) -> Self {
397+ fn build ( cx : & ' a CodegenCx < ' gcc , ' tcx > , block : Block < ' gcc > ) -> Builder < ' a , ' gcc , ' tcx > {
397398 Builder :: with_cx ( cx, block)
398399 }
399400
@@ -450,8 +451,36 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> {
450451 self . block . end_with_switch ( None , value, default_block, & gcc_cases) ;
451452 }
452453
454+ #[ cfg( feature="master" ) ]
455+ fn invoke ( & mut self , typ : Type < ' gcc > , func : RValue < ' gcc > , args : & [ RValue < ' gcc > ] , then : Block < ' gcc > , catch : Block < ' gcc > , _funclet : Option < & Funclet > ) -> RValue < ' gcc > {
456+ let try_block = self . current_func ( ) . new_block ( "try" ) ;
457+
458+ let current_block = self . block . clone ( ) ;
459+ self . block = try_block;
460+ let call = self . call ( typ, func, args, None ) ; // TODO: use funclet here?
461+ self . block = current_block;
462+
463+ let return_value = self . current_func ( )
464+ . new_local ( None , call. get_type ( ) , "invokeResult" ) ;
465+
466+ try_block. add_assignment ( None , return_value, call) ;
467+
468+ try_block. end_with_jump ( None , then) ;
469+
470+ self . block . add_try_catch ( None , try_block, catch) ;
471+
472+ self . block . end_with_jump ( None , then) ;
473+
474+ // NOTE: since jumps were added in a place rustc does not expect, the current blocks in the
475+ // state need to be updated.
476+ // FIXME: not sure it's actually needed.
477+ self . switch_to_block ( then) ;
478+
479+ return_value. to_rvalue ( )
480+ }
481+
482+ #[ cfg( not( feature="master" ) ) ]
453483 fn invoke ( & mut self , typ : Type < ' gcc > , func : RValue < ' gcc > , args : & [ RValue < ' gcc > ] , then : Block < ' gcc > , catch : Block < ' gcc > , _funclet : Option < & Funclet > ) -> RValue < ' gcc > {
454- // TODO(bjorn3): Properly implement unwinding.
455484 let call_site = self . call ( typ, func, args, None ) ;
456485 let condition = self . context . new_rvalue_from_int ( self . bool_type , 1 ) ;
457486 self . llbb ( ) . end_with_conditional ( None , condition, then, catch) ;
@@ -1160,23 +1189,56 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> {
11601189 aggregate_value
11611190 }
11621191
1163- fn set_personality_fn ( & mut self , _personality : RValue < ' gcc > ) {
1164- // TODO(antoyo)
1165- }
1166-
1167- fn cleanup_landing_pad ( & mut self , _ty : Type < ' gcc > , _pers_fn : RValue < ' gcc > ) -> RValue < ' gcc > {
1168- let field1 = self . context . new_field ( None , self . u8_type . make_pointer ( ) , "landing_pad_field_1" ) ;
1169- let field2 = self . context . new_field ( None , self . i32_type , "landing_pad_field_1" ) ;
1192+ fn set_personality_fn ( & mut self , personality : RValue < ' gcc > ) {
1193+ let personality = self . rvalue_as_function ( personality) ; // FIXME: why calling
1194+ //rvalue_as_function doesn't work?
1195+ //let personality = unsafe { std::mem::transmute(personality) };
1196+ #[ cfg( feature="master" ) ]
1197+ self . current_func ( ) . set_personality_function ( personality) ;
1198+ // FIXME: rustc manages to generate the symbol DW.ref.rust_eh_personality multiple times
1199+ // for the same asm file, which causes an assembler error.
1200+ }
1201+
1202+ fn cleanup_landing_pad ( & mut self , _ty : Type < ' gcc > , pers_fn : RValue < ' gcc > ) -> RValue < ' gcc > {
1203+ self . set_personality_fn ( pers_fn) ;
1204+
1205+ // FIXME: we're probably not creating a real cleanup pad here.
1206+ // FIXME: FIXME: FIXME: It seems to be the actual problem:
1207+ // libunwind finds a catch, so returns _URC_HANDLER_FOUND instead of _URC_CONTINUE_UNWIND.
1208+ // TODO: can we generate a goto from the finally to the cleanup landing pad?
1209+ // TODO: TODO: TODO: add this block to a cleanup_blocks variable and generate a try/finally instead if
1210+ // the catch block for it is a cleanup block.
1211+ //
1212+ // TODO: look at TRY_CATCH_IS_CLEANUP, CLEANUP_POINT_EXPR, WITH_CLEANUP_EXPR, CLEANUP_EH_ONLY.
1213+ let eh_pointer_builtin = self . cx . context . get_target_builtin_function ( "__builtin_eh_pointer" ) ;
1214+ let zero = self . cx . context . new_rvalue_zero ( self . int_type ) ;
1215+ let ptr = self . cx . context . new_call ( None , eh_pointer_builtin, & [ zero] ) ;
1216+
1217+ let field1_type = self . u8_type . make_pointer ( ) ;
1218+ let field1 = self . context . new_field ( None , field1_type, "landing_pad_field_1" ) ;
1219+ let field2 = self . context . new_field ( None , self . i32_type , "landing_pad_field_2" ) ;
11701220 let struct_type = self . context . new_struct_type ( None , "landing_pad" , & [ field1, field2] ) ;
1171- self . current_func ( ) . new_local ( None , struct_type. as_type ( ) , "landing_pad" )
1172- . to_rvalue ( )
1173- // TODO(antoyo): Properly implement unwinding.
1174- // the above is just to make the compilation work as it seems
1175- // rustc_codegen_ssa now calls the unwinding builder methods even on panic=abort.
1176- }
1177-
1178- fn resume ( & mut self , _exn : RValue < ' gcc > ) {
1179- // TODO(bjorn3): Properly implement unwinding.
1221+ let value = self . current_func ( ) . new_local ( None , struct_type. as_type ( ) , "landing_pad" ) ;
1222+ let ptr = self . cx . context . new_cast ( None , ptr, field1_type) ;
1223+ self . block . add_assignment ( None , value. access_field ( None , field1) , ptr) ;
1224+ self . block . add_assignment ( None , value. access_field ( None , field2) , zero) ; // TODO: set the proper value here (the type of exception?).
1225+
1226+ // Resume.
1227+ let param = self . context . new_parameter ( None , ptr. get_type ( ) , "exn" ) ;
1228+ // TODO: should we call __builtin_unwind_resume instead?
1229+ // FIXME: should probably not called resume because it could be executed (I believe) in
1230+ // normal (no exception) cases
1231+ let unwind_resume = self . context . new_function ( None , FunctionType :: Extern , self . type_void ( ) , & [ param] , "_Unwind_Resume" , false ) ;
1232+ self . block . add_eval ( None , self . context . new_call ( None , unwind_resume, & [ ptr] ) ) ;
1233+
1234+ value. to_rvalue ( )
1235+ }
1236+
1237+ fn resume ( & mut self , exn : RValue < ' gcc > ) {
1238+ let param = self . context . new_parameter ( None , exn. get_type ( ) , "exn" ) ;
1239+ // TODO: should we call __builtin_unwind_resume instead?
1240+ let unwind_resume = self . context . new_function ( None , FunctionType :: Extern , self . type_void ( ) , & [ param] , "_Unwind_Resume" , false ) ;
1241+ self . llbb ( ) . add_eval ( None , self . context . new_call ( None , unwind_resume, & [ exn] ) ) ;
11801242 self . unreachable ( ) ;
11811243 }
11821244
0 commit comments