@@ -500,6 +500,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
500500 & mut self ,
501501 helper : TerminatorCodegenHelper < ' tcx > ,
502502 bx : & mut Bx ,
503+ source_info : & mir:: SourceInfo ,
503504 location : mir:: Place < ' tcx > ,
504505 target : mir:: BasicBlock ,
505506 unwind : mir:: UnwindAction ,
@@ -523,90 +524,106 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
523524 args1 = [ place. val . llval ] ;
524525 & args1[ ..]
525526 } ;
526- let ( drop_fn, fn_abi, drop_instance) =
527- match ty. kind ( ) {
528- // FIXME(eddyb) perhaps move some of this logic into
529- // `Instance::resolve_drop_in_place`?
530- ty:: Dynamic ( _, _, ty:: Dyn ) => {
531- // IN THIS ARM, WE HAVE:
532- // ty = *mut (dyn Trait)
533- // which is: exists<T> ( *mut T, Vtable<T: Trait> )
534- // args[0] args[1]
535- //
536- // args = ( Data, Vtable )
537- // |
538- // v
539- // /-------\
540- // | ... |
541- // \-------/
542- //
543- let virtual_drop = Instance {
544- def : ty:: InstanceDef :: Virtual ( drop_fn. def_id ( ) , 0 ) , // idx 0: the drop function
545- args : drop_fn. args ,
546- } ;
547- debug ! ( "ty = {:?}" , ty) ;
548- debug ! ( "drop_fn = {:?}" , drop_fn) ;
549- debug ! ( "args = {:?}" , args) ;
550- let fn_abi = bx. fn_abi_of_instance ( virtual_drop, ty:: List :: empty ( ) ) ;
551- let vtable = args[ 1 ] ;
552- // Truncate vtable off of args list
553- args = & args[ ..1 ] ;
554- (
555- meth:: VirtualIndex :: from_index ( ty:: COMMON_VTABLE_ENTRIES_DROPINPLACE )
556- . get_fn ( bx, vtable, ty, fn_abi) ,
557- fn_abi,
558- virtual_drop,
559- )
560- }
561- ty:: Dynamic ( _, _, ty:: DynStar ) => {
562- // IN THIS ARM, WE HAVE:
563- // ty = *mut (dyn* Trait)
564- // which is: *mut exists<T: sizeof(T) == sizeof(usize)> (T, Vtable<T: Trait>)
565- //
566- // args = [ * ]
567- // |
568- // v
569- // ( Data, Vtable )
570- // |
571- // v
572- // /-------\
573- // | ... |
574- // \-------/
575- //
576- //
577- // WE CAN CONVERT THIS INTO THE ABOVE LOGIC BY DOING
578- //
579- // data = &(*args[0]).0 // gives a pointer to Data above (really the same pointer)
580- // vtable = (*args[0]).1 // loads the vtable out
581- // (data, vtable) // an equivalent Rust `*mut dyn Trait`
582- //
583- // SO THEN WE CAN USE THE ABOVE CODE.
584- let virtual_drop = Instance {
585- def : ty:: InstanceDef :: Virtual ( drop_fn. def_id ( ) , 0 ) , // idx 0: the drop function
586- args : drop_fn. args ,
587- } ;
588- debug ! ( "ty = {:?}" , ty) ;
589- debug ! ( "drop_fn = {:?}" , drop_fn) ;
590- debug ! ( "args = {:?}" , args) ;
591- let fn_abi = bx. fn_abi_of_instance ( virtual_drop, ty:: List :: empty ( ) ) ;
592- let meta_ptr = place. project_field ( bx, 1 ) ;
593- let meta = bx. load_operand ( meta_ptr) ;
594- // Truncate vtable off of args list
595- args = & args[ ..1 ] ;
596- debug ! ( "args' = {:?}" , args) ;
597- (
598- meth:: VirtualIndex :: from_index ( ty:: COMMON_VTABLE_ENTRIES_DROPINPLACE )
599- . get_fn ( bx, meta. immediate ( ) , ty, fn_abi) ,
600- fn_abi,
601- virtual_drop,
602- )
603- }
604- _ => (
605- bx. get_fn_addr ( drop_fn) ,
606- bx. fn_abi_of_instance ( drop_fn, ty:: List :: empty ( ) ) ,
607- drop_fn,
608- ) ,
609- } ;
527+ let ( maybe_null, drop_fn, fn_abi, drop_instance) = match ty. kind ( ) {
528+ // FIXME(eddyb) perhaps move some of this logic into
529+ // `Instance::resolve_drop_in_place`?
530+ ty:: Dynamic ( _, _, ty:: Dyn ) => {
531+ // IN THIS ARM, WE HAVE:
532+ // ty = *mut (dyn Trait)
533+ // which is: exists<T> ( *mut T, Vtable<T: Trait> )
534+ // args[0] args[1]
535+ //
536+ // args = ( Data, Vtable )
537+ // |
538+ // v
539+ // /-------\
540+ // | ... |
541+ // \-------/
542+ //
543+ let virtual_drop = Instance {
544+ def : ty:: InstanceDef :: Virtual ( drop_fn. def_id ( ) , 0 ) , // idx 0: the drop function
545+ args : drop_fn. args ,
546+ } ;
547+ debug ! ( "ty = {:?}" , ty) ;
548+ debug ! ( "drop_fn = {:?}" , drop_fn) ;
549+ debug ! ( "args = {:?}" , args) ;
550+ let fn_abi = bx. fn_abi_of_instance ( virtual_drop, ty:: List :: empty ( ) ) ;
551+ let vtable = args[ 1 ] ;
552+ // Truncate vtable off of args list
553+ args = & args[ ..1 ] ;
554+ (
555+ true ,
556+ meth:: VirtualIndex :: from_index ( ty:: COMMON_VTABLE_ENTRIES_DROPINPLACE )
557+ . get_optional_fn ( bx, vtable, ty, fn_abi) ,
558+ fn_abi,
559+ virtual_drop,
560+ )
561+ }
562+ ty:: Dynamic ( _, _, ty:: DynStar ) => {
563+ // IN THIS ARM, WE HAVE:
564+ // ty = *mut (dyn* Trait)
565+ // which is: *mut exists<T: sizeof(T) == sizeof(usize)> (T, Vtable<T: Trait>)
566+ //
567+ // args = [ * ]
568+ // |
569+ // v
570+ // ( Data, Vtable )
571+ // |
572+ // v
573+ // /-------\
574+ // | ... |
575+ // \-------/
576+ //
577+ //
578+ // WE CAN CONVERT THIS INTO THE ABOVE LOGIC BY DOING
579+ //
580+ // data = &(*args[0]).0 // gives a pointer to Data above (really the same pointer)
581+ // vtable = (*args[0]).1 // loads the vtable out
582+ // (data, vtable) // an equivalent Rust `*mut dyn Trait`
583+ //
584+ // SO THEN WE CAN USE THE ABOVE CODE.
585+ let virtual_drop = Instance {
586+ def : ty:: InstanceDef :: Virtual ( drop_fn. def_id ( ) , 0 ) , // idx 0: the drop function
587+ args : drop_fn. args ,
588+ } ;
589+ debug ! ( "ty = {:?}" , ty) ;
590+ debug ! ( "drop_fn = {:?}" , drop_fn) ;
591+ debug ! ( "args = {:?}" , args) ;
592+ let fn_abi = bx. fn_abi_of_instance ( virtual_drop, ty:: List :: empty ( ) ) ;
593+ let meta_ptr = place. project_field ( bx, 1 ) ;
594+ let meta = bx. load_operand ( meta_ptr) ;
595+ // Truncate vtable off of args list
596+ args = & args[ ..1 ] ;
597+ debug ! ( "args' = {:?}" , args) ;
598+ (
599+ true ,
600+ meth:: VirtualIndex :: from_index ( ty:: COMMON_VTABLE_ENTRIES_DROPINPLACE )
601+ . get_optional_fn ( bx, meta. immediate ( ) , ty, fn_abi) ,
602+ fn_abi,
603+ virtual_drop,
604+ )
605+ }
606+ _ => (
607+ false ,
608+ bx. get_fn_addr ( drop_fn) ,
609+ bx. fn_abi_of_instance ( drop_fn, ty:: List :: empty ( ) ) ,
610+ drop_fn,
611+ ) ,
612+ } ;
613+
614+ // We generate a null check for the drop_fn. This saves a bunch of relocations being
615+ // generated for no-op drops.
616+ if maybe_null {
617+ let is_not_null = bx. append_sibling_block ( "is_not_null" ) ;
618+ let llty = bx. fn_ptr_backend_type ( fn_abi) ;
619+ let null = bx. const_null ( llty) ;
620+ let non_null =
621+ bx. icmp ( base:: bin_op_to_icmp_predicate ( mir:: BinOp :: Ne , false ) , drop_fn, null) ;
622+ bx. cond_br ( non_null, is_not_null, helper. llbb_with_cleanup ( self , target) ) ;
623+ bx. switch_to_block ( is_not_null) ;
624+ self . set_debug_loc ( bx, * source_info) ;
625+ }
626+
610627 helper. do_call (
611628 self ,
612629 bx,
@@ -617,7 +634,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
617634 unwind,
618635 & [ ] ,
619636 Some ( drop_instance) ,
620- mergeable_succ,
637+ !maybe_null && mergeable_succ,
621638 )
622639 }
623640
@@ -1346,9 +1363,16 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
13461363 MergingSucc :: False
13471364 }
13481365
1349- mir:: TerminatorKind :: Drop { place, target, unwind, replace : _ } => {
1350- self . codegen_drop_terminator ( helper, bx, place, target, unwind, mergeable_succ ( ) )
1351- }
1366+ mir:: TerminatorKind :: Drop { place, target, unwind, replace : _ } => self
1367+ . codegen_drop_terminator (
1368+ helper,
1369+ bx,
1370+ & terminator. source_info ,
1371+ place,
1372+ target,
1373+ unwind,
1374+ mergeable_succ ( ) ,
1375+ ) ,
13521376
13531377 mir:: TerminatorKind :: Assert { ref cond, expected, ref msg, target, unwind } => self
13541378 . codegen_assert_terminator (
0 commit comments