@@ -13,7 +13,7 @@ use gccjit::{
13
13
RValue ,
14
14
ToRValue ,
15
15
Type ,
16
- UnaryOp ,
16
+ UnaryOp , FunctionType ,
17
17
} ;
18
18
use rustc_codegen_ssa:: MemFlags ;
19
19
use rustc_codegen_ssa:: common:: { AtomicOrdering , AtomicRmwBinOp , IntPredicate , RealPredicate , SynchronizationScope } ;
@@ -372,10 +372,11 @@ impl<'tcx> FnAbiOfHelpers<'tcx> for Builder<'_, '_, 'tcx> {
372
372
}
373
373
}
374
374
375
- impl < ' gcc , ' tcx > Deref for Builder < ' _ , ' gcc , ' tcx > {
375
+ impl < ' a , ' gcc , ' tcx > Deref for Builder < ' a , ' gcc , ' tcx > {
376
376
type Target = CodegenCx < ' gcc , ' tcx > ;
377
377
378
- fn deref ( & self ) -> & Self :: Target {
378
+ fn deref < ' b > ( & ' b self ) -> & ' a Self :: Target
379
+ {
379
380
self . cx
380
381
}
381
382
}
@@ -393,7 +394,7 @@ impl<'gcc, 'tcx> BackendTypes for Builder<'_, 'gcc, 'tcx> {
393
394
}
394
395
395
396
impl < ' 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 > {
397
398
Builder :: with_cx ( cx, block)
398
399
}
399
400
@@ -450,8 +451,36 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> {
450
451
self . block . end_with_switch ( None , value, default_block, & gcc_cases) ;
451
452
}
452
453
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" ) ) ]
453
483
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.
455
484
let call_site = self . call ( typ, func, args, None ) ;
456
485
let condition = self . context . new_rvalue_from_int ( self . bool_type , 1 ) ;
457
486
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> {
1160
1189
aggregate_value
1161
1190
}
1162
1191
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" ) ;
1170
1220
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] ) ) ;
1180
1242
self . unreachable ( ) ;
1181
1243
}
1182
1244
0 commit comments